Vcsn  2.8
Be Rational
evaluate.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <vector>
4 #include <queue>
5 
7 #include <vcsn/core/automaton.hh> // out
8 #include <vcsn/ctx/traits.hh>
9 #include <vcsn/dyn/automaton.hh>
10 #include <vcsn/dyn/fwd.hh>
11 #include <vcsn/dyn/value.hh>
14 #include <vcsn/misc/algorithm.hh>
15 #include <vcsn/misc/type_traits.hh>
16 
17 namespace vcsn
18 {
19  namespace detail
20  {
22  template <Automaton Aut>
23  class evaluator
24  {
25  using automaton_t = Aut;
32  using polynomial_t = typename wps_t::value_t;
34  using weight_t = typename weightset_t::value_t;
35 
37  using weights_t = std::vector<weight_t>;
38 
39  public:
41  : aut_(a)
42  {}
43 
45  {
50  {
51  w = w_;
52  l = l_;
53  s = s_;
54  }
55  };
56 
58  template <typename LabelSet = labelset_t>
59  std::enable_if_t<!LabelSet::is_free(),
60  weight_t>
61  operator()(const word_t& word) const
62  {
63  // Initialization.
64  auto res = ws_.zero();
65 
66  // A queue of current word states in the automaton.
67  auto q = std::queue<labeled_weight>{};
68  q.emplace(ws_.one(), wordset_.delimit(word), aut_->pre());
69 
70  while (!q.empty())
71  {
72  auto cur = q.front();
73  q.pop();
74 
75  for (const auto t : all_out(aut_, cur.s))
76  if (aut_->dst_of(t) == aut_->post() && wordset_.is_special(cur.l))
77  // The word is accepted.
78  {
79  cur.w = ws_.mul(cur.w, aut_->weight_of(t));
80  res = ws_.add(res, cur.w);
81  }
82  else if (auto new_word
83  = wordset_.maybe_ldivide(ls_.word(aut_->label_of(t)), cur.l))
84  q.emplace(
85  ws_.mul(cur.w, aut_->weight_of(t)),
86  std::move(*new_word),
87  aut_->dst_of(t));
88  }
89 
90  return res;
91  }
92 
93  template <typename LabelSet = labelset_t>
94  std::enable_if_t<LabelSet::is_free(),
95  weight_t>
96  operator()(const word_t& word) const
97  {
98  // An array indexed by state numbers.
99  //
100  // Do not use braces (v1{size, ws_.zero()}): the type of zero
101  // might result in the compiler believing we are building a
102  // vector with two values: size and zero.
103  //
104  // We start with just two states numbered 0 and 1: pre() and
105  // post().
106  auto v1 = weights_t(2, ws_.zero());
107  v1.reserve(states_size(aut_));
108  v1[aut_->pre()] = ws_.one();
109  auto v2 = v1;
110  v2.reserve(states_size(aut_));
111 
112  // Computation.
113  for (const auto l : ls_.letters_of(ls_.delimit(word)))
114  {
115  v2.assign(v2.size(), ws_.zero());
116  for (size_t s = 0; s < v1.size(); ++s)
117  if (!ws_.is_zero(v1[s])) // delete if bench >
118  for (const auto t : out(aut_, s, l))
119  {
120  const auto dst = aut_->dst_of(t);
121  // Make sure the vectors are large enough for dst.
122  // Exponential growth on the capacity, but keep
123  // the actual size as small as possible.
124  if (v2.size() <= dst)
125  {
126  auto capacity = v2.capacity();
127  while (capacity <= dst)
128  capacity *= 2;
129  v1.reserve(capacity);
130  v2.reserve(capacity);
131  v1.resize(dst + 1, ws_.zero());
132  v2.resize(dst + 1, ws_.zero());
133  }
134  // Introducing a reference to v2[dst] is tempting,
135  // but won't work for std::vector<bool>. FIXME:
136  // Specialize for Boolean? Or introduce add_here.
137  v2[dst] =
138  ws_.add(v2[dst],
139  ws_.mul(v1[s], aut_->weight_of(t)));
140  }
141  std::swap(v1, v2);
142  }
143  return v1[aut_->post()];
144  }
145 
147  weight_t operator()(const polynomial_t& poly) const
148  {
149  // Since the algorithm itself is about circulating monomials,
150  // it's natural to load the queue with a polynonial, rather
151  // than performing a full evaluation for each monomial of the
152  // polynonial. But this benchmark:
153  //
154  // import vcsn
155  // c = vcsn.context('law(a-z), z')
156  // a = c.de_bruijn(100)
157  // p = c.polynomial('\z')
158  // for i in range(1, 100):
159  // p = p + c.polynomial('abcxyz' * i)
160  // print(vcsn.timeit(lambda: a(p)))
161  //
162  // shows no improvement if we do so.
163  auto res = ws_.zero();
164  for (const auto& m: poly)
165  res = ws_.add(res, ws_.mul(weight_of(m), operator()(label_of(m))));
166  return res;
167  }
168 
169  private:
171  const weightset_t& ws_ = *aut_->weightset();
172  const labelset_t& ls_ = *aut_->labelset();
173  const wordset_t wordset_ = make_wordset(*aut_->labelset());
174  const wps_t wps_ = make_word_polynomialset(aut_->context());
175  };
176 
177  } // namespace detail
178 
180  template <Automaton Aut>
181  auto
182  evaluate(const Aut& a, const word_t_of<Aut>& w)
183  -> std::enable_if_t<!context_t_of<Aut>::is_lao, weight_t_of<Aut>>
184  {
185  auto e = detail::evaluator<Aut>{a};
186  return e(w);
187  }
188 
194  template <Automaton Aut>
195  auto
196  evaluate(const Aut& a, const label_t_of<Aut>& = {})
197  -> std::enable_if_t<context_t_of<Aut>::is_lao, weight_t_of<Aut>>
198  {
199  require(is_proper(a),
200  "evaluate: cannot evaluate with spontaneous transitions");
201  const auto& ws = *a->weightset();
202  auto res = ws.zero();
203  for (const auto init_tr: initial_transitions(a))
204  {
205  const auto s = a->dst_of(init_tr);
206  const auto w = a->weight_of(init_tr);
207  for (const auto out: all_out(a, s))
208  {
209  assert(a->dst_of(out) == a->post());
210  res = ws.add(res, ws.mul(w, a->weight_of(out)));
211  }
212  }
213  return res;
214  }
215 
216  namespace dyn
217  {
218  namespace detail
219  {
221  template <Automaton Aut, typename LabelSet>
222  weight
223  evaluate(const automaton& aut, const label& lbl)
224  {
225  using ctx_t = context_t_of<Aut>;
226  // This is utterly wrong, as we do not support
227  // lat<expressionset, ...>. but currently we have no means to
228  // tell the difference. We probably need something like
229  // "is_graduated".
230  constexpr auto valid
231  = (ctx_t::is_lal || ctx_t::is_lan || ctx_t::is_lao
232  || ctx_t::is_lat || ctx_t::is_law);
233  return vcsn::detail::static_if<valid>
234  ([](const auto& a, const auto& l) -> weight
235  {
236  auto res = ::vcsn::evaluate(a, l);
237  return {*a->weightset(), res};
238  },
239  [](const auto& a, const auto&) -> weight
240  {
241  raise("evaluate: unsupported labelset: ",
242  *a->labelset());
243  })
244  (aut->as<Aut>(), lbl->as<LabelSet>().value());
245  }
246  }
247  }
248 
250  template <Automaton Aut>
251  auto
252  evaluate(const Aut& a,
253  const typename detail::word_polynomialset_t<context_t_of<Aut>>::value_t& p)
255  {
256  auto e = detail::evaluator<Aut>{a};
257  return e(p);
258  }
259 
260 
261  namespace dyn
262  {
263  namespace detail
264  {
266  template <Automaton Aut, typename PolynomialSet>
267  weight
268  evaluate_polynomial(const automaton& aut, const polynomial& poly)
269  {
270  const auto& a = aut->as<Aut>();
271  const auto& p = poly->as<PolynomialSet>().value();
272  auto res = ::vcsn::evaluate(a, p);
273  return {*a->weightset(), res};
274  }
275  }
276  }
277 } // namespace vcsn
std::vector< weight_t > weights_t
state -> weight.
Definition: evaluate.hh:37
A dyn automaton.
Definition: automaton.hh:17
auto initial_transitions(const Aut &aut) -> decltype(aut->all_out(aut->pre()))
Indexes of transitions to (visible) initial states.
Definition: automaton.hh:167
weight evaluate_polynomial(const automaton &aut, const polynomial &poly)
Bridge (evaluate).
Definition: evaluate.hh:268
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
Definition: traits.hh:67
std::enable_if_t<!LabelSet::is_free(), weight_t > operator()(const word_t &word) const
Evaluation of a word.
Definition: evaluate.hh:61
typename detail::state_t_of_impl< base_t< ValueSet > >::type state_t_of
Definition: traits.hh:64
size_t states_size(const Aut &aut)
The largest state number, plus one.
Definition: automaton.hh:41
state_t_of< automaton_t > state_t
Definition: evaluate.hh:27
bool is_proper(const Aut &aut)
Test whether an automaton is proper.
Definition: is-proper.hh:47
typename wps_t::value_t polynomial_t
Definition: evaluate.hh:32
const weightset_t & ws_
Definition: evaluate.hh:171
labeled_weight(weight_t w_, word_t l_, state_t s_)
Definition: evaluate.hh:49
auto & as()
Extract wrapped typed value.
Definition: value.hh:55
word_t_of< automaton_t > word_t
Definition: evaluate.hh:28
auto all_out(const Aut &aut, state_t_of< Aut > s)
Indexes of transitions leaving state s.
Definition: automaton.hh:67
typename detail::context_t_of_impl< base_t< ValueSet > >::type context_t_of
Definition: traits.hh:61
auto evaluate(const Aut &a, const typename detail::word_polynomialset_t< context_t_of< Aut >>::value_t &p) -> weight_t_of< Aut >
Evaluation of a polynomial.
Definition: evaluate.hh:252
auto evaluate(const Aut &a, const word_t_of< Aut > &w) -> std::enable_if_t<!context_t_of< Aut >::is_lao, weight_t_of< Aut >>
General case of evaluation.
Definition: evaluate.hh:182
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
evaluator(const automaton_t &a)
Definition: evaluate.hh:40
context_t_of< automaton_t > context_t
Definition: evaluate.hh:30
const labelset_t & ls_
Definition: evaluate.hh:172
const wordset_t wordset_
Definition: evaluate.hh:173
A dyn Value/ValueSet.
Definition: fwd.hh:29
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
Definition: traits.hh:63
Definition: a-star.hh:8
typename detail::label_t_of_impl< base_t< ValueSet > >::type label_t_of
Definition: traits.hh:62
Evaluate a word on an automaton.
Definition: evaluate.hh:23
law_t< labelset_t > wordset_t
Definition: evaluate.hh:29
typename law_traits< LabelSet >::type law_t
The smallest wordset that includes LabelSet.
Definition: labelset.hh:254
auto & as()
Extract wrapped typed automaton.
Definition: automaton.hh:37
auto make_word_polynomialset(const Ctx &ctx) -> word_polynomialset_t< Ctx >
The polynomialset of words of a labelset (not necessarily on words itself).
void swap(config::value &first, config::value &second)
typename weightset_t::value_t weight_t
Definition: evaluate.hh:34
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
The weight of a welement.
Definition: wet.hh:154
auto label_of(const welement< Label, Weight > &m) -> decltype(m.label())
The label of a welement.
Definition: wet.hh:146
typename labelset_t_of< base_t< ValueSet > >::word_t word_t_of
Definition: traits.hh:90
std::enable_if_t< LabelSet::is_free(), weight_t > operator()(const word_t &word) const
Definition: evaluate.hh:96
law_t< LabelSet > make_wordset(const LabelSet &ls)
The wordset of a labelset.
Definition: labelset.hh:259
weight_t operator()(const polynomial_t &poly) const
Polynomial implementation.
Definition: evaluate.hh:147
weightset_t_of< automaton_t > weightset_t
Definition: evaluate.hh:33
labelset_t_of< automaton_t > labelset_t
Definition: evaluate.hh:26
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:87
typename detail::weight_t_of_impl< base_t< ValueSet > >::type weight_t_of
Definition: traits.hh:66
value_impl< detail::weight_tag > weight
Definition: fwd.hh:34
return res
Definition: multiply.hh:399
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.
Definition: automaton.hh:86