Vcsn  2.8
Be Rational
weightset.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <iostream>
4 #include <map>
5 #include <memory> // std::make_shared
6 #include <string>
7 #include <type_traits>
8 #include <vector>
9 
10 #include <boost/algorithm/string/erase.hpp>
11 #include <boost/tokenizer.hpp>
12 
13 #include <vcsn/misc/algorithm.hh>
14 #include <vcsn/misc/cast.hh>
15 #include <vcsn/misc/functional.hh>
16 #include <vcsn/misc/random.hh>
17 #include <vcsn/misc/type_traits.hh> // detect
18 
19 // It is much simpler and saner in C++ to put types and functions on
20 // these types in the same namespace. Since "using q =
21 // detail::weightset_mixin<q_impl>" would just create an alias of
22 // q, its original namespace, detail::, would still be the namespace
23 // used in ADL.
24 //
25 // This is really troublesome to implement free-functions such as join.
26 //
27 // Therefore, although this wrapper should be hidden as a detail::, it
28 // will remain in vcsn::, where join and the like will find it.
29 
30 namespace vcsn
31 {
32  /*-------------------.
33  | weightset_mixin. |
34  `-------------------*/
35  namespace detail
36  {
38  template <typename T>
39  using power_mem_fn_t
40  = decltype(std::declval<T>()
41  .power(std::declval<typename T::value_t>(), 0));
42 
44  template <typename T>
46  }
47 
49  template <typename WeightSet>
50  struct weightset_mixin : WeightSet
51  {
52  using super_t = WeightSet;
53  using typename super_t::value_t;
54 
56  using super_t::super_t;
57 
59  using super_t::mul;
60 
62  template <typename... Ts>
63  value_t mul(const Ts&... ts) const
64  {
65  value_t res = this->one();
66  // FIXME: Remove once GCC is fixed.
67  using swallow = int[];
68  (void) swallow
69  {
70  ((res = super_t::mul(res, ts)), 0)...
71  };
72  return res;
73  }
74 
75  private:
78  template <typename WS = super_t>
79  auto power_(value_t e, unsigned n) const
80  -> std::enable_if_t<detail::has_power_mem_fn<WS>{}, value_t>
81  {
82  return super_t::power(e, n);
83  }
84 
87  template <typename WS = super_t>
88  auto power_(value_t e, unsigned n) const
89  -> std::enable_if_t<!detail::has_power_mem_fn<WS>{}, value_t>
90  {
91  value_t res = super_t::one();
92  if (!super_t::is_one(e))
93  while (n--)
94  res = mul(res, e);
95  return res;
96  }
97 
98  public:
99 
101  value_t power(value_t e, unsigned n) const
102  {
103  return power_<WeightSet>(e, n);
104  }
105  };
106 
107 
108  /*-----------------.
109  | random_weight. |
110  `-----------------*/
111  namespace detail
112  {
116  template <typename WeightSet,
117  typename RandomGenerator = std::default_random_engine>
119  {
120  public:
122  using weight_t = typename weightset_t::value_t;
123  using random_generator_t = RandomGenerator;
124 
125  random_weight_base(random_generator_t& gen, const weightset_t& ws)
126  : gen_{gen}
127  , ws_{ws}
128  , min_{ws.min()}
129  , max_{ws.max()}
130  {}
131 
132  void parse_param(const std::string& param)
133  {
134  if (!param.empty())
135  parse_param_(param);
136  }
137 
139  {
140  return print_random_weight_();
141  }
142 
143  protected:
144  virtual void parse_param_(const std::string& weights)
145  {
146  using tokenizer = boost::tokenizer<boost::char_separator<char>>;
147  using boost::algorithm::erase_all_copy;
148  auto sep = boost::char_separator<char>{","};
149  for (const auto& arg: tokenizer(weights, sep))
150  {
151  auto eq = arg.find('=');
152  auto weight = erase_all_copy(arg.substr(0, eq), " ");
153  if (weight == "min")
154  min_ = conv(ws_, arg.substr(eq + 1));
155  else if (weight == "max")
156  max_ = conv(ws_, arg.substr(eq + 1));
157  else
158  {
159  float value = (eq != std::string::npos)
160  ? detail::lexical_cast<float>(arg.substr(eq + 1))
161  : 1;
162  auto w = conv(ws_, weight);
163  weight_[w] = value;
164  }
165  }
166 
167  weight_weight_
168  = detail::transform(weight_, [](const auto& v){ return v.second; });
169  }
170 
171  virtual weight_t pick_value_() const = 0;
172 
175  {
176  if (choose_map(weight_weight_, gen_))
177  {
180  auto it = chooser_it_(weight_weight_, weight_);
181  return it->first;
182  }
184  else
185  {
186  return pick_value_();
187  }
188  }
189 
190  random_generator_t& gen_;
198  using weight_map_t = std::map<weight_t, float, vcsn::less<weightset_t>>;
200  using weight_weight_t = std::vector<float>;
203  };
204 
207  template <typename WeightSet, typename RandomGenerator>
209  }
210 
211  /*----------.
212  | traits. |
213  `----------*/
214 
215  // FIXME: find generic implementation for min-plus.
216  template <typename T>
217  struct is_tropical : std::false_type
218  {};
219 
220  /*----------.
221  | Errors. |
222  `----------*/
223 
225  template <typename ValueSet, typename... Args>
226  ATTRIBUTE_NORETURN
227  void raise_invalid_value(const ValueSet& vs, Args&&... args)
228  {
229  raise(vs, ": invalid value: ", std::forward<Args>(args)...);
230  }
231 
233  template <typename WeightSet>
234  ATTRIBUTE_NORETURN
236  const typename WeightSet::value_t& w)
237  {
238  raise(ws, ": value is not starrable: ", to_string(ws, w));
239  }
240 }
void parse_param(const std::string &param)
Definition: weightset.hh:132
static bool choose_map(const std::vector< float > &map, RandomGenerator &gen=RandomGenerator())
Choose whether to pick an element from a map or not.
Definition: random.hh:17
ATTRIBUTE_NORETURN void raise_invalid_value(const ValueSet &vs, Args &&... args)
Cannot make a value from this.
Definition: weightset.hh:227
variadic< type_t::mul, Context > mul
Definition: fwd.hh:159
constant< type_t::one, Context > one
Definition: fwd.hh:121
auto power_(value_t e, unsigned n) const -> std::enable_if_t< detail::has_power_mem_fn< WS >
Case where the weightset T features a power(value_t, unsigned) member function.
Definition: weightset.hh:79
value_t mul(const Ts &... ts) const
A variadic multiplication.
Definition: weightset.hh:63
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
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
Abstract class for random weight generation.
Definition: weightset.hh:118
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
Definition: a-star.hh:8
auto power_(value_t e, unsigned n) const -> std::enable_if_t<!detail::has_power_mem_fn< WS >
Case where the weightset T does not feature a power(value_t, unsigned) member function.
Definition: weightset.hh:88
weight_t min_
The min and the max given by the user.
Definition: weightset.hh:194
weight_t generate_random_weight() const
Definition: weightset.hh:138
ATTRIBUTE_NORETURN void raise_not_starrable(const WeightSet &ws, const typename WeightSet::value_t &w)
This value is not starrable.
Definition: weightset.hh:235
random_generator_t & gen_
Definition: weightset.hh:190
value_t power(value_t e, unsigned n) const
Repeated multiplication.
Definition: weightset.hh:101
Generic declaration of the class which is specialized in each weightset.
Definition: weightset.hh:208
std::string to_string(direction d)
Conversion to string.
Definition: direction.cc:7
virtual void parse_param_(const std::string &weights)
Definition: weightset.hh:144
decltype(std::declval< T >() .power(std::declval< typename T::value_t >(), 0)) power_mem_fn_t
The signature of power.
Definition: weightset.hh:41
std::map< weight_t, float, vcsn::less< weightset_t > > weight_map_t
Elements given by the user and their associated probabilities (weight_weight_).
Definition: weightset.hh:198
value_impl< detail::weight_tag > weight
Definition: fwd.hh:34
weight_t print_random_weight_() const
A random weight.
Definition: weightset.hh:174
return res
Definition: multiply.hh:399
random_weight_base(random_generator_t &gen, const weightset_t &ws)
Definition: weightset.hh:125