Vcsn  2.8
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_ = xs_.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, xs_.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 = xs_.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&
129  print_(const expansion_t& v, std::ostream& o = std::cerr) const
130  {
131  xs_.print(v, o);
132  if (transposed_)
133  o << " (transposed)";
134  return o;
135  }
136 
138  expression_t me(expression_t res) const
139  {
140  while (true)
141  {
142  auto i = names_.find(res);
143  if (i == end(names_))
144  break;
145  else
146  res = i->second;
147  }
148  return res;
149  }
150 
151 
156  {
157  // Record that e.sub has a name.
158  auto i = names_.emplace(e.sub(), e.shared_from_this()).first;
159  super_t::visit(e);
160  names_.erase(i);
161  }
162 
164  {
165  res_ = xs_.zero();
166  }
167 
169  {
170  res_ = xs_.one();
171  }
172 
174  {
176  ? ls_.transpose(e.value())
177  : e.value());
178  }
179 
181  {
182  res_ = xs_.zero();
183  for (const auto& v: e)
185  }
186 
188  {
189  if (getenv("VCSN_NAIVE_MUL"))
190  {
191  assert(!transposed_);
192  res_ = to_expansion(e[0]);
195  prod_(std::next(e.begin()), std::end(e)));
196  }
197  else
198  {
199  res_ = xs_.one();
200  for (size_t i = 0, size = e.size(); i < size; ++i)
201  {
202  auto r = e[transposed_ ? size-1 - i : i];
203  auto rhs = to_expansion(r);
204  if (transposed_)
205  r = rs_.transposition(r);
206 
207  // Instead of performing successive binary
208  // multiplications, we immediately multiply the current
209  // expansion by all the remaining operands on its right
210  // hand side. This also allows to break the iterations as
211  // soon as an expansion has a null constant term.
212  //
213  // In essence, it allows to treat the product as if it
214  // were right-associative: in `E.(FG)`, if `c(E) != 0`, we
215  // don't need to traverse `FG`, just append it to
216  // `d_p(E)`.
217  //
218  // Also, using prod_ saves from a useless application of
219  // the identities with repeated multiplications, which
220  // have already been applied. Large performance impact.
221  //
222  // The gain is very effective.
223  //
224  // Do it only if there is really something left though, so
225  // that we don't need any particular identity.
226  if (i + 1 < size)
227  {
228  expression_t rhss
229  = transposed_
230  ? rs_.transposition(prod_(e.begin(),
231  std::next(e.begin(), size-(i+1))))
232  : prod_(std::next(e.begin(), i + 1), std::end(e));
233  // rmul_label_here requires a null constant term,
234  // please it.
235  auto w = std::move(rhs.constant);
236  rhs.constant = ws_.zero();
237  xs_.rmul_label_here(rhs, rhss);
238  rhs.constant = std::move(w);
239  }
240 
241  for (const auto& p: rhs.polynomials)
242  ps_.add_here(res_.polynomials[p.first],
243  ps_.lweight(res_.constant, p.second));
244  res_.constant = ws_.mul(res_.constant, rhs.constant);
245  // Nothing else will be added.
246  if (ws_.is_zero(res_.constant))
247  break;
248  }
249  }
250  }
251 
256  expression_t
257  prod_(typename mul_t::iterator begin,
258  typename mul_t::iterator end) const
259  {
260  using expressions_t = typename mul_t::values_t;
261  assert(begin != end);
262  if (std::next(begin, 1) == end)
263  return *begin;
264  else
265  return std::make_shared<mul_t>(expressions_t{begin, end});
266  }
267 
269  {
270  assert(e.size() == 2);
271  bool transposed = transposed_;
272  transposed_ = false;
273  auto lhs = to_expansion(e[0]);
274  auto rhs = to_expansion(e[1]);
275  res_ = xs_.ldivide(lhs, rhs);
276  if (transposed)
277  res_ = xs_.transpose(res_);
278  transposed_ = transposed;
279  }
280 
283  {
284  res_ = to_expansion(e.head());
285  for (const auto& r: e.tail())
287  }
288 
292  {
293  // The shuffle-product of the previously traversed siblings,
294  // to compute the "E:d(F)" part, E being all the previous lhs.
295  auto prev = e.head();
296  res_ = to_expansion(prev);
297  for (const auto& r: e.tail())
298  {
299  res_ = xs_.shuffle(res_,
300  transposed_ ? rs_.transposition(prev) : prev,
301  to_expansion(r),
302  transposed_ ? rs_.transposition(r) : r);
303  prev = rs_.shuffle(prev, r);
304  }
305  }
306 
310  {
311  // The infiltration-product of the previously traversed
312  // siblings, to compute the "E&:d(F)" part, E being all the
313  // previous lhs.
314  auto prev = e.head();
315  res_ = to_expansion(prev);
316  for (const auto& r: e.tail())
317  {
319  (res_,
320  transposed_ ? rs_.transposition(prev) : prev,
321  to_expansion(r),
322  transposed_ ? rs_.transposition(r) : r);
323  prev = rs_.infiltrate(prev, r);
324  }
325  }
326 
328  {
329  res_ = xs_.complement(to_expansion(e.sub()));
330  }
331 
334  {
336  e.sub()->accept(*this);
338  }
339 
343  {
344  // F = E*.
345  auto f = me(e.shared_from_this());
346  // d(E).
347  auto x = to_expansion(e.sub());
348  if (xs_.is_normal(x) && !getenv("VCSN_NAIVE_STAR"))
349  res_.constant = ws_.star(x.constant);
350  else
351  {
352  // Do not leave any constant-term.
353  xs_.denormalize(x);
354  res_.constant = ws_.one();
355  }
356  if (transposed_)
357  {
358  // FIXME: check the case of named expression.
359  res_.constant = ws_.transpose(res_.constant);
360  f = rs_.transposition(f);
361  }
362 
363  for (const auto& p: x.polynomials)
364  res_.polynomials[label_of(p)]
365  = ps_.lweight(res_.constant,
366  ps_.rmul_label(weight_of(p), f));
367  if (getenv("VCSN_DENORMALIZE_STAR"))
369  }
370 
372  {
373  auto l = e.weight();
374  auto r = to_expansion(e.sub());
375  res_
376  = transposed_
377  ? xs_.rweight(r, ws_.transpose(l))
378  : xs_.lweight_here(l, r);
379  }
380 
382  {
383  auto l = to_expansion(e.sub());
384  auto r = e.weight();
385  res_
386  = transposed_
387  ? xs_.lweight_here(ws_.transpose(r), l)
388  : xs_.rweight(l, r);
389  }
390 
391  using tuple_t = typename super_t::tuple_t;
392 
393  template <bool = context_t::is_lat,
394  typename Dummy = void>
395  struct visit_tuple
396  {
397  template <size_t... I>
399  {
400  return
401  visitor_
402  .xs_
403  .tuple(vcsn::to_expansion(detail::project<I>(visitor_.rs_),
404  std::get<I>(v.sub()))...);
405  }
406 
407  expansion_t operator()(const tuple_t& v)
408  {
410  }
411  const self_t& visitor_;
412  };
413 
414  template <typename Dummy>
415  struct visit_tuple<false, Dummy>
416  {
417  expansion_t operator()(const tuple_t&)
418  {
420  }
421  const self_t& visitor_;
422  };
423 
424  void visit(const tuple_t& v, std::true_type) override
425  {
426  res_ = visit_tuple<>{*this}(v);
427  }
428 
429  // d(E@F) = d(E)@d(F).
431  {
432  compose(e, 0);
433  }
434 
435  template <typename Exp = expansion_t>
436  auto compose(const compose_t& e, int)
437  -> decltype(std::declval<expansionset_t>()
438  .compose(std::declval<Exp>(), std::declval<Exp>()),
439  void())
440  {
441  res_ = to_expansion(e.head());
442  for (const auto& r: e.tail())
444  }
445 
446  auto compose(const compose_t&, long)
447  -> void
448  {
449  require(false, "compose: context is not composable");
450  }
451 
452 
456  labelset_t ls_ = *rs_.labelset();
458  weightset_t ws_ = *rs_.weightset();
463 
465  bool transposed_ = false;
467  expansion_t res_ = xs_.zero();
469  std::map<expression_t, expression_t> names_;
470  };
471  } // rat::
472 
474  template <typename ExpSet>
476  to_expansion(const ExpSet& rs, const typename ExpSet::value_t& e)
477  {
479  return to_expansion(e);
480  }
481 
482  namespace dyn
483  {
484  namespace detail
485  {
487  template <typename ExpSet>
488  expansion
490  {
491  const auto& e = exp->as<ExpSet>();
492  const auto& rs = e.valueset();
493  auto es = vcsn::rat::expansionset<ExpSet>(rs);
494  return {es, to_expansion<ExpSet>(rs, e.value())};
495  }
496  }
497  }
498 } // vcsn::
std::ostream & iendl(std::ostream &o)
Print an end of line, then set the indentation.
Definition: indent.cc:49
value_impl< detail::expansion_tag > expansion
Definition: fwd.hh:30
value_t & denormalize(value_t &res) const
Move the constant to the polynomial associated to one.
VCSN_RAT_VISIT(transposition, e)
d(Eᵗ) = dᵗ(E)
typename expressionset_t::value_t expression_t
Definition: to-expansion.hh:49
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
Definition: traits.hh:67
typename expansionset_t::polys_t polys_t
Definition: to-expansion.hh:59
auto compose(const compose_t &e, int) -> decltype(std::declval< expansionset_t >() .compose(std::declval< Exp >(), std::declval< Exp >()), void())
value_t complement(const value_t &v) const
The complement of v.
std::map< expression_t, expression_t > names_
A table from the expression to the naming expression.
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
#define DEBUG_IF(Then)
Definition: to-expansion.hh:23
typename expressionset_t::const_visitor super_t
Definition: to-expansion.hh:44
auto tuple(Expansions &&... es) const -> value_t
The tuplization of single-tape expansions into a multitape expansion.
An inner node with multiple children.
Definition: expression.hh:119
value_t & rmul_label_here(value_t &res, const expression_t &rhs) const
In place right multiplication by an expression.
std::map< label_t, polynomial_t, vcsn::less< labelset_t > > polys_t
Definition: expansionset.hh:42
VCSN_RAT_VISIT(shuffle, e)
d(E:F) = d(E):F + E:d(F) dᵗ(E:F) = dᵗ(E):Fᵗ + Eᵗ:dᵗ(F)
static constexpr const char * me()
Definition: to-expansion.hh:57
bool transposed_
Whether to work transposed.
typename expansionset_t::value_t expansion_t
Definition: to-expansion.hh:60
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) ...
value_t conjunction(const value_t &l, const value_t &r) const
The conjunction of l and r.
VCSN_RAT_VISIT(name, e)
When we find that an expression is named, record named -> naming, so that when we need named...
value_t rweight(const value_t &lhs, const weight_t &w) const
Right-multiplication of lhs by w.
auto compose(const compose_t &, long) -> void
An inner node to name the subexpression.
Definition: expression.hh:290
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:72
typename detail::context_t_of_impl< base_t< ValueSet > >::type context_t_of
Definition: traits.hh:61
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
Definition: traits.hh:63
expression_t me(expression_t res) const
Find if an expression is named.
value_t & lweight_here(const weight_t &w, value_t &res) const
Inplace left-multiplication by w of res.
value_t one() const
The one.
Definition: a-star.hh:8
std::ostream & incendl(std::ostream &o)
Increment the indentation, print an end of line, and set the indentation.
Definition: indent.cc:54
std::ostream & print(const value_t &v, std::ostream &o=std::cout, format fmt={}) const
Print this expansion.
to_expansion_visitor(const expressionset_t &rs)
Definition: to-expansion.hh:62
std::ostream & decendl(std::ostream &o)
Decrement the indentation, print an end of line, and set the indentation.
Definition: indent.cc:59
VCSN_RAT_VISIT(star, e)
If E is normal, d(E*) = <c(E)*> + <c(E)*> dp(E) E*.
expansion_t res_
The result.
std::string to_string(identities i)
Wrapper around operator<<.
Definition: identities.cc:38
expression_t prod_(typename mul_t::iterator begin, typename mul_t::iterator end) const
Build a product for these expressions.
An inner node implementing a weight.
Definition: expression.hh:256
A static list of size_t.
Definition: tuple.hh:32
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:27
weightset_t ws_
Manipulate the weights.
value_t zero() const
The zero.
void visit(const tuple_t &v, std::true_type) override
VCSN_RAT_VISIT(conjunction, e)
d(E&F) = d(E) & d(F).
void swap(config::value &first, config::value &second)
expansion_t operator()(const tuple_t &v)
typename polynomialset_t::value_t polynomial_t
Definition: to-expansion.hh:55
weightset_t_of< expressionset_t > weightset_t
Definition: to-expansion.hh:50
expansion_t to_expansion(const expression_t &e)
Facilitate recursion.
Definition: to-expansion.hh:90
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
The weight of a welement.
Definition: wet.hh:154
return v
Definition: multiply.hh:362
auto label_of(const welement< Label, Weight > &m) -> decltype(m.label())
The label of a welement.
Definition: wet.hh:146
value_t ldivide(value_t lhs, value_t rhs) const
polynomialset_t ps_
Manipulate the polynomials of expressions.
rat::expansionset< ExpSet >::value_t to_expansion(const ExpSet &rs, const typename ExpSet::value_t &e)
First order expansion.
expansionset_t xs_
Manipulate the expansions.
value_impl< detail::expression_tag > expression
Definition: fwd.hh:31
Functor to compute the expansion of an expression.
Definition: to-expansion.hh:39
expression_polynomialset_t< ExpSet > make_expression_polynomialset(const ExpSet &rs)
From a ExpSet to its polynomialset.
Definition: split.hh:31
value_t shuffle(const value_t &de, const expression_t &e, const value_t &df, const expression_t &f) const
The shuffle product of de and df.
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:87
Request the unordered_map implementation.
value_t transpose(const value_t &v) const
Transpose an expansion. The firsts must be reduced to one.
value_t infiltrate(const value_t &de, const expression_t &e, const value_t &df, const expression_t &f) const
The infiltration product of l and r.
context_t_of< expressionset_t > context_t
Definition: to-expansion.hh:47
auto compose(value_t l, value_t r) const -> std::enable_if_t< are_composable< Ctx, Ctx >() &&number_of_tapes< Ctx >::value==2, value_t >
The composition of l and r.
expansion_t operator()(const expression_t &v)
From an expression, build its expansion.
Definition: to-expansion.hh:67
labelset_t ls_
Manipulate the labels.
bool is_normal(const value_t &x) const
Whether an expansion is normal.
std::ostream & print_(const expansion_t &v, std::ostream &o=std::cerr) const
Print an expansion.
Indentation relative functions.
#define BUILTIN_UNREACHABLE()
Definition: builtins.hh:13
return res
Definition: multiply.hh:399
expansion_t work_(const tuple_t &v, detail::index_sequence< I... >)
value_t atom(const label_t &l) const
A single label.
void add_here(value_t &lhs, const value_t &rhs) const
In place addition.
expressionset_t rs_
Manipulate the expressions.