Vcsn  2.4
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& print_(const expansion_t& v, std::ostream& o) const
129  {
130  xs_.print(v, o);
131  if (transposed_)
132  o << " (transposed)";
133  return o;
134  }
135 
136  private:
138  {
139  res_ = xs_.zero();
140  }
141 
143  {
144  res_ = xs_.one();
145  }
146 
148  {
150  ? ls_.transpose(e.value())
151  : e.value());
152  }
153 
155  {
156  res_ = xs_.zero();
157  for (const auto& v: e)
159  }
160 
162  {
163  res_ = xs_.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  xs_.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  bool transposed = transposed_;
226  transposed_ = false;
227  expansion_t lhs = to_expansion(e[0]);
228  expansion_t rhs = to_expansion(e[1]);
229  res_ = xs_.ldivide(lhs, rhs);
230  if (transposed)
231  res_ = xs_.transpose(res_);
232  transposed_ = transposed;
233  }
234 
237  {
238  res_ = to_expansion(e.head());
239  for (const auto& r: e.tail())
241  }
242 
246  {
247  // The shuffle-product of the previously traversed siblings,
248  // to compute the "E:d(F)" part, E being all the previous lhs.
249  auto prev = e.head();
250  res_ = to_expansion(prev);
251  for (const auto& r: e.tail())
252  {
253  res_ = xs_.shuffle(res_,
254  transposed_ ? rs_.transposition(prev) : prev,
255  to_expansion(r),
256  transposed_ ? rs_.transposition(r) : r);
257  prev = rs_.shuffle(prev, r);
258  }
259  }
260 
264  {
265  // The infiltration-product of the previously traversed
266  // siblings, to compute the "E&:d(F)" part, E being all the
267  // previous lhs.
268  auto prev = e.head();
269  res_ = to_expansion(prev);
270  for (const auto& r: e.tail())
271  {
273  (res_,
274  transposed_ ? rs_.transposition(prev) : prev,
275  to_expansion(r),
276  transposed_ ? rs_.transposition(r) : r);
277  prev = rs_.infiltrate(prev, r);
278  }
279  }
280 
282  {
283  res_ = xs_.complement(to_expansion(e.sub()));
284  }
285 
288  {
290  e.sub()->accept(*this);
292  }
293 
295  {
296  expansion_t res = to_expansion(e.sub());
297  res_.constant = ws_.star(res.constant);
298  auto f = e.shared_from_this();
299  if (transposed_)
300  {
301  res_.constant = ws_.transpose(res_.constant);
302  f = rs_.transposition(f);
303  }
304 
305  for (const auto& p: res.polynomials)
306  res_.polynomials[label_of(p)]
307  = ps_.lweight(res_.constant,
308  ps_.rmul_label(weight_of(p), f));
309  }
310 
312  {
313  auto l = e.weight();
314  auto r = to_expansion(e.sub());
315  res_
316  = transposed_
317  ? xs_.rweight(r, ws_.transpose(l))
318  : xs_.lweight_here(l, r);
319  }
320 
322  {
323  auto l = to_expansion(e.sub());
324  auto r = e.weight();
325  res_
326  = transposed_
327  ? xs_.lweight_here(ws_.transpose(r), l)
328  : xs_.rweight(l, r);
329  }
330 
331  using tuple_t = typename super_t::tuple_t;
332 
333  template <bool = context_t::is_lat,
334  typename Dummy = void>
335  struct visit_tuple
336  {
337  template <size_t... I>
339  {
340  return
341  visitor_
342  .xs_
343  .tuple(vcsn::to_expansion(detail::project<I>(visitor_.rs_),
344  std::get<I>(v.sub()))...);
345  }
346 
347  expansion_t operator()(const tuple_t& v)
348  {
350  }
351  const self_t& visitor_;
352  };
353 
354  template <typename Dummy>
355  struct visit_tuple<false, Dummy>
356  {
357  expansion_t operator()(const tuple_t&)
358  {
360  }
361  const self_t& visitor_;
362  };
363 
364  void visit(const tuple_t& v, std::true_type) override
365  {
366  res_ = visit_tuple<>{*this}(v);
367  }
368 
369  // d(E@F) = d(E)@d(F).
371  {
372  compose(e, 0);
373  }
374 
375  template <typename Exp = expansion_t>
376  auto compose(const compose_t& e, int)
377  -> decltype(std::declval<expansionset_t>()
378  .compose(std::declval<Exp>(), std::declval<Exp>()),
379  void())
380  {
381  res_ = to_expansion(e.head());
382  for (const auto& r: e.tail())
384  }
385 
386  auto compose(const compose_t&, long)
387  -> void
388  {
389  require(false, "compose: context is not composable");
390  }
391 
392 
396  labelset_t ls_ = *rs_.labelset();
398  weightset_t ws_ = *rs_.weightset();
403 
405  bool transposed_ = false;
407  expansion_t res_;
408  };
409  } // rat::
410 
412  template <typename ExpSet>
414  to_expansion(const ExpSet& rs, const typename ExpSet::value_t& e)
415  {
417  return to_expansion(e);
418  }
419 
420  namespace dyn
421  {
422  namespace detail
423  {
425  template <typename ExpSet>
426  expansion
428  {
429  const auto& e = exp->as<ExpSet>();
430  const auto& rs = e.valueset();
432  return {es, to_expansion<ExpSet>(rs, e.value())};
433  }
434  }
435  }
436 } // vcsn::
rat::expansionset< ExpSet >::value_t to_expansion(const ExpSet &rs, const typename ExpSet::value_t &e)
First order expansion.
value_impl< detail::expansion_tag > expansion
Definition: fwd.hh:24
value_t conjunction(const value_t &l, const value_t &r) const
The conjunction of l and r.
auto tuple(Expansions &&...es) const -> value_t
The tuplization of single-tape expansions into a multitape expansion.
expansion_t to_expansion(const expression_t &e)
Facilitate recursion.
Definition: to-expansion.hh:90
weightset_t ws_
Manipulate the weights.
typename polynomialset_t::value_t polynomial_t
Definition: to-expansion.hh:55
value_t rweight(const value_t &lhs, const weight_t &w) const
Right-multiplication of lhs by w.
expression_polynomialset_t< ExpSet > make_expression_polynomialset(const ExpSet &rs)
From a ExpSet to its polynomialset.
Definition: split.hh:31
value_t ldivide(value_t lhs, value_t rhs) const
auto rs
Definition: lift.hh:152
return res
Definition: multiply.hh:398
std::ostream & print(const value_t &v, std::ostream &o, format fmt={}) const
Print this expansion.
typename expansionset_t::value_t expansion_t
Definition: to-expansion.hh:60
typename expressionset_t::value_t expression_t
Definition: to-expansion.hh:49
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:12
weightset_t_of< expressionset_t > weightset_t
Definition: to-expansion.hh:50
std::ostream & decendl(std::ostream &o)
Decrement the indentation, print an end of line, and set the indentation.
Definition: indent.cc:59
An inner node implementing a weight.
Definition: expression.hh:255
typename expansionset_t::polys_t polys_t
Definition: to-expansion.hh:59
auto compose(value_t l, value_t r) const -> std::enable_if_t< are_composable< Ctx, Ctx >
The composition of l and r.
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: functional.hh:57
expansion_t operator()(const tuple_t &v)
VCSN_RAT_VISIT(conjunction, e)
d(E&F) = d(E) & d(F).
value_t atom(const label_t &l) const
A single label.
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
The weight of a welement.
Definition: wet.hh:154
expression_t prod_(typename mul_t::iterator begin, typename mul_t::iterator end) const
Build a product for these expressions.
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.
auto compose(const compose_t &e, int) -> decltype(std::declval< expansionset_t >() .compose(std::declval< Exp >(), std::declval< Exp >()), void())
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
void require(Bool b, Args &&...args)
If b is not verified, raise an error with args as message.
Definition: raise.hh:91
expansionset_t xs_
Manipulate the expansions.
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
std::map< label_t, polynomial_t, vcsn::less< labelset_t >> polys_t
Definition: expansionset.hh:40
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:63
value_t & lweight_here(const weight_t &w, value_t &res) const
Inplace left-multiplication by w of res.
#define DEBUG_IF(Then)
Definition: to-expansion.hh:23
static constexpr const char * me()
Definition: to-expansion.hh:57
value_t complement(const value_t &v) const
The complement of v.
Definition: a-star.hh:8
polynomialset_t ps_
Manipulate the polynomials of expressions.
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
to_expansion_visitor(const expressionset_t &rs)
Definition: to-expansion.hh:62
VCSN_RAT_VISIT(transposition, e)
d(Eᵗ) = dᵗ(E)
context_t_of< expressionset_t > context_t
Definition: to-expansion.hh:47
std::ostream & iendl(std::ostream &o)
Print an end of line, then set the indentation.
Definition: indent.cc:49
value_t zero() const
The zero.
#define BUILTIN_UNREACHABLE()
Definition: builtins.hh:13
expansion_t work_(const tuple_t &v, detail::index_sequence< I... >)
value_t transpose(const value_t &v) const
Transpose an expansion. The firsts must be reduced to one.
bool transposed_
Whether to work transposed.
An inner node with multiple children.
Definition: expression.hh:118
return v
Definition: multiply.hh:361
value_t & rweight_here(value_t &res, const expression_t &rhs) const
In place right multiplication by an expression.
std::ostream & incendl(std::ostream &o)
Increment the indentation, print an end of line, and set the indentation.
Definition: indent.cc:54
auto & as()
Extract wrapped typed value.
Definition: value.hh:53
Indentation relative functions.
void add_here(value_t &lhs, const value_t &rhs) const
In place addition.
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:67
std::ostream & print_(const expansion_t &v, std::ostream &o) const
Print an expansion.
auto compose(const compose_t &, long) -> void
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.
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_impl< detail::expression_tag > expression
Definition: fwd.hh:25
void visit(const tuple_t &v, std::true_type) override
expressionset_t rs_
Manipulate the expressions.
typename detail::context_t_of_impl< base_t< ValueSet >>::type context_t_of
Definition: traits.hh:61
Request the unordered_map implementation.
auto label_of(const welement< Label, Weight > &m) -> decltype(m.label())
The label of a welement.
Definition: wet.hh:146
expansion_t res_
The result.
value_t one() const
The one.
std::string to_string(identities i)
Wrapper around operator<<.
Definition: identities.cc:42
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)
Functor to compute the expansion of an expression.
Definition: to-expansion.hh:39
expansion_t operator()(const expression_t &v)
From an expression, build its expansion.
Definition: to-expansion.hh:67
expansion to_expansion(const expression &exp)
Bridge.
typename expressionset_t::const_visitor super_t
Definition: to-expansion.hh:44