Vcsn  2.3
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 
9 #include <vcsn/core/rat/expressionset.hh> // make_expressionset
10 #include <vcsn/dyn/algos.hh>
11 #include <vcsn/misc/algorithm.hh>
12 #include <vcsn/misc/cast.hh>
13 #include <vcsn/misc/raise.hh>
14 #include <vcsn/misc/random.hh>
16 
17 namespace vcsn
18 {
19  namespace detail
20  {
21 
27  template <typename ExpressionSet,
28  typename RandomGenerator = std::default_random_engine>
30  {
31  public:
32  using expressionset_t = ExpressionSet;
33  using expression_t = typename expressionset_t::value_t;
34 
36  const std::string& param, RandomGenerator& gen)
37  : rs_{rs}
38  , gen_{gen}
39  {
40  parse_param_(param);
41  }
42 
45  std::ostream& print_random_expression(std::ostream& out) const
46  {
47  return print_random_expression_(out, length_);
48  }
49 
52  std::string random_expression_string() const
53  {
54  std::ostringstream out;
56  return out.str();
57  }
58 
62  {
64  }
65 
66  private:
67  using operator_t = std::map<std::string, float>;
68  using operator_set_t = std::unordered_set<std::string>;
69  using weight_t = std::vector<float>;
70 
71  void parse_param_(const std::string& param)
72  {
73  // Set default value.
74  length_ = 6;
75  using tokenizer = boost::tokenizer<boost::char_separator<char>>;
76  auto sep = boost::char_separator<char>{","};
77  auto tok = tokenizer(param, sep);
78  for (auto it = tok.begin(); it != tok.end(); ++it)
79  {
80  auto tok_arg = std::string{*it};
81  auto eq = tok_arg.find_first_of('=');
82  auto op = tok_arg.substr(0, eq);
83  boost::algorithm::erase_all(op, " ");
84  float value = 1;
85  if (eq != std::string::npos)
86  value = lexical_cast<float>(tok_arg.substr(eq + 1));
87  if (has(nullary_op_, op) || has(unary_op_, op) || has(binary_op_, op))
88  operators_[op] = value;
89  else if (op == "length")
90  length_ = value;
91  else
92  raise("random_expression: invalid operator: ", op);
93  }
94  weight_ = transform(operators_, [](const auto& v){ return v.second; });
95  }
96 
98  void print_unary_exp_(std::ostream& out, unsigned length,
99  const std::string& op) const
100  {
101  // prefix
102  if (op == "!")
103  {
104  out << '(' << op;
105  print_random_expression_(out, length - 1);
106  out << ')';
107  }
108  // postfix
109  else
110  {
111  out << '(';
112  print_random_expression_(out, length - 1);
113  out << op << ')';
114  }
115  }
116 
120  void print_binary_exp_(std::ostream& out, unsigned length,
121  const std::string& op) const
122  {
123  if (length < 3)
124  rs_.labelset()->print(random_label(*rs_.labelset(), gen_), out);
125  else
126  {
127  auto dis = std::uniform_int_distribution<>(1, length - 1);
128  auto num_lhs = dis(gen_);
129  out << "(";
130  print_random_expression_(out, num_lhs);
131  out << op;
132  print_random_expression_(out, length - num_lhs);
133  out << ")";
134  }
135  }
136 
137  std::ostream&
138  print_random_expression_(std::ostream& out, unsigned length) const
139  {
140  // If there is no operators at all, that's impossible to
141  // construct an expression, so just return a label.
142  if (operators_.empty())
143  rs_.labelset()->print(random_label(*rs_.labelset(), gen_), out);
144 
145  // 1 symbol left: print a label.
146  else if (length == 1)
147  rs_.labelset()->print(random_label(*rs_.labelset(), gen_), out);
148 
149  // binary, unary or nullary operators are possible
150  // just choose randomly one (with associated weight probability)
151  // and print the associated expression.
152  else
153  {
154  auto it =
156  weight_.end(),
157  operators_.begin());
158  auto op = it->first;
159  if (has(nullary_op_, op))
160  out << op;
161  else if (has(unary_op_, op))
162  print_unary_exp_(out, length, op);
163  else
164  print_binary_exp_(out, length, op);
165  }
166  return out;
167  }
168 
170  unsigned length_;
172  operator_set_t nullary_op_ = { "\\e", "\\z" };
173  operator_set_t unary_op_ = { "!", "{c}", "*", "{T}" };
174  operator_set_t binary_op_ = { "&", "&:", ":", ".", "<+", "%", "+", "{/}", "{\\}" };
176  RandomGenerator& gen_;
177  };
178 
180  template <typename ExpressionSet, typename RandomGenerator = std::mt19937>
182  make_random_expression_impl(const ExpressionSet& rs,
183  const std::string& param,
184  RandomGenerator& gen = make_random_engine())
185  {
186  return {rs, param, gen};
187  }
188 
189  } // end namespace vcsn::detail
190 
191 
198  template <typename ExpressionSet>
199  std::string
200  random_expression_string(const ExpressionSet& rs, const std::string& param)
201  {
202  auto random_exp = detail::make_random_expression_impl(rs, param);
203  return random_exp.random_expression_string();
204  }
205 
206 
208  template <typename ExpressionSet>
209  typename ExpressionSet::value_t
210  random_expression(const ExpressionSet& rs, const std::string& param)
211  {
212  auto random_exp = detail::make_random_expression_impl(rs, param);
213  return random_exp.random_expression();
214  }
215 
216  namespace dyn
217  {
218  namespace detail
219  {
221  template <typename Context, typename String, typename Identities>
222  expression
223  random_expression(const context& ctx, const std::string& param,
224  identities ids)
225  {
226  const auto& c = ctx->as<Context>();
227  auto rs = make_expressionset(c, ids);
228  return {rs, random_expression(rs, param)};
229  }
230  }
231  }
232 } // end namespace vcsn
void print_binary_exp_(std::ostream &out, unsigned length, const std::string &op) const
Print binary expression with binary operator.
ExpressionSet::value_t random_expression(const ExpressionSet &rs, const std::string &param)
Generate a random expression.
void print_unary_exp_(std::ostream &out, unsigned length, const std::string &op) const
Print expression with unary operator.
expression_t random_expression() const
A random expression (parsed, so there cannot be syntactic sugar such as <+).
std::mt19937 & make_random_engine()
Generate a unique random device.
Definition: random.cc:6
Class random expression generator.
Random selector on container, using discrete distribution.
Definition: random.hh:15
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:64
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::string random_expression_string(const ExpressionSet &rs, const std::string &param)
Generate a random expression string.
auto & as()
Downcast to the exact type.
Definition: context.hh:36
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 <+)...
std::ostream & print_random_expression_(std::ostream &out, unsigned length) const
std::string random_expression_string() const
A random expression string (not parsed, so there might be some syntactic sugar such as <+)...
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
Template-less root for contexts.
Definition: context.hh:16
auto rs
Definition: lift.hh:152
Definition: a-star.hh:8
random_expression_impl(const expressionset_t &rs, const std::string &param, RandomGenerator &gen)
T lexical_cast(const std::string &str)
String to templated type T conversion.
Definition: cast.hh:79
void parse_param_(const std::string &param)
auto make_expressionset(const context< LabelSet, WeightSet > &ctx, rat::identities ids={}) -> expressionset< context< LabelSet, WeightSet >>
Shorthand to expressionset constructor.
std::unordered_set< std::string > operator_set_t
oneset::value_t random_label(const oneset &ls, RandomGenerator &=RandomGenerator())
Random label from oneset.
Definition: random-label.hh:16
std::map< std::string, float > operator_t
random_expression_impl< ExpressionSet, RandomGenerator > make_random_expression_impl(const ExpressionSet &rs, const std::string &param, RandomGenerator &gen=make_random_engine())
Convenience constructor.
typename expressionset_t::value_t expression_t
static identities ids(const driver &d)
Get the identities of the driver.
Definition: parse.cc:89
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:157
value_impl< detail::expression_tag > expression
Definition: fwd.hh:25
expression random_expression(const context &ctx, const std::string &param, identities ids)
Bridge.