Vcsn  2.0
Be Rational
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
random.hh
Go to the documentation of this file.
1 #ifndef VCSN_ALGOS_RANDOM_HH
2 # define VCSN_ALGOS_RANDOM_HH
3 
4 # include <vcsn/ctx/traits.hh>
6 # include <vcsn/dyn/automaton.hh>
7 # include <vcsn/dyn/context.hh>
9 # include <vcsn/labelset/oneset.hh>
10 # include <vcsn/labelset/tupleset.hh>
11 # include <vcsn/misc/raise.hh>
12 # include <vcsn/misc/random.hh>
13 # include <vcsn/misc/set.hh>
14 
15 namespace vcsn
16 {
17 
18  template <typename RandomGenerator = std::default_random_engine>
19  typename oneset::value_t
20  random_label(const oneset& ls,
21  RandomGenerator& = RandomGenerator())
22  {
23  return ls.one();
24  };
25 
26  template <typename... LabelSet,
27  typename RandomGenerator = std::default_random_engine>
28  typename tupleset<LabelSet...>::value_t
30  RandomGenerator& gen = RandomGenerator())
31  {
32  return random_label(ls, gen, ls.indices);
33  };
34 
35  template <typename... LabelSet,
36  size_t... I,
37  typename RandomGenerator = std::default_random_engine>
38  typename tupleset<LabelSet...>::value_t
40  RandomGenerator& gen,
42  {
43  return ls.value(std::make_tuple(random_label(ls.template set<I>(), gen)...));
44  };
45 
46 
47  template <typename LabelSet,
48  typename RandomGenerator = std::default_random_engine>
49  typename LabelSet::value_t
51  RandomGenerator& gen = RandomGenerator())
52  {
53  // Pick a member of a container following a uniform distribution.
54  auto pick = make_random_selector(gen);
55  return ls.value(pick(ls.genset()));
56  };
57 
58  template <typename LabelSet,
59  typename RandomGenerator = std::default_random_engine>
60  typename nullableset<LabelSet>::value_t
62  RandomGenerator& gen = RandomGenerator())
63  {
64  std::uniform_int_distribution<> dis(0, 1);
65  if (dis(gen))
66  return ls.one();
67  else
68  return ls.value(random_label(*ls.labelset(), gen));
69  };
70 
71  template <typename Context,
72  typename RandomGenerator = std::default_random_engine>
73  typename ratexpset<Context>::value_t
75  RandomGenerator& gen = RandomGenerator())
76  {
77  return rs.atom(random_label(*rs.labelset(), gen));
78  };
79 
80  /*--------------------.
81  | random(automaton). |
82  `--------------------*/
83 
84  template <typename Ctx>
85  mutable_automaton<Ctx>
86  random(const Ctx& ctx,
87  unsigned num_states, float density = 0.1,
88  unsigned num_initial = 1, unsigned num_final = 1)
89  {
90  require(0 <= density && density <= 1,
91  "random: density must be in [0,1]");
92  using automaton_t = mutable_automaton<Ctx>;
93  using state_t = state_t_of<automaton_t>;
94  automaton_t res = make_shared_ptr<automaton_t>(ctx);
95 
96  // A good source of random integers.
97  std::random_device rd;
98  auto seed = rd();
99  if (getenv("VCSN_SEED"))
100  seed = std::mt19937::default_seed;
101  std::mt19937 gen(seed);
102 
103  std::vector<state_t> states;
104  states.reserve(num_states);
105  // Indirect access to states[] to help random selection of successors.
106  std::vector<int> state_randomizer;
107  state_randomizer.reserve(num_states);
108 
109  // Using Sgi::hash_set instead of std::set for these sets is 3
110  // times slower (tested on a 50000 states example). These are
111  // indexes in states[].
112  using state_set = std::set<int>;
113  state_set worklist;
114  // Reachability from state[0] (_not_ from pre()).
115  state_set unreachables;
116 
117  for (unsigned i = 0; i < num_states; ++i)
118  {
119  states.push_back(res->new_state());
120  state_randomizer.push_back(i);
121  // State 0 is "reachable" from 0.
122  if (i)
123  unreachables.emplace(i);
124  if (i < num_initial)
125  res->set_initial(states[i]);
126  }
127  worklist.insert(0);
128 
129  // Select the final states.
130  for (unsigned i = 0; i < num_final; ++i)
131  {
132  std::uniform_int_distribution<> dis(i, num_states - 1);
133  int index = dis(gen);
134  res->set_final(states[state_randomizer[index]]);
135  // Swap it at the beginning of state_randomizer, so we cannot
136  // pick it again.
137  std::swap(state_randomizer[index], state_randomizer[i]);
138  }
139 
140  // We want to connect each state to a number of successors between
141  // 1 and n. If the probability to connect to each successor is d,
142  // the number of connected successors follows a binomial distribution.
143  std::binomial_distribution<> bin(num_states - 1, density);
144 
145  // Pick a member of a container following a uniform distribution.
147 
148  while (!worklist.empty())
149  {
150  auto src = states[*worklist.begin()];
151  worklist.erase(worklist.begin());
152 
153  // Choose a random number of successors (at least one), using
154  // a binomial distribution.
155  unsigned nsucc = 1 + bin(gen);
156 
157  // Connect to NSUCC randomly chosen successors. We want at
158  // least one unreachable successors among these if there are
159  // some.
160  bool saw_unreachable = false;
161  auto possibilities = num_states;
162  while (nsucc--)
163  {
164  // The index (in states[]) of the destination.
165  unsigned dst = -1;
166  // No connection to unreachable successors so far. This is
167  // our last chance, so force it now.
168  if (nsucc == 0
169  && !saw_unreachable
170  && !unreachables.empty())
171  {
172  // Pick a random unreachable state.
173  dst = pick.pop(unreachables);
174  worklist.insert(dst);
175  }
176  else
177  {
178  // Pick the index of a random state.
179  std::uniform_int_distribution<> dis(0, possibilities - 1);
180  int index = dis(gen);
181  possibilities--;
182 
183  dst = state_randomizer[index];
184 
185  // Permute it with state_randomizer[possibilities], so
186  // we cannot pick it again.
187  std::swap(state_randomizer[index],
188  state_randomizer[possibilities]);
189 
190  state_set::iterator j = unreachables.find(dst);
191  if (j != unreachables.end())
192  {
193  worklist.insert(dst);
194  unreachables.erase(j);
195  saw_unreachable = true;
196  }
197  }
198  res->add_transition(src, states[dst],
199  random_label(*ctx.labelset(), gen));
200  }
201  }
202  return std::move(res);
203  }
204 
205  namespace dyn
206  {
207  namespace detail
208  {
210  template <typename Ctx, typename, typename, typename, typename>
211  automaton
212  random(const context& ctx,
213  unsigned num_states, float density,
214  unsigned num_initial = 1, unsigned num_final = 1)
215  {
216  const auto& c = ctx->as<Ctx>();
217  return make_automaton(vcsn::random(c, num_states, density,
218  num_initial, num_final));
219  }
220 
222  (const context& ctx,
223  unsigned n, float density,
224  unsigned num_initial, unsigned num_final) -> automaton);
225  }
226  }
227 
228 
229  /*-----------------------.
230  | random_deterministic. |
231  `-----------------------*/
232 
233  template <typename Ctx>
234  mutable_automaton<Ctx>
235  random_deterministic(const Ctx& ctx, unsigned num_states)
236  {
237  require(0 < num_states, "num_states must be > 0");
238 
239  using automaton_t = mutable_automaton<Ctx>;
240  using state_t = state_t_of<automaton_t>;
241  automaton_t res = make_shared_ptr<automaton_t>(ctx);
242 
243  std::random_device rd;
244  auto seed = rd();
245  if (getenv("VCSN_SEED"))
246  seed = std::mt19937::default_seed;
247  std::mt19937 gen(seed);
248  std::uniform_int_distribution<int> distrib(0, num_states - 1);
249 
250  std::vector<state_t> states;
251  states.reserve(num_states);
252 
253  for (unsigned i = 0; i < num_states; ++i)
254  states.push_back(res->new_state());
255 
256  for (unsigned i = 0; i < num_states; ++i)
257  for (auto l : ctx.labelset()->genset())
258  res->add_transition(states[i], states[distrib(gen)], l,
259  ctx.weightset()->one());
260 
261  res->set_initial(states[distrib(gen)]);
262  res->set_final(states[distrib(gen)]);
263 
264  return res;
265  }
266 
267  namespace dyn
268  {
269  namespace detail
270  {
272  template <typename Ctx, typename>
273  automaton
274  random_deterministic(const context& ctx, unsigned num_states)
275  {
276  const auto& c = ctx->as<Ctx>();
277  return make_automaton(vcsn::random_deterministic(c, num_states));
278  }
279 
281  (const context& ctx, unsigned n) -> automaton);
282 
283  }
284  }
285 
286 } // vcsn::
287 
288 #endif // !VCSN_ALGOS_RANDOM_HH
REGISTER_DECLARE(accessible,(const automaton &) -> automaton)
std::shared_ptr< detail::automaton_base > automaton
Definition: automaton.hh:71
value_t value(const std::tuple< Args...> &args) const
Construct a value.
Definition: tupleset.hh:163
mutable_automaton< Ctx > random(const Ctx &ctx, unsigned num_states, float density=0.1, unsigned num_initial=1, unsigned num_final=1)
Definition: random.hh:86
A ValueSet which is a Cartesian product of ValueSets.
Definition: fwd.hh:20
static constexpr indices_t indices
Definition: tupleset.hh:62
automaton random(const context &ctx, unsigned num_states, float density, unsigned num_initial=1, unsigned num_final=1)
Bridge.
Definition: random.hh:212
static empty_t one()
Definition: oneset.hh:114
Implementation of labels are nullables (letter or empty).
Definition: fwd.hh:13
automaton make_automaton(const Aut &aut)
Build a dyn::automaton.
Definition: automaton.hh:77
std::shared_ptr< detail::mutable_automaton_impl< Context >> mutable_automaton
Definition: fwd.hh:25
Implementation of labels are ones: there is a single instance of label.
Definition: oneset.hh:18
const labelset_ptr labelset() const
Definition: nullableset.hh:280
struct random_selector< RandomGenerator > make_random_selector(const RandomGenerator &g) ATTRIBUTE_PURE
Definition: random.hh:65
vcsn::empty_t value_t
Definition: oneset.hh:22
mutable_automaton< Ctx > random_deterministic(const Ctx &ctx, unsigned num_states)
Definition: random.hh:235
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:36
oneset::value_t random_label(const oneset &ls, RandomGenerator &=RandomGenerator())
Definition: random.hh:20
std::shared_ptr< const detail::context_base > context
Definition: context.hh:71
auto pop(Container &c) -> typename Container::value_type
A randomly selected member of c. Remove it from c.
Definition: random.hh:45
automaton random_deterministic(const context &ctx, unsigned num_states)
Bridge.
Definition: random.hh:274
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
Definition: traits.hh:35
static ATTRIBUTE_PURE constexpr value_t one()
Definition: nullableset.hh:240
value_t value(Args &&...args) const
Definition: nullableset.hh:287
void require(bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:39