Vcsn  2.8
Be Rational
random-expression.hh
Go to the documentation of this file.
1 #include <ostream>
2 #include <regex>
3 #include <string>
4 
5 #include <boost/algorithm/string/erase.hpp>
6 #include <boost/tokenizer.hpp>
7 
8 #include <vcsn/core/rat/expressionset.hh> // make_expressionset
9 #include <vcsn/dyn/algos.hh>
10 #include <vcsn/misc/algorithm.hh>
11 #include <vcsn/misc/cast.hh>
12 #include <vcsn/misc/raise.hh>
13 #include <vcsn/misc/random.hh>
14 #include <vcsn/misc/tuple.hh>
16 
17 namespace vcsn
18 {
19  template <typename ExpressionSet>
20  std::string
21  random_expression_string(const ExpressionSet& es, const std::string& param);
22 
23  namespace detail
24  {
29  template <typename ExpressionSet,
30  typename RandomGenerator = std::default_random_engine>
32  {
33  public:
34  using expressionset_t = ExpressionSet;
35  using expression_t = typename expressionset_t::value_t;
36  using weight_t = typename expressionset_t::weight_t;
37  using weightset_t = typename expressionset_t::weightset_t;
38 
40  const std::string& param,
41  RandomGenerator& gen)
42  : es_{es}
43  , gen_{gen}
44  {
45  parse_param_(param);
46  }
47 
50  std::ostream& print_random_expression(std::ostream& out,
51  const format& fmt = {}) const
52  {
53  return print_random_expression_(out, length_, fmt);
54  }
55 
58  std::string random_expression_string() const
59  {
60  std::ostringstream out;
62  return out.str();
63  }
64 
68  {
70  }
71 
72  private:
73  // FIXME: maybe use something similar to Boost.ProgramOptions or
74  // getargs.
75  void parse_param_(const std::string& param)
76  {
77  // Set default value.
78  length_ = 6;
79  using tokenizer = boost::tokenizer<boost::escaped_list_separator<char>>;
80  using boost::algorithm::erase_all_copy;
81  const auto sep
82  = boost::escaped_list_separator<char>("#####", ",", "\"");
83  for (const auto& arg: tokenizer(param, sep))
84  {
85  const auto eq = arg.find('=');
86  const auto op = erase_all_copy(arg.substr(0, eq), " ");
87  if (op == "w")
88  {
89  random_weight_params_ = arg.substr(eq + 1);
91  }
92  else
93  {
94  const float value = (eq != std::string::npos)
95  ? detail::lexical_cast<float>(arg.substr(eq + 1))
96  : 1;
97  if (has(arities_, op))
98  {
99  // Ignore operators that don't make sense.
100  if ((op != "|" && op != "@")
102  operators_[op] = value;
103  }
104  else if (op == "length")
105  length_ = value;
106  else
107  raise("random_expression: invalid operator: ", op);
108  }
109  }
111  [](const auto& v){ return v.second; });
112  }
113 
115  std::string make_param_(unsigned length) const
116  {
117  auto res = std::string{};
118  for (const auto& p: operators_)
119  res += p.first + "=" + std::to_string(p.second) + ", ";
120  if (!random_weight_params_.empty())
121  res += "w=\"" + random_weight_params_ + "\", ";
122  res += "length=" + std::to_string(length);
123  return res;
124  }
125 
127  void print_weight_(std::ostream& out, const format& fmt) const
128  {
129  out << "<";
130  es_.weightset()->print(random_weight_.generate_random_weight(), out,
131  fmt.for_weights());
132  out << ">";
133  }
134 
136  void print_label_(std::ostream& out, const format& fmt) const
137  {
138  const auto& ls = *es_.labelset();
139  ls.print(random_label(ls, gen_), out,
140  fmt.for_labels().delimit(true));
141  }
142 
144  void print_unary_exp_(std::ostream& out, unsigned length,
145  const std::string& op, const format& fmt) const
146  {
147  // Prefix.
148  if (op == "!" || op == "w.")
149  {
150  out << '(';
151  if (op == "w.")
152  print_weight_(out, fmt);
153  else
154  out << op;
155  print_random_expression_(out, length - 1, fmt);
156  out << ')';
157  }
158  // Postfix.
159  else
160  {
161  out << '(';
162  print_random_expression_(out, length - 1, fmt);
163  if (op == ".w")
164  print_weight_(out, fmt);
165  else
166  out << op;
167  out << ")";
168  }
169  }
170 
174  void print_binary_exp_(std::ostream& out, unsigned length,
175  const std::string& op, const format& fmt) const
176  {
177  if (length < 3)
178  print_label_(out, fmt);
179  else
180  {
181  auto dis = std::uniform_int_distribution<>(1, length - 2);
182  const auto num_lhs = dis(gen_);
183  out << "(";
184  print_random_expression_(out, num_lhs, fmt);
185  out << op;
186  print_random_expression_(out, length - 1 - num_lhs, fmt);
187  out << ")";
188  }
189  }
190 
191 
195  template <typename ExpSet = expressionset_t>
196  auto
197  print_tuple_exp_(std::ostream& out, unsigned length,
198  const std::string& op, const format& fmt) const
199  -> std::enable_if_t<context_t_of<ExpSet>::is_lat,
200  void>
201  {
202  assert(op == "|");
203  const auto len = length / es_.labelset()->size();
204  const auto param = make_param_(std::max(size_t{1}, len));
205  out << '(';
206  const auto* sep = "";
207  es_.as_tupleset().map([&out, &param, &sep](const auto& subes)
208  {
209  out << sep
210  << '('
211  << vcsn::random_expression_string(subes, param)
212  << ')';
213  sep = "|";
214  // Please make_tuple.
215  return 0;
216  });
217  out << ')';
218  }
219 
221  template <typename ExpSet = expressionset_t>
222  auto
223  print_tuple_exp_(std::ostream& out, unsigned length,
224  const std::string& op, const format& fmt) const
225  -> std::enable_if_t<!context_t_of<ExpSet>::is_lat,
226  void>
227  {
228  assert(op == "|");
229  raise(es_, "random_expression: invalid use of '|'");
230  }
231 
232 
233  std::ostream&
234  print_random_expression_(std::ostream& out, unsigned length,
235  const format& fmt) const
236  {
237  // If there is no operator at all, return a label.
238  if (operators_.empty())
239  print_label_(out, fmt);
240 
241  // One symbol left: print a label.
242  else if (length == 1)
243  print_label_(out, fmt);
244 
245  // All operators are possible, choose one randomly (with
246  // associated weight probability) and print the associated
247  // expression.
248  else
249  {
250  // Choose an operator.
251  auto op = choose_(proba_op_, operators_)->first;
252  switch (arities_.at(op))
253  {
254  case 0:
255  out << op;
256  break;
257  case 1:
258  print_unary_exp_(out, length, op, fmt);
259  break;
260  case 2:
261  print_binary_exp_(out, length, op, fmt);
262  break;
263  case 3:
264  print_tuple_exp_(out, length, op, fmt);
265  break;
266  default:
267  assert(!"invalid arity");
268  }
269  }
270  return out;
271  }
272 
275  unsigned length_;
277  std::map<std::string, float> operators_;
279  const std::unordered_map<std::string, int> arities_
280  {
281  // Nullary.
282  {"\\e", 0},
283  {"\\z", 0},
284  // Unary.
285  {"!", 1},
286  {"{c}", 1},
287  {"*", 1},
288  {"{T}", 1},
289  {"w.", 1},
290  {".w", 1},
291  // Binary.
292  {"&", 2},
293  {"&:", 2},
294  {":", 2},
295  {".", 2},
296  {"<+", 2},
297  {"%", 2},
298  {"+", 2},
299  {"{/}", 2},
300  {"{\\}",2},
301  {"@", 2},
302  // Special.
303  {"|", 3},
304  };
305 
308  std::vector<float> proba_op_;
310  RandomGenerator& gen_;
317  };
318 
320  template <typename ExpressionSet, typename RandomGenerator = std::mt19937>
322  make_random_expression_impl(const ExpressionSet& es,
323  const std::string& param,
324  RandomGenerator& gen = make_random_engine())
325  {
326  return {es, param, gen};
327  }
328  } // end namespace vcsn::detail
329 
330 
337  template <typename ExpressionSet>
338  std::string
339  random_expression_string(const ExpressionSet& es, const std::string& param)
340  {
341  auto random_exp = detail::make_random_expression_impl(es, param);
342  return random_exp.random_expression_string();
343  }
344 
345 
347  template <typename ExpressionSet>
348  typename ExpressionSet::value_t
349  random_expression(const ExpressionSet& es, const std::string& param)
350  {
351  auto random_exp = detail::make_random_expression_impl(es, param);
352  return random_exp.random_expression();
353  }
354 
355  namespace dyn
356  {
357  namespace detail
358  {
360  template <typename Context, typename String, typename Identities>
361  expression
362  random_expression(const context& ctx, const std::string& param,
363  identities ids)
364  {
365  const auto& c = ctx->as<Context>();
366  auto es = make_expressionset(c, ids);
367  return {es, random_expression(es, param)};
368  }
369  }
370  }
371 } // end namespace vcsn
void print_binary_exp_(std::ostream &out, unsigned length, const std::string &op, const format &fmt) const
Print binary expression with binary operator.
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
Definition: setalpha.hh:26
std::shared_ptr< const node< Context > > expression
Definition: fwd.hh:195
format for_labels() const
A copy of this format, but to print labels.
Definition: format.hh:42
random_expression_impl< ExpressionSet, RandomGenerator > make_random_expression_impl(const ExpressionSet &es, const std::string &param, RandomGenerator &gen=make_random_engine())
Convenience constructor.
std::string make_param_(unsigned length) const
A string that specifies the current parameters.
typename expressionset_t::weight_t weight_t
RandomGenerator & gen_
Random generator.
Random selector on container, using discrete distribution.
Definition: random.hh:27
void print_label_(std::ostream &out, const format &fmt) const
Print label.
std::string random_expression_string() const
A random expression string (not parsed, so there might be some syntactic sugar such as <+)...
random_weight< weightset_t, RandomGenerator > random_weight_
Random weights generator.
std::mt19937 & make_random_engine()
Generate a unique random device.
Definition: random.cc:6
auto conv(const ValueSet &vs, const std::string &str, Args &&... args) -> decltype(vs.conv(std::declval< std::istream &>(), std::forward< Args >(args)...))
Parse str via vs.conv.
Definition: stream.hh:29
std::ostream & print_random_expression_(std::ostream &out, unsigned length, const format &fmt) const
discrete_chooser< RandomGenerator > choose_
Random selection in containers.
An expressionset can implement several different sets of identities on expressions.
Definition: identities.hh:20
auto transform(const Container &c, Fun &&fun)
Map a unary function on a container of values, and return the vector the results. ...
Definition: algorithm.hh:211
typename detail::context_t_of_impl< base_t< ValueSet > >::type context_t_of
Definition: traits.hh:61
An input/output format for valuesets.
Definition: format.hh:13
Random expression generator.
void print_unary_exp_(std::ostream &out, unsigned length, const std::string &op, const format &fmt) const
Print expression with unary operator.
std::map< std::string, float > operators_
For each operator, its probability.
Template-less root for contexts.
Definition: context.hh:16
std::string random_expression_string(const ExpressionSet &es, const std::string &param)
Generate a random expression string.
expression_t random_expression() const
A random expression (parsed, so there cannot be syntactic sugar such as <+).
Definition: a-star.hh:8
bool delimit() const
Whether we should delimit: (1, 2) instead of 1, 2.
Definition: format.hh:58
auto & as()
Downcast to the exact type.
Definition: context.hh:36
std::ostream & print_random_expression(std::ostream &out, const format &fmt={}) const
Print a random expression string (not parsed, so there might be some syntactic sugar such as <+)...
auto print_tuple_exp_(std::ostream &out, unsigned length, const std::string &op, const format &fmt) const -> std::enable_if_t< context_t_of< ExpSet >::is_lat, void >
Print a tuple operator.
void print_weight_(std::ostream &out, const format &fmt) const
Print random weight.
random_expression_impl(const expressionset_t &es, const std::string &param, RandomGenerator &gen)
std::string to_string(identities i)
Wrapper around operator<<.
Definition: identities.cc:38
typename expressionset_t::weightset_t weightset_t
auto make_expressionset(const context< LabelSet, WeightSet > &ctx, rat::identities ids={}) -> expressionset< context< LabelSet, WeightSet >>
Shorthand to expressionset constructor.
auto print_tuple_exp_(std::ostream &out, unsigned length, const std::string &op, const format &fmt) const -> std::enable_if_t<!context_t_of< ExpSet >::is_lat, void >
Print a tuple operator.
typename expressionset_t::value_t expression_t
std::string random_weight_params_
Random weights generator parameters.
std::vector< float > proba_op_
Vector of weights associated with the operators, i.e., the probabilities to pick each operator...
format for_weights() const
A copy of this format, but to print weights.
Definition: format.hh:50
static identities ids(const driver &d)
Get the identities of the driver.
Definition: parse.cc:91
const std::unordered_map< std::string, int > arities_
Number of arguments of each operator.
void parse_param_(const std::string &param)
return res
Definition: multiply.hh:399
expressionset< Context >::value_t random_label(const expressionset< Context > &rs, RandomGenerator &gen=RandomGenerator())
Random label from expressionset: limited to a single label.
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:86