Vcsn  2.5
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>
15 
16 namespace vcsn
17 {
18  namespace detail
19  {
20 
26  template <typename ExpressionSet,
27  typename RandomGenerator = std::default_random_engine>
29  {
30  public:
31  using expressionset_t = ExpressionSet;
32  using expression_t = typename expressionset_t::value_t;
33  using weight_t = typename expressionset_t::weight_t;
34  using weightset_t = typename expressionset_t::weightset_t;
35 
37  const std::string& param,
38  RandomGenerator& gen)
39  : rs_{rs}
40  , gen_{gen}
41  {
42  parse_param_(param);
43  }
44 
47  std::ostream& print_random_expression(std::ostream& out) const
48  {
49  return print_random_expression_(out, length_);
50  }
51 
54  std::string random_expression_string() const
55  {
56  std::ostringstream out;
58  return out.str();
59  }
60 
64  {
66  }
67 
68  private:
71  void parse_param_(const std::string& param)
72  {
73  // Set default value.
74  length_ = 6;
75  using tokenizer = boost::tokenizer<boost::escaped_list_separator<char>>;
76  using boost::algorithm::erase_all_copy;
77  auto sep = boost::escaped_list_separator<char>("#####", ",", "\"");
78  for (const auto& arg: tokenizer(param, sep))
79  {
80  auto eq = arg.find('=');
81  auto op = erase_all_copy(arg.substr(0, eq), " ");
82  if (op == "w")
83  random_weight_.parse_param(arg.substr(eq + 1));
84  else
85  {
86  float value = (eq != std::string::npos)
87  ? detail::lexical_cast<float>(arg.substr(eq + 1))
88  : 1;
89  if (has(arities_, op))
90  operators_[op] = value;
91  else if (op == "length")
92  length_ = value;
93  else
94  raise("random_expression: invalid operator: ", op);
95  }
96  }
98  [](const auto& v){ return v.second; });
99  }
100 
102  void print_weight_(std::ostream& out) const
103  {
104  out << "<";
105  rs_.weightset()->print(random_weight_.generate_random_weight(), out);
106  out << ">";
107  }
108 
110  void print_label_(std::ostream& out) const
111  {
112  rs_.labelset()->print(random_label(*rs_.labelset(), gen_), out);
113  }
114 
116  void print_unary_exp_(std::ostream& out, unsigned length,
117  const std::string& op) const
118  {
119  // Prefix.
120  if (op == "!" || op == "w.")
121  {
122  out << '(';
123  if (op == "w.")
124  print_weight_(out);
125  else
126  out << op;
127  print_random_expression_(out, length - 1);
128  out << ')';
129  }
130  // Postfix.
131  else
132  {
133  out << '(';
134  print_random_expression_(out, length - 1);
135  if (op == ".w")
136  print_weight_(out);
137  else
138  out << op;
139  out << ")";
140  }
141  }
142 
146  void print_binary_exp_(std::ostream& out, unsigned length,
147  const std::string& op) const
148  {
149  if (length < 3)
150  print_label_(out);
151  else
152  {
153  auto dis = std::uniform_int_distribution<>(1, length - 2);
154  auto num_lhs = dis(gen_);
155  out << "(";
156  print_random_expression_(out, num_lhs);
157  out << op;
158  print_random_expression_(out, length - 1 - num_lhs);
159  out << ")";
160  }
161  }
162 
163  std::ostream&
164  print_random_expression_(std::ostream& out, unsigned length) const
165  {
166  // If there is no operators at all, that's impossible to
167  // construct an expression, so just return a label.
168  if (operators_.empty())
169  print_label_(out);
170 
171  // One symbol left: print a label.
172  else if (length == 1)
173  print_label_(out);
174 
175  // All operators are possible, choose one randomly (with
176  // associated weight probability) and print the associated
177  // expression.
178  else
179  {
180  // Choose an operator.
181  auto op = chooser_it_(proba_op_, operators_)->first;
182  switch (arities_.at(op))
183  {
184  case 0:
185  out << op;
186  break;
187  case 1:
188  print_unary_exp_(out, length, op);
189  break;
190  case 2:
191  print_binary_exp_(out, length, op);
192  break;
193  default:
194  assert(!"invalid arity");
195  }
196  }
197  return out;
198  }
199 
202  unsigned length_;
204  std::map<std::string, float> operators_;
206  std::unordered_map<std::string, int> arities_
207  {
208  // Nullary.
209  {"\\e", 0},
210  {"\\z", 0},
211  // Unary.
212  {"!", 1},
213  {"{c}", 1},
214  {"*", 1},
215  {"{T}", 1},
216  {"w.", 1},
217  {".w", 1},
218  // Binary.
219  {"&", 2},
220  {"&:", 2},
221  {":", 2},
222  {".", 2},
223  {"<+", 2},
224  {"%", 2},
225  {"+", 2},
226  {"{/}", 2},
227  {"{\\}",2},
228  };
229 
232  std::vector<float> proba_op_;
234  RandomGenerator& gen_;
238  };
239 
241  template <typename ExpressionSet, typename RandomGenerator = std::mt19937>
243  make_random_expression_impl(const ExpressionSet& rs,
244  const std::string& param,
245  RandomGenerator& gen = make_random_engine())
246  {
247  return {rs, param, gen};
248  }
249 
250  } // end namespace vcsn::detail
251 
252 
259  template <typename ExpressionSet>
260  std::string
261  random_expression_string(const ExpressionSet& rs, const std::string& param)
262  {
263  auto random_exp = detail::make_random_expression_impl(rs, param);
264  return random_exp.random_expression_string();
265  }
266 
267 
269  template <typename ExpressionSet>
270  typename ExpressionSet::value_t
271  random_expression(const ExpressionSet& rs, const std::string& param)
272  {
273  auto random_exp = detail::make_random_expression_impl(rs, param);
274  return random_exp.random_expression();
275  }
276 
277  namespace dyn
278  {
279  namespace detail
280  {
282  template <typename Context, typename String, typename Identities>
283  expression
284  random_expression(const context& ctx, const std::string& param,
285  identities ids)
286  {
287  const auto& c = ctx->as<Context>();
288  auto rs = make_expressionset(c, ids);
289  return {rs, random_expression(rs, param)};
290  }
291  }
292  }
293 } // end namespace vcsn
random_expression_impl(const expressionset_t &rs, const std::string &param, RandomGenerator &gen)
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:25
random_weight< weightset_t, RandomGenerator > random_weight_
Random weights generator.
Definition: a-star.hh:8
void print_binary_exp_(std::ostream &out, unsigned length, const std::string &op) const
Print binary expression with binary operator.
void print_weight_(std::ostream &out) const
Print random weight.
discrete_chooser< RandomGenerator > chooser_it_
An expressionset can implement several different sets of identities on expressions.
Definition: identities.hh:20
std::ostream & print_random_expression_(std::ostream &out, unsigned length) const
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:86
void print_unary_exp_(std::ostream &out, unsigned length, const std::string &op) const
Print expression with unary operator.
static identities ids(const driver &d)
Get the identities of the driver.
Definition: parse.cc:89
std::map< std::string, float > operators_
For each operator, its probability.
Class random expression generator.
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:195
random_expression_impl< ExpressionSet, RandomGenerator > make_random_expression_impl(const ExpressionSet &rs, const std::string &param, RandomGenerator &gen=make_random_engine())
Convenience constructor.
void parse_param_(const std::string &param)
FIXME: maybe use something similar to Boost.ProgramOptions or getargs.
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
void print_label_(std::ostream &out) const
Print label.
typename expressionset_t::weight_t weight_t
std::unordered_map< std::string, int > arities_
Number of arguments of each operator.
std::shared_ptr< const node< Context > > expression
Definition: fwd.hh:191
expressionset< Context >::value_t random_label(const expressionset< Context > &rs, RandomGenerator &gen=RandomGenerator())
Random label from expressionset: limited to a single label.
std::vector< float > proba_op_
Vector of weights associated with the operators, i.e., the probabilities to pick each operator...
std::string random_expression_string() const
A random expression string (not parsed, so there might be some syntactic sugar such as <+)...
typename expressionset_t::weightset_t weightset_t
Random selector on container, using discrete distribution.
Definition: random.hh:27
auto make_expressionset(const context< LabelSet, WeightSet > &ctx, rat::identities ids={}) -> expressionset< context< LabelSet, WeightSet >>
Shorthand to expressionset constructor.
expression_t random_expression() const
A random expression (parsed, so there cannot be syntactic sugar such as <+).
Template-less root for contexts.
Definition: context.hh:16
typename expressionset_t::value_t expression_t
std::ostream & print_random_expression(std::ostream &out) const
Print a random expression string (not parsed, so there might be some syntactic sugar such as <+)...
auto & as()
Downcast to the exact type.
Definition: context.hh:36
RandomGenerator & gen_
Random generator.