Vcsn  2.2
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/expansion.hh>
10 #include <vcsn/dyn/polynomial.hh>
11 #include <vcsn/dyn/expression.hh>
12 #include <vcsn/misc/indent.hh>
13 #include <vcsn/misc/raise.hh>
15 
16 //# define DEBUG 1
17 
18 #if DEBUG
19 # define DEBUG_IFELSE(Then, Else) Then
20 #else
21 # define DEBUG_IFELSE(Then, Else) Else
22 #endif
23 
24 #define DEBUG_IF(Then) DEBUG_IFELSE(Then,)
25 
26 namespace vcsn
27 {
28 
29  namespace rat
30  {
31 
32  /*------------------------.
33  | to_expansion_visitor. |
34  `------------------------*/
35 
39  template <typename ExpSet>
41  : public ExpSet::const_visitor
42  {
43  public:
44  using expressionset_t = ExpSet;
45  using super_t = typename expressionset_t::const_visitor;
47 
50  using expression_t = typename expressionset_t::value_t;
52  using weight_t = typename weightset_t::value_t;
54 
57 
58  constexpr static const char* me() { return "to_expansion"; }
59 
60  using polys_t = typename expansionset_t::polys_t;
62 
64  : rs_(rs)
65  {}
66 
69  {
70  res_ = es_.zero();
71  v->accept(*this);
72  return res_;
73  }
74 
75  private:
76 #if CACHE
80 #endif
81  expansion_t to_expansion(const expression_t& e)
85  {
86 #if CACHE
87  auto insert = cache_.emplace(e, es_.zero());
88  auto& res = insert.first->second;
89  if (insert.second)
90  {
91  std::swap(res, res_);
92  DEBUG_IF(rs_.print(e, std::cerr) << "..." << incendl);
93  e->accept(*this);
94  std::swap(res, res_);
95  DEBUG_IF(
96  rs_.print(e, std::cerr) << " => ";
97  print_(res, std::cerr) << decendl;
98  );
99  }
100  else
101  {
102  DEBUG_IF(
103  rs_.print(e, std::cerr) << " -> ";
104  print_(res, std::cerr) << iendl;
105  );
106  }
107  return res;
108 #else
109  auto res = es_.zero();
110  std::swap(res, res_);
111  e->accept(*this);
112  std::swap(res, res_);
113  DEBUG_IF(
114  rs_.print(e, std::cerr) << " -> ";
115  print_(res, std::cerr) << iendl;
116  );
117  return res;
118 #endif
119  }
120 
122  std::ostream& print_(const expansion_t& v, std::ostream& o) const
123  {
124  es_.print(v, o);
125  if (transposed_)
126  o << " (transposed)";
127  return o;
128  }
129 
130  private:
132  {
133  res_ = es_.zero();
134  }
135 
137  {
138  res_ = es_.one();
139  }
140 
142  {
144  ? ls_.transpose(e.value())
145  : e.value());
146  }
147 
149  {
150  res_ = es_.zero();
151  for (const auto& v: e)
153  }
154 
156  {
157  res_ = es_.one();
158  for (size_t i = 0, size = e.size(); i < size; ++i)
159  {
160  auto r = e[transposed_ ? size-1 - i : i];
161  expansion_t rhs = to_expansion(r);
162  if (transposed_)
163  r = rs_.transposition(r);
164 
165  // Instead of performing successive binary
166  // multiplications, we immediately multiply the current
167  // expansion by all the remaining operands on its right
168  // hand side. This will also allow us to break the
169  // iterations as soon as an expansion has a null constant
170  // term.
171  //
172  // In essence, it allows us to treat the product as if it
173  // were right-associative: in `E.(FG)`, if `c(E) != 0`, we
174  // don't need to traverse `FG`, just append it to
175  // `d_p(E)`.
176  //
177  // Also, using prod_ saves from a useless application of
178  // the identities with repeated multiplications, which
179  // have already been applied. Large performance impact.
180  //
181  // The gain is very effective.
182  expression_t rhss
183  = transposed_
184  ? rs_.transposition(prod_(e.begin(),
185  std::next(e.begin(), size-(i+1))))
186  : prod_(std::next(e.begin(), i + 1), std::end(e));
187  es_.rmul_here(rhs, rhss);
188 
189  for (const auto& p: rhs.polynomials)
190  ps_.add_here(res_.polynomials[p.first],
191  ps_.lmul(res_.constant, p.second));
192  res_.constant = ws_.mul(res_.constant, rhs.constant);
193  // Nothing else will be added.
194  if (ws_.is_zero(res_.constant))
195  break;
196  }
197  }
198 
203  expression_t
204  prod_(typename prod_t::iterator begin,
205  typename prod_t::iterator end) const
206  {
207  using expressions_t = typename prod_t::values_t;
208  if (begin == end)
209  return rs_.one();
210  else if (std::next(begin, 1) == end)
211  return *begin;
212  else
213  return std::make_shared<prod_t>(expressions_t{begin, end});
214  }
215 
217  {
218  assert(e.size() == 2);
219  DEBUG_IF(
220  std::cerr << "Start: ";
221  rs_.print(e.shared_from_this(), std::cerr) << " =>\n";
222  );
223 
224  bool transposed = transposed_;
225  transposed_ = false;
226  expansion_t lhs = to_expansion(e[0]);
227  expansion_t rhs = to_expansion(e[1]);
228  transposed_ = transposed;
229  DEBUG_IF(
230  std::cerr << "Lhs: "; print_(lhs, std::cerr) << '\n';
231  std::cerr << "Rhs: "; print_(rhs, std::cerr) << '\n';
232  );
233  res_ = es_.zero();
234  // lp: (label, left_polynomial)
235  if (!ws_.is_zero(lhs.constant))
236  {
237  if (transposed_)
238  {
239  auto rhs_transposed = to_expansion(e[1]);
240  es_.add_here(res_,
241  es_.ldiv_here(lhs.constant, rhs_transposed));
242  }
243  else
244  es_.add_here(res_, es_.ldiv_here(lhs.constant, rhs));
245  }
246  auto one = detail::label_one(ls_);
247  for (const auto& p: zip_maps(lhs.polynomials, rhs.polynomials))
248  for (const auto& lm: std::get<0>(p.second))
249  for (const auto& rm: std::get<1>(p.second))
250  // Now, recursively develop the quotient of monomials,
251  // directly in res_.
252  if (transposed_)
253  ps_.add_here(res_.polynomials[one],
254  rs_.transposition(rs_.ldiv(label_of(lm),
255  label_of(rm))),
256  ws_.transpose(ws_.ldiv(weight_of(lm),
257  weight_of(rm))));
258  else
259  ps_.add_here(res_.polynomials[one],
260  rs_.ldiv(label_of(lm), label_of(rm)),
261  ws_.ldiv(weight_of(lm), weight_of(rm)));
262  es_.normalize(res_);
263  }
264 
265  // d(E&F) = d(E)&d(F).
267  {
268  res_ = to_expansion(e.head());
269  for (const auto& r: e.tail())
271  }
272 
273  // d(E:F) = d(E):F + E:d(F)
275  {
276  // The shuffle-product of the previously traversed siblings,
277  // to compute the "E:d(F)" part, E being all the previous lhs.
278  auto prev = e.head();
279  res_ = to_expansion(prev);
280  for (const auto& r: e.tail())
281  {
282  res_ = es_.shuffle(res_, prev,
283  to_expansion(r), r);
284  prev = rs_.shuffle(prev, r);
285  }
286  }
287 
288  // d(E&:F) = d(E)&:F + d(E)&:d(F) + E&:d(F)
290  {
291  // The infiltration-product of the previously traversed
292  // siblings, to compute the "E&:d(F)" part, E being all the
293  // previous lhs.
294  auto prev = e.head();
295  res_ = to_expansion(prev);
296  for (const auto& r: e.tail())
297  {
298  res_ = es_.infiltration(res_, prev,
299  to_expansion(r), r);
300  prev = rs_.infiltration(prev, r);
301  }
302  }
303 
305  {
306  res_ = es_.complement(to_expansion(e.sub()));
307  }
308 
309 
311  {
313  e.sub()->accept(*this);
315  }
316 
318  {
319  expansion_t res = to_expansion(e.sub());
320  res_.constant = ws_.star(res.constant);
321  auto f = e.shared_from_this();
322  if (transposed_)
323  {
324  res_.constant = ws_.transpose(res_.constant);
325  f = rs_.transposition(f);
326  }
327 
328  for (const auto& p: res.polynomials)
329  res_.polynomials[label_of(p)]
330  = ps_.lmul(res_.constant,
331  ps_.rmul_label(weight_of(p), f));
332  }
333 
335  {
336  auto l = e.weight();
337  auto r = to_expansion(e.sub());
338  res_
339  = transposed_
340  ? es_.rmul(r, ws_.transpose(l))
341  : es_.lmul_here(l, r);
342  }
343 
345  {
346  auto l = to_expansion(e.sub());
347  auto r = e.weight();
348  res_
349  = transposed_
350  ? es_.lmul_here(ws_.transpose(r), l)
351  : es_.rmul(l, r);
352  }
353 
354  using tuple_t = typename super_t::tuple_t;
355 
356  template <bool = context_t::is_lat,
357  typename Dummy = void>
358  struct visit_tuple
359  {
360  template <size_t... I>
362  {
363  return
364  visitor_
365  .es_
366  .tuple(vcsn::to_expansion(detail::project<I>(visitor_.rs_),
367  std::get<I>(v.sub()))...);
368  }
369 
370  expansion_t operator()(const tuple_t& v)
371  {
373  }
374  const self_t& visitor_;
375  };
376 
377  template <typename Dummy>
378  struct visit_tuple<false, Dummy>
379  {
380  expansion_t operator()(const tuple_t&)
381  {
383  }
384  const self_t& visitor_;
385  };
386 
387  void visit(const tuple_t& v, std::true_type) override
388  {
389  res_ = visit_tuple<>{*this}(v);
390  }
391 
395  labelset_t ls_ = *rs_.labelset();
397  weightset_t ws_ = *rs_.weightset();
402 
404  bool transposed_ = false;
406  expansion_t res_;
407  };
408  } // rat::
409 
411  template <typename ExpSet>
413  to_expansion(const ExpSet& rs, const typename ExpSet::value_t& e)
414  {
416  return to_expansion(e);
417  }
418 
419  namespace dyn
420  {
421  namespace detail
422  {
424  template <typename ExpSet>
425  expansion
427  {
428  const auto& e = exp->as<ExpSet>();
429  const auto& rs = e.expressionset();
431  return make_expansion(es,
432  to_expansion<ExpSet>(rs, e.expression()));
433  }
434  }
435  }
436 } // vcsn::
void visit(const tuple_t &v, std::true_type) override
value_t conjunction(value_t l, value_t r) const
The conjunction of l and r.
std::ostream & incendl(std::ostream &o)
Increment the indentation, print an end of line, and set the indentation.
Definition: indent.cc:54
value_t complement(const value_t &v) const
The complement of v.
expansion_t operator()(const tuple_t &v)
void add_here(value_t &lhs, const value_t &rhs) const
In place addition.
#define DEBUG_IF(Then)
Definition: to-expansion.hh:24
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:59
labelset_t ls_
Manipulate the labels.
typename expressionset_t::const_visitor super_t
Definition: to-expansion.hh:45
value_t & rmul_here(value_t &res, const expression_t &rhs) const
In place right multiplication by an expression.
value_t rmul(const value_t &lhs, const weight_t &w) const
Right-multiplication of lhs by w.
Definition: a-star.hh:8
expansionset_t es_
Manipulate the expansions.
value_t zero() const
The zero.
expansion_t to_expansion(const expression_t &e)
Facilitate recursion.
Definition: to-expansion.hh:84
std::ostream & decendl(std::ostream &o)
Decrement the indentation, print an end of line, and set the indentation.
Definition: indent.cc:59
polynomialset_t ps_
Manipulate the polynomials of expressions.
std::shared_ptr< const detail::expansion_base > expansion
Definition: expansion.hh:73
weightset_t ws_
Manipulate the weights.
value_t infiltration(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.
value_t one() const
The one.
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:55
typename expansionset_t::value_t expansion_t
Definition: to-expansion.hh:61
Indentation relative functions.
expression_t prod_(typename prod_t::iterator begin, typename prod_t::iterator end) const
Build a product for these expressions.
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
An inner node with multiple children.
Definition: expression.hh:118
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
The weight of a welement.
Definition: wet.hh:154
std::ostream & iendl(std::ostream &o)
Print an end of line, then set the indentation.
Definition: indent.cc:49
typename expansionset_t::polys_t polys_t
Definition: to-expansion.hh:60
context_t_of< expressionset_t > context_t
Definition: to-expansion.hh:48
#define BUILTIN_UNREACHABLE()
Definition: builtins.hh:13
bool transposed_
Whether to work transposed.
value_t & normalize(value_t &res) const
Normalize: move the constant term to the label one.
std::ostream & print(const value_t &v, std::ostream &o, format fmt={}) const
Print this expansion.
Request the unordered_map implementation.
auto rs
Definition: lift.hh:151
auto label_one() -> std::enable_if_t< LabelSet::has_one(), typename LabelSet::value_t >
This LabelSet's one(), if supported.
Definition: labelset.hh:45
static constexpr const char * me()
Definition: to-expansion.hh:58
expressionset_t rs_
Manipulate the expressions.
typename detail::context_t_of_impl< base_t< ValueSet >>::type context_t_of
Definition: traits.hh:53
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
to_expansion_visitor(const expressionset_t &rs)
Definition: to-expansion.hh:63
VCSN_RAT_VISIT(transposition, e)
An inner node implementing a weight.
Definition: expression.hh:264
expansion_t res_
The result.
Functor to compute the expansion of an expression.
Definition: to-expansion.hh:40
expansion_t operator()(const expression_t &v)
From an expression, build its expansion.
Definition: to-expansion.hh:68
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:42
std::shared_ptr< detail::expression_base > expression
Definition: expression.hh:92
expansion make_expansion(const ExpansionSet &ps, const typename ExpansionSet::value_t &expansion)
Definition: expansion.hh:78
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 l and r.
expression_polynomialset_t< ExpSet > make_expression_polynomialset(const ExpSet &rs)
From a ExpSet to its polynomialset.
Definition: split.hh:33
expansion to_expansion(const expression &exp)
Bridge.
value_t & lmul_here(const weight_t &w, value_t &res) const
Inplace left-multiplication by w of res.
value_t atom(const label_t &l) const
A single label.
rat::expansionset< ExpSet >::value_t to_expansion(const ExpSet &rs, const typename ExpSet::value_t &e)
First order expansion.
typename polynomialset_t::value_t polynomial_t
Definition: to-expansion.hh:56
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:12
typename expressionset_t::value_t expression_t
Definition: to-expansion.hh:50
value_t & ldiv_here(const weight_t &w, value_t &res) const
Inplace left-division by w of res.
zipped_maps< Dereference, Maps... > zip_maps(Maps &&...maps)
Definition: zip-maps.hh:250
std::map< label_t, polynomial_t, vcsn::less< labelset_t >> polys_t
Definition: expansionset.hh:39
std::ostream & print_(const expansion_t &v, std::ostream &o) const
Print an expansion.
weightset_t_of< expressionset_t > weightset_t
Definition: to-expansion.hh:51
expansion_t work_(const tuple_t &v, detail::index_sequence< I... >)