44 template <
typename Ctx>
45 mutable_automaton<Ctx>
47 unsigned num_states,
float density = 0.1,
48 unsigned num_initial = 1,
unsigned num_final = 1,
49 boost::optional<unsigned> max_labels = {},
50 float loop_chance = 0.0,
const std::string& weights =
"")
52 require(0 <= density && density <= 1,
53 "random_automaton: density must be in [0,1]");
54 require(0 <= loop_chance && loop_chance <= 1,
55 "random_automaton: loop chance must be in [0,1]");
60 auto res = make_shared_ptr<automaton_t>(
ctx);
64 const auto& ws = *ctx.weightset();
67 const auto& ls = *ctx.labelset();
68 const auto& gens = ls.generators();
69 auto num_gens = boost::distance(gens) + ls.has_one();
71 "random_automaton: empty labelset: ", ls);
75 "random_automaton: max number of labels cannot be null");
77 require(*max_labels <= num_gens,
78 "random_automaton: max number of labels cannot be greater " 79 "than the number of generators");
82 max_labels = num_gens;
83 auto num_labels = std::uniform_int_distribution<>(1, *max_labels);
90 auto states = std::vector<state_t>{};
91 states.reserve(num_states);
93 auto state_randomizer = std::vector<int>{};
94 state_randomizer.reserve(num_states);
99 using state_set = std::set<int>;
102 state_set unreachables;
106 states.emplace_back(
res->new_state());
107 state_randomizer.emplace_back(i);
110 unreachables.emplace(i);
112 res->set_initial(states[i]);
119 auto dis = std::uniform_int_distribution<>(i, num_states - 1);
120 int index = dis(gen);
121 res->set_final(states[state_randomizer[index]]);
124 std::swap(state_randomizer[index], state_randomizer[i]);
130 auto bin = std::binomial_distribution<>(num_states - 1, density);
135 while (!worklist.empty())
137 auto src = states[*worklist.begin()];
138 worklist.erase(worklist.begin());
142 unsigned nsucc = 1 + bin(gen);
147 bool saw_unreachable =
false;
148 auto possibilities = num_states;
157 && !unreachables.empty())
160 dst = pick.pop(unreachables);
161 worklist.insert(dst);
167 = std::uniform_int_distribution<>(0, possibilities - 1);
168 int index = dis(gen);
171 dst = state_randomizer[index];
176 state_randomizer[possibilities]);
178 state_set::iterator j = unreachables.find(dst);
179 if (j != unreachables.end())
181 worklist.insert(dst);
182 unreachables.erase(j);
183 saw_unreachable =
true;
186 auto n = num_labels(gen);
188 res->add_transition(src, states[dst],
197 auto dis = std::bernoulli_distribution(loop_chance);
198 for (
auto s :
res->states())
200 res->add_transition(s, s,
214 template <
typename Ctx,
typename NumStates,
typename Density,
215 typename NumInitial,
typename NumFinal,
216 typename MaxLabels,
typename LoopChance,
typename String>
219 unsigned num_states,
float density,
220 unsigned num_initial,
unsigned num_final,
221 boost::optional<unsigned> max_labels,
223 const std::string& weights)
225 const auto& c = ctx->
as<Ctx>();
227 num_initial, num_final,
240 template <
typename Ctx>
244 require(0 < num_states,
"num_states must be > 0");
248 automaton_t
res = make_shared_ptr<automaton_t>(
ctx);
251 auto dis = std::uniform_int_distribution<int>(0, num_states - 1);
253 auto states = std::vector<state_t>{};
254 states.reserve(num_states);
257 states.emplace_back(res->new_state());
260 for (
auto l : ctx.labelset()->generators())
261 res->add_transition(states[i], states[dis(gen)], l,
262 ctx.weightset()->one());
264 res->set_initial(states[dis(gen)]);
265 res->set_final(states[dis(gen)]);
275 template <
typename Ctx,
typename>
279 const auto& c = ctx->
as<Ctx>();
WeightSet::value_t random_weight(const WeightSet &ws, const std::string ¶m={})
Generate a random weight.
std::shared_ptr< detail::mutable_automaton_impl< Context > > mutable_automaton
automaton random_automaton_deterministic(const context &ctx, unsigned num_states)
Bridge.
typename detail::state_t_of_impl< base_t< ValueSet > >::type state_t_of
mutable_automaton< Ctx > random_automaton_deterministic(const Ctx &ctx, unsigned num_states)
std::mt19937 & make_random_engine()
Generate a unique random device.
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, const std::string &weights="")
Produce a random automaton.
auto irange(Integer last)
Generate an integer range.
Template-less root for contexts.
auto & as()
Downcast to the exact type.
random_selector< RandomGenerator > make_random_selector(RandomGenerator &g)
void swap(config::value &first, config::value &second)
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
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, const std::string &weights)
Bridge.
expressionset< Context >::value_t random_label(const expressionset< Context > &rs, RandomGenerator &gen=RandomGenerator())
Random label from expressionset: limited to a single label.