Vcsn  2.3
Be Rational
to-expansion.hh
Go to the documentation of this file.
1 #pragma once
2 
8 #include <vcsn/ctx/fwd.hh>
9 #include <vcsn/dyn/value.hh>
10 #include <vcsn/misc/indent.hh>
11 #include <vcsn/misc/map.hh>
12 #include <vcsn/misc/raise.hh>
14 
15 //# define DEBUG 1
16 
17 #if DEBUG
18 # define DEBUG_IFELSE(Then, Else) Then
19 #else
20 # define DEBUG_IFELSE(Then, Else) Else
21 #endif
22 
23 #define DEBUG_IF(Then) DEBUG_IFELSE(Then,)
24 
25 namespace vcsn
26 {
27 
28  namespace rat
29  {
30 
31  /*------------------------.
32  | to_expansion_visitor. |
33  `------------------------*/
34 
38  template <typename ExpSet>
40  : public ExpSet::const_visitor
41  {
42  public:
43  using expressionset_t = ExpSet;
44  using super_t = typename expressionset_t::const_visitor;
46 
49  using expression_t = typename expressionset_t::value_t;
51  using weight_t = typename weightset_t::value_t;
53 
56 
57  constexpr static const char* me() { return "to_expansion"; }
58 
59  using polys_t = typename expansionset_t::polys_t;
61 
63  : rs_(rs)
64  {}
65 
68  {
69  try
70  {
71  res_ = es_.zero();
72  v->accept(*this);
73  return res_;
74  }
75  catch (const std::runtime_error& e)
76  {
77  raise(e, " while computing expansion of: ", to_string(rs_, v));
78  }
79  }
80 
81  private:
82 #if CACHE
86 #endif
87  expansion_t to_expansion(const expression_t& e)
91  {
92 #if CACHE
93  auto insert = cache_.emplace(e, es_.zero());
94  auto& res = insert.first->second;
95  if (insert.second)
96  {
97  std::swap(res, res_);
98  DEBUG_IF(rs_.print(e, std::cerr) << "..." << incendl);
99  e->accept(*this);
100  std::swap(res, res_);
101  DEBUG_IF(
102  rs_.print(e, std::cerr) << " => ";
103  print_(res, std::cerr) << decendl;
104  );
105  }
106  else
107  {
108  DEBUG_IF(
109  rs_.print(e, std::cerr) << " -> ";
110  print_(res, std::cerr) << iendl;
111  );
112  }
113  return res;
114 #else
115  auto res = es_.zero();
116  std::swap(res, res_);
117  e->accept(*this);
118  std::swap(res, res_);
119  DEBUG_IF(
120  rs_.print(e, std::cerr) << " -> ";
121  print_(res, std::cerr) << iendl;
122  );
123  return res;
124 #endif
125  }
126 
128  std::ostream& print_(const expansion_t& v, std::ostream& o) const
129  {
130  es_.print(v, o);
131  if (transposed_)
132  o << " (transposed)";
133  return o;
134  }
135 
136  private:
138  {
139  res_ = es_.zero();
140  }
141 
143  {
144  res_ = es_.one();
145  }
146 
148  {
150  ? ls_.transpose(e.value())
151  : e.value());
152  }
153 
155  {
156  res_ = es_.zero();
157  for (const auto& v: e)
159  }
160 
162  {
163  res_ = es_.one();
164  for (size_t i = 0, size = e.size(); i < size; ++i)
165  {
166  auto r = e[transposed_ ? size-1 - i : i];
167  expansion_t rhs = to_expansion(r);
168  if (transposed_)
169  r = rs_.transposition(r);
170 
171  // Instead of performing successive binary
172  // multiplications, we immediately multiply the current
173  // expansion by all the remaining operands on its right
174  // hand side. This will also allow us to break the
175  // iterations as soon as an expansion has a null constant
176  // term.
177  //
178  // In essence, it allows us to treat the product as if it
179  // were right-associative: in `E.(FG)`, if `c(E) != 0`, we
180  // don't need to traverse `FG`, just append it to
181  // `d_p(E)`.
182  //
183  // Also, using prod_ saves from a useless application of
184  // the identities with repeated multiplications, which
185  // have already been applied. Large performance impact.
186  //
187  // The gain is very effective.
188  expression_t rhss
189  = transposed_
190  ? rs_.transposition(prod_(e.begin(),
191  std::next(e.begin(), size-(i+1))))
192  : prod_(std::next(e.begin(), i + 1), std::end(e));
193  es_.rweight_here(rhs, rhss);
194 
195  for (const auto& p: rhs.polynomials)
196  ps_.add_here(res_.polynomials[p.first],
197  ps_.lweight(res_.constant, p.second));
198  res_.constant = ws_.mul(res_.constant, rhs.constant);
199  // Nothing else will be added.
200  if (ws_.is_zero(res_.constant))
201  break;
202  }
203  }
204 
209  expression_t
210  prod_(typename mul_t::iterator begin,
211  typename mul_t::iterator end) const
212  {
213  using expressions_t = typename mul_t::values_t;
214  if (begin == end)
215  return rs_.one();
216  else if (std::next(begin, 1) == end)
217  return *begin;
218  else
219  return std::make_shared<mul_t>(expressions_t{begin, end});
220  }
221 
223  {
224  assert(e.size() == 2);
225  DEBUG_IF(
226  std::cerr << "Start: ";
227  rs_.print(e.shared_from_this(), std::cerr) << " =>\n";
228  );
229 
230  bool transposed = transposed_;
231  transposed_ = false;
232  expansion_t lhs = to_expansion(e[0]);
233  expansion_t rhs = to_expansion(e[1]);
234  es_.denormalize(lhs);
235  es_.denormalize(rhs);
236  transposed_ = transposed;
237  DEBUG_IF(
238  std::cerr << "Lhs: "; print_(lhs, std::cerr) << '\n';
239  std::cerr << "Rhs: "; print_(rhs, std::cerr) << '\n';
240  );
241  res_ = es_.zero();
242  auto one = detail::label_one(ls_);
243  for (const auto& p: zip_maps(lhs.polynomials, rhs.polynomials))
244  for (const auto& lm: std::get<0>(p.second))
245  for (const auto& rm: std::get<1>(p.second))
246  // Now, recursively develop the quotient of monomials,
247  // directly in res_.
248  if (transposed_)
249  ps_.add_here(res_.polynomials[one],
250  rs_.transposition(rs_.ldivide(label_of(lm),
251  label_of(rm))),
252  ws_.transpose(ws_.ldivide(weight_of(lm),
253  weight_of(rm))));
254  else
255  ps_.add_here(res_.polynomials[one],
256  rs_.ldivide(label_of(lm), label_of(rm)),
257  ws_.ldivide(weight_of(lm), weight_of(rm)));
258  if (has(lhs.polynomials, one))
259  for (const auto& rhsp: rhs.polynomials)
260  if (rhsp.first != one)
261  for (const auto& lm: lhs.polynomials[one])
262  for (const auto& rm: rhsp.second)
263  {
264  if (transposed_)
265  ps_.add_here(res_.polynomials[one],
266  rs_.transposition(
267  rs_.ldivide(label_of(lm),
268  rs_.mul(rs_.atom(rhsp.first),
269  label_of(rm)))),
270  ws_.transpose(ws_.ldivide(weight_of(lm), weight_of(rm))));
271  else
272  ps_.add_here(res_.polynomials[one],
273  rs_.ldivide(label_of(lm),
274  rs_.mul(rs_.atom(rhsp.first), label_of(rm))),
275  ws_.ldivide(weight_of(lm), weight_of(rm)));
276  }
277  if (has(rhs.polynomials, one))
278  for (const auto& lhsp: lhs.polynomials)
279  if (lhsp.first != one)
280  for (const auto& lm: lhsp.second)
281  for (const auto& rm: rhs.polynomials[one])
282  {
283  if (transposed_)
284  ps_.add_here(res_.polynomials[one],
285  rs_.transposition(
286  rs_.ldivide(rs_.mul(rs_.atom(lhsp.first), label_of(lm)),
287  label_of(rm))),
288  ws_.transpose(ws_.ldivide(weight_of(lm), weight_of(rm))));
289  else
290  ps_.add_here(res_.polynomials[one],
291  rs_.ldivide(rs_.mul(rs_.atom(lhsp.first), label_of(lm)),
292  label_of(rm)),
293  ws_.ldivide(weight_of(lm), weight_of(rm)));
294  }
295  es_.normalize(res_);
296  }
297 
300  {
301  res_ = to_expansion(e.head());
302  for (const auto& r: e.tail())
304  }
305 
309  {
310  // The shuffle-product of the previously traversed siblings,
311  // to compute the "E:d(F)" part, E being all the previous lhs.
312  auto prev = e.head();
313  res_ = to_expansion(prev);
314  for (const auto& r: e.tail())
315  {
316  res_ = es_.shuffle(res_,
317  transposed_ ? rs_.transposition(prev) : prev,
318  to_expansion(r),
319  transposed_ ? rs_.transposition(r) : r);
320  prev = rs_.shuffle(prev, r);
321  }
322  }
323 
327  {
328  // The infiltration-product of the previously traversed
329  // siblings, to compute the "E&:d(F)" part, E being all the
330  // previous lhs.
331  auto prev = e.head();
332  res_ = to_expansion(prev);
333  for (const auto& r: e.tail())
334  {
336  (res_,
337  transposed_ ? rs_.transposition(prev) : prev,
338  to_expansion(r),
339  transposed_ ? rs_.transposition(r) : r);
340  prev = rs_.infiltrate(prev, r);
341  }
342  }
343 
345  {
346  res_ = es_.complement(to_expansion(e.sub()));
347  }
348 
351  {
353  e.sub()->accept(*this);
355  }
356 
358  {
359  expansion_t res = to_expansion(e.sub());
360  res_.constant = ws_.star(res.constant);
361  auto f = e.shared_from_this();
362  if (transposed_)
363  {
364  res_.constant = ws_.transpose(res_.constant);
365  f = rs_.transposition(f);
366  }
367 
368  for (const auto& p: res.polynomials)
369  res_.polynomials[label_of(p)]
370  = ps_.lweight(res_.constant,
371  ps_.rmul_label(weight_of(p), f));
372  }
373 
375  {
376  auto l = e.weight();
377  auto r = to_expansion(e.sub());
378  res_
379  = transposed_
380  ? es_.rweight(r, ws_.transpose(l))
381  : es_.lweight_here(l, r);
382  }
383 
385  {
386  auto l = to_expansion(e.sub());
387  auto r = e.weight();
388  res_
389  = transposed_
390  ? es_.lweight_here(ws_.transpose(r), l)
391  : es_.rweight(l, r);
392  }
393 
394  using tuple_t = typename super_t::tuple_t;
395 
396  template <bool = context_t::is_lat,
397  typename Dummy = void>
398  struct visit_tuple
399  {
400  template <size_t... I>
402  {
403  return
404  visitor_
405  .es_
406  .tuple(vcsn::to_expansion(detail::project<I>(visitor_.rs_),
407  std::get<I>(v.sub()))...);
408  }
409 
410  expansion_t operator()(const tuple_t& v)
411  {
413  }
414  const self_t& visitor_;
415  };
416 
417  template <typename Dummy>
418  struct visit_tuple<false, Dummy>
419  {
420  expansion_t operator()(const tuple_t&)
421  {
423  }
424  const self_t& visitor_;
425  };
426 
427  void visit(const tuple_t& v, std::true_type) override
428  {
429  res_ = visit_tuple<>{*this}(v);
430  }
431 
432  // d(E@F) = d(E)@d(F).
434  {
435  compose(e, 0);
436  }
437 
438  template <typename Exp = expansion_t>
439  auto compose(const compose_t& e, int)
440  -> decltype(std::declval<expansionset_t>()
441  .compose(std::declval<Exp>(), std::declval<Exp>()),
442  void())
443  {
444  res_ = to_expansion(e.head());
445  for (const auto& r: e.tail())
447  }
448 
449  auto compose(const compose_t&, long)
450  -> void
451  {
452  require(false, "compose: context is not composable");
453  }
454 
455 
459  labelset_t ls_ = *rs_.labelset();
461  weightset_t ws_ = *rs_.weightset();
466 
468  bool transposed_ = false;
470  expansion_t res_;
471  };
472  } // rat::
473 
475  template <typename ExpSet>
477  to_expansion(const ExpSet& rs, const typename ExpSet::value_t& e)
478  {
480  return to_expansion(e);
481  }
482 
483  namespace dyn
484  {
485  namespace detail
486  {
488  template <typename ExpSet>
489  expansion
491  {
492  const auto& e = exp->as<ExpSet>();
493  const auto& rs = e.valueset();
495  return {es, to_expansion<ExpSet>(rs, e.value())};
496  }
497  }
498  }
499 } // vcsn::
VCSN_RAT_VISIT(infiltrate, e)
d(E&:F) = d(E)&:F + d(E)&:d(F) + E&:d(F) dᵗ(E&:F) = dᵗ(E)&:Fᵗ + dᵗ(E)&:dᵗ(F) + Eᵗ&:dᵗ(F) ...
return v
Definition: multiply.hh:361
value_t & normalize(value_t &res) const
Normalize: move the constant term to the label one.
expressionset_t rs_
Manipulate the expressions.
labelset_t ls_
Manipulate the labels.
VCSN_RAT_VISIT(shuffle, e)
d(E:F) = d(E):F + E:d(F) dᵗ(E:F) = dᵗ(E):Fᵗ + Eᵗ:dᵗ(F)
std::ostream & print_(const expansion_t &v, std::ostream &o) const
Print an expansion.
#define BUILTIN_UNREACHABLE()
Definition: builtins.hh:13
weightset_t ws_
Manipulate the weights.
value_t & denormalize(value_t &res) const
Move the constant to the polynomial associated to one.
std::ostream & incendl(std::ostream &o)
Increment the indentation, print an end of line, and set the indentation.
Definition: indent.cc:54
auto compose(const compose_t &, long) -> void
auto label_one(const LabelSet &ls) -> typename LabelSet::value_t
Enjoy type inference.
Definition: labelset.hh:53
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:63
typename expansionset_t::polys_t polys_t
Definition: to-expansion.hh:59
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
auto compose(value_t l, value_t r) const -> std::enable_if_t< are_composable< Ctx, Ctx >
The composition of l and r.
typename expressionset_t::value_t expression_t
Definition: to-expansion.hh:49
typename detail::context_t_of_impl< base_t< ValueSet >>::type context_t_of
Definition: traits.hh:61
std::ostream & iendl(std::ostream &o)
Print an end of line, then set the indentation.
Definition: indent.cc:49
auto tuple(Expansions &&...es) const -> value_t
The tuplization of single-tape expansions into a multitape expansion.
auto label_of(const welement< Label, Weight > &m) -> decltype(m.label())
The label of a welement.
Definition: wet.hh:146
std::ostream & decendl(std::ostream &o)
Decrement the indentation, print an end of line, and set the indentation.
Definition: indent.cc:59
value_t infiltrate(const value_t &lhs_xpn, const expression_t &lhs_xpr, const value_t &rhs_xpn, const expression_t &rhs_xpr) const
The infiltration product of l and r.
VCSN_RAT_VISIT(transposition, e)
d(Eᵗ) = dᵗ(E)
An inner node implementing a weight.
Definition: expression.hh:264
void require(Bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:91
value_t & lweight_here(const weight_t &w, value_t &res) const
Inplace left-multiplication by w of res.
Request the unordered_map implementation.
weightset_t_of< expressionset_t > weightset_t
Definition: to-expansion.hh:50
static constexpr const char * me()
Definition: to-expansion.hh:57
return res
Definition: multiply.hh:398
auto compose(const compose_t &e, int) -> decltype(std::declval< expansionset_t >() .compose(std::declval< Exp >(), std::declval< Exp >()), void())
value_t shuffle(const value_t &lhs_xpn, const expression_t &lhs_xpr, const value_t &rhs_xpn, const expression_t &rhs_xpr) const
The shuffle product of lhs_xpn and rhs_xpn.
value_t atom(const label_t &l) const
A single label.
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
rat::expansionset< ExpSet >::value_t to_expansion(const ExpSet &rs, const typename ExpSet::value_t &e)
First order expansion.
value_t complement(const value_t &v) const
The complement of v.
value_t & rweight_here(value_t &res, const expression_t &rhs) const
In place right multiplication by an expression.
auto rs
Definition: lift.hh:152
typename expansionset_t::value_t expansion_t
Definition: to-expansion.hh:60
std::map< label_t, polynomial_t, vcsn::less< labelset_t >> polys_t
Definition: expansionset.hh:40
Definition: a-star.hh:8
expansion_t work_(const tuple_t &v, detail::index_sequence< I... >)
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:57
bool transposed_
Whether to work transposed.
void visit(const tuple_t &v, std::true_type) override
#define DEBUG_IF(Then)
Definition: to-expansion.hh:23
Indentation relative functions.
expansion_t to_expansion(const expression_t &e)
Facilitate recursion.
Definition: to-expansion.hh:90
value_t zero() const
The zero.
polynomialset_t ps_
Manipulate the polynomials of expressions.
value_impl< detail::expansion_tag > expansion
Definition: fwd.hh:24
Functor to compute the expansion of an expression.
Definition: to-expansion.hh:39
void add_here(value_t &lhs, const value_t &rhs) const
In place addition.
std::string to_string(identities i)
Wrapper around operator<<.
Definition: identities.cc:41
value_t one() const
The one.
expression_t prod_(typename mul_t::iterator begin, typename mul_t::iterator end) const
Build a product for these expressions.
to_expansion_visitor(const expressionset_t &rs)
Definition: to-expansion.hh:62
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
The weight of a welement.
Definition: wet.hh:154
expansionset_t es_
Manipulate the expansions.
expansion_t operator()(const tuple_t &v)
expansion_t operator()(const expression_t &v)
From an expression, build its expansion.
Definition: to-expansion.hh:67
auto & as()
Extract wrapped typed value.
Definition: value.hh:53
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:67
typename expressionset_t::const_visitor super_t
Definition: to-expansion.hh:44
expansion to_expansion(const expression &exp)
Bridge.
expression_polynomialset_t< ExpSet > make_expression_polynomialset(const ExpSet &rs)
From a ExpSet to its polynomialset.
Definition: split.hh:31
value_t rweight(const value_t &lhs, const weight_t &w) const
Right-multiplication of lhs by w.
An inner node with multiple children.
Definition: expression.hh:118
expansion_t res_
The result.
std::ostream & print(const value_t &v, std::ostream &o, format fmt={}) const
Print this expansion.
VCSN_RAT_VISIT(conjunction, e)
d(E&F) = d(E) & d(F).
zipped_maps< Dereference, Maps... > zip_maps(Maps &&...maps)
Definition: zip-maps.hh:250
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
typename polynomialset_t::value_t polynomial_t
Definition: to-expansion.hh:55
value_impl< detail::expression_tag > expression
Definition: fwd.hh:25
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:12
value_t conjunction(const value_t &l, const value_t &r) const
The conjunction of l and r.
context_t_of< expressionset_t > context_t
Definition: to-expansion.hh:47
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54