40 template <
typename Ctx>
41 mutable_automaton<Ctx>
43 unsigned num_states,
float density = 0.1,
44 unsigned num_initial = 1,
unsigned num_final = 1,
45 boost::optional<unsigned> max_labels = {},
46 float loop_chance = 0.0)
48 require(0 <= density && density <= 1,
49 "random_automaton: density must be in [0,1]");
50 require(0 <= loop_chance && loop_chance <= 1,
51 "random_automaton: loop chance must be in [0,1]");
54 using automaton_t = mutable_automaton<Ctx>;
55 using state_t = state_t_of<automaton_t>;
56 auto res = make_shared_ptr<automaton_t>(
ctx);
61 const auto& ls = *ctx.labelset();
64 "random_automaton: max number of labels cannot be null");
67 max_labels = (boost::distance(ls.generators()) + ls.has_one());
69 "random_automaton: empty labelset: ", ls);
71 auto num_labels = std::uniform_int_distribution<>(1, *max_labels);
73 auto states = std::vector<state_t>{};
74 states.reserve(num_states);
76 auto state_randomizer = std::vector<int>{};
77 state_randomizer.reserve(num_states);
82 using state_set = std::set<int>;
85 state_set unreachables;
89 states.emplace_back(
res->new_state());
90 state_randomizer.emplace_back(i);
93 unreachables.emplace(i);
95 res->set_initial(states[i]);
102 auto dis = std::uniform_int_distribution<>(i, num_states - 1);
103 int index = dis(gen);
104 res->set_final(states[state_randomizer[index]]);
107 std::swap(state_randomizer[index], state_randomizer[i]);
113 auto bin = std::binomial_distribution<>(num_states - 1, density);
118 while (!worklist.empty())
120 auto src = states[*worklist.begin()];
121 worklist.erase(worklist.begin());
125 unsigned nsucc = 1 + bin(gen);
130 bool saw_unreachable =
false;
131 auto possibilities = num_states;
140 && !unreachables.empty())
143 dst = pick.pop(unreachables);
144 worklist.insert(dst);
150 = std::uniform_int_distribution<>(0, possibilities - 1);
151 int index = dis(gen);
154 dst = state_randomizer[index];
158 std::swap(state_randomizer[index],
159 state_randomizer[possibilities]);
161 state_set::iterator j = unreachables.find(dst);
162 if (j != unreachables.end())
164 worklist.insert(dst);
165 unreachables.erase(j);
166 saw_unreachable =
true;
169 auto n = num_labels(gen);
171 res->add_transition(src, states[dst],
179 auto dis = std::bernoulli_distribution(loop_chance);
180 for (
auto s :
res->states())
193 template <
typename Ctx,
typename NumStates,
typename Density,
194 typename NumInitial,
typename NumFinal,
195 typename MaxLabels,
typename LoopChance>
198 unsigned num_states,
float density,
199 unsigned num_initial,
unsigned num_final,
200 boost::optional<unsigned> max_labels,
203 const auto& c = ctx->
as<Ctx>();
205 num_initial, num_final,
217 template <
typename Ctx>
218 mutable_automaton<Ctx>
221 require(0 < num_states,
"num_states must be > 0");
225 automaton_t
res = make_shared_ptr<automaton_t>(
ctx);
228 auto dis = std::uniform_int_distribution<int>(0, num_states - 1);
230 auto states = std::vector<state_t>{};
231 states.reserve(num_states);
234 states.emplace_back(res->new_state());
237 for (
auto l : ctx.labelset()->generators())
238 res->add_transition(states[i], states[dis(gen)], l,
239 ctx.weightset()->one());
241 res->set_initial(states[dis(gen)]);
242 res->set_final(states[dis(gen)]);
252 template <
typename Ctx,
typename>
256 const auto& c = ctx->
as<Ctx>();
std::mt19937 & make_random_engine()
Generate a unique random device.
std::shared_ptr< detail::mutable_automaton_impl< Context >> mutable_automaton
mutable_automaton< Ctx > random_automaton_deterministic(const Ctx &ctx, unsigned num_states)
automaton random_automaton_deterministic(const context &ctx, unsigned num_states)
Bridge.
void require(Bool b, Args &&...args)
If b is not verified, raise an error with args as message.
auto & as()
Downcast to the exact type.
mutable_automaton< Ctx > random_automaton(const Ctx &ctx, unsigned num_states, float density=0.1, unsigned num_initial=1, unsigned num_final=1, boost::optional< unsigned > max_labels={}, float loop_chance=0.0)
Produce a random automaton.
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Template-less root for contexts.
automaton random_automaton(const context &ctx, unsigned num_states, float density, unsigned num_initial, unsigned num_final, boost::optional< unsigned > max_labels, float loop_chance)
Bridge.
oneset::value_t random_label(const oneset &ls, RandomGenerator &=RandomGenerator())
Random label from oneset.
random_selector< RandomGenerator > make_random_selector(RandomGenerator &g)
auto irange(Integer last)
Generate an integer range.