Vcsn  2.0
Be Rational
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
to-expansion.hh
Go to the documentation of this file.
1 #ifndef VCSN_ALGOS_TO_EXPANSION_HH
2 # define VCSN_ALGOS_TO_EXPANSION_HH
3 
4 # include <stack>
5 
9 # include <vcsn/core/rat/visitor.hh>
11 # include <vcsn/ctx/fwd.hh>
12 # include <vcsn/dyn/expansion.hh>
13 # include <vcsn/dyn/polynomial.hh>
14 # include <vcsn/dyn/ratexp.hh>
15 # include <vcsn/misc/indent.hh>
16 # include <vcsn/misc/raise.hh>
18 
19 //# define DEBUG 1
20 
21 #if DEBUG
22 # define DEBUG_IFELSE(Then, Else) Then
23 #else
24 # define DEBUG_IFELSE(Then, Else) Else
25 #endif
26 
27 # define DEBUG_IF(Then) DEBUG_IFELSE(Then,)
28 
29 namespace vcsn
30 {
31 
32  namespace rat
33  {
34 
35  /*------------------------.
36  | to_expansion_visitor. |
37  `------------------------*/
38 
39  template <typename RatExpSet>
41  : public RatExpSet::const_visitor
42  {
43  public:
44  using ratexpset_t = RatExpSet;
48  using ratexp_t = typename ratexpset_t::value_t;
50  using weight_t = typename weightset_t::value_t;
52 
55 
56  using super_t = typename ratexpset_t::const_visitor;
57 
58  constexpr static const char* me() { return "to_expansion"; }
59 
60  using polys_t = typename expansionset_t::polys_t;
61  using expansion_t = typename expansionset_t::value_t;
62 
64  : rs_(rs)
65  {}
66 
68  {
69  res_ = es_.zero();
70  v->accept(*this);
71  return res_;
72  }
73 
74 #if CACHE
75  std::unordered_map<ratexp_t, expansion_t,
78 #endif
79 
81  {
82 #if CACHE
83  auto insert = cache_.emplace(e, es_.zero());
84  auto& res = insert.first->second;
85  if (insert.second)
86  {
87  std::swap(res, res_);
88  DEBUG_IF(rs_.print(e, std::cerr) << "..." << incendl);
89  e->accept(*this);
90  std::swap(res, res_);
91  DEBUG_IF(
92  rs_.print(e, std::cerr) << " => ";
93  print_(res, std::cerr) << decendl;
94  );
95  }
96  else
97  {
98  DEBUG_IF(
99  rs_.print(e, std::cerr) << " -> ";
100  print_(res, std::cerr) << iendl;
101  );
102  }
103  return res;
104 #else
105  auto res = es_.zero();
106  std::swap(res, res_);
107  e->accept(*this);
108  std::swap(res, res_);
109  DEBUG_IF(
110  rs_.print(e, std::cerr) << " -> ";
111  print_(res, std::cerr) << iendl;
112  );
113  return res;
114 #endif
115  }
116 
118  {
119  operator()(e);
120  return es_.as_polynomial(res_);
121  }
122 
124  std::ostream& print_(const expansion_t& v, std::ostream& o) const
125  {
126  es_.print(v, o);
127  if (transposed_)
128  o << " (transposed)";
129  return o;
130  }
131 
132  private:
134  {
135  res_ = es_.zero();
136  }
137 
139  {
140  res_ = es_.one();
141  }
142 
144  {
146  ? ls_.transpose(e.value())
147  : e.value());
148  }
149 
151  {
152  res_ = es_.zero();
153  for (const auto& v: e)
155  }
156 
158  {
159  res_ = es_.one();
160  for (size_t i = 0, size = e.size(); i < size; ++i)
161  if (ws_.is_zero(res_.constant))
162  {
163  // Finish the product with all the remaining rhs and
164  // break. This optimization (as opposed to performing
165  // all the remaining iterations and repeatedly calling
166  // ps.mul) improves the score for
167  // derived-term([ab]*a[ab]{150}) from 0.32s to 0.23s on
168  // erebus, clang++ 3.4.
169  ratexp_t rhss
170  = transposed_
171  ? rs_.transposition(prod_(e.begin(),
172  std::next(e.begin(), size-i)))
173  : prod_(std::next(e.begin(), i), std::end(e));
174  es_.rmul_here(res_, rhss);
175  break;
176  }
177  else
178  {
179  auto r = e[transposed_ ? size-1 - i : i];
180  expansion_t rhs = to_expansion(r);
181  if (transposed_)
182  r = rs_.transposition(r);
183 
184  es_.rmul_here(res_, r);
185 
186  for (const auto& p: rhs.polynomials)
187  ps_.add_here(res_.polynomials[p.first],
188  ps_.lmul(res_.constant, p.second));
189  res_.constant = ws_.mul(res_.constant, rhs.constant);
190  }
191  }
192 
195  ratexp_t
196  prod_(typename prod_t::iterator begin,
197  typename prod_t::iterator end) const
198  {
199  using ratexps_t = typename prod_t::values_t;
200  if (begin == end)
201  return rs_.one();
202  else if (std::next(begin, 1) == end)
203  return *begin;
204  else
205  return std::make_shared<prod_t>(ratexps_t{begin, end});
206  }
207 
208  label_t one_(std::true_type)
209  {
210  return rs_.labelset()->one();
211  }
212 
213  label_t one_(std::false_type)
214  {
215  raise(me(), ": quotient requires a labelset with a neutral");
216  }
217 
224  {
225  if (auto c = std::dynamic_pointer_cast<const transposition_t>(r))
226  {
227  if (auto s = std::dynamic_pointer_cast<const star_t>(c->sub()))
228  return rs_.transposition(s->sub());
229  }
230  else if (auto s = std::dynamic_pointer_cast<const star_t>(r))
231  return s->sub();
232  return nullptr;
233  }
234 
236  {
237  assert(e.size() == 2);
238  DEBUG_IF(
239  std::cerr << "Start: ";
240  rs_.print(e.shared_from_this, std::cerr()) << " =>\n";
241  );
242 
243  bool transposed = transposed_;
244  transposed_ = false;
245  expansion_t lhs = to_expansion(e[0]);
246  expansion_t rhs = to_expansion(e[1]);
247  transposed_ = transposed;
248  DEBUG_IF(
249  std::cerr << "Lhs: "; print_(lhs, std::cerr) << '\n';
250  std::cerr << "Rhs: "; print_(rhs, std::cerr) << '\n';
251  );
252  res_ = es_.zero();
253  // lp: (label, left_polynomial)
254  if (!ws_.is_zero(lhs.constant))
255  {
256  if (transposed_)
257  {
258  auto rhs_transposed = to_expansion(e[1]);
259  es_.add_here(res_,
260  es_.ldiv_here(lhs.constant, rhs_transposed));
261  }
262  else
263  es_.add_here(res_, es_.ldiv_here(lhs.constant, rhs));
264  }
265  auto one = one_(std::integral_constant<bool, context_t::has_one()>());
266  for (const auto& p: zip_maps(lhs.polynomials, rhs.polynomials))
267  for (const auto& lm: std::get<0>(p.second))
268  for (const auto& rm: std::get<1>(p.second))
269  // Now, recursively develop the quotient of monomials,
270  // directly in res_.
271  if (transposed_)
272  ps_.add_here(res_.polynomials[one],
273  rs_.transposition(rs_.ldiv(lm.first, rm.first)),
274  ws_.transpose(ws_.ldiv(lm.second, rm.second)));
275  else
276  ps_.add_here(res_.polynomials[one],
277  rs_.ldiv(lm.first, rm.first),
278  ws_.ldiv(lm.second, rm.second));
279  es_.normalize(res_);
280  }
281 
283  {
284  res_ = to_expansion(e.head());
285  for (const auto& r: e.tail())
287  }
288 
289  // FO(E:F) = FO(E):F + E:FO(F)
291  {
292  expansion_t res = es_.one();
293  // The shuffle-product of the previously traversed siblings.
294  // Initially the neutral element: \e.
295  ratexp_t prev = rs_.one();
296  for (const auto& rhs: e)
297  {
298  // Save current result in lhs, and compute the result in res.
299  expansion_t lhs; lhs.constant = ws_.zero();
300  std::swap(res, lhs);
301 
302  expansion_t r = to_expansion(rhs);
303  res.constant = ws_.mul(lhs.constant, r.constant);
304 
305  // (i) fo(lhs) -> fo(lhs):r, that is, shuffle-multiply the
306  // current result by the current child (rhs).
307  for (const auto& p: lhs.polynomials)
308  for (const auto& m: p.second)
309  res.polynomials[p.first].emplace(rs_.shuffle(m.first, rhs),
310  m.second);
311  // (ii) prev:fo(rhs)
312  for (const auto& p: r.polynomials)
313  for (const auto& m: p.second)
314  ps_.add_here(res.polynomials[p.first],
315  rs_.shuffle(prev, m.first), m.second);
316 
317  prev = rs_.shuffle(prev, rhs);
318  }
319  res_ = res;
320  }
321 
323  {
324  // Complement requires a free labelset.
325  visit_complement<context_t::labelset_t::is_free()>(e);
326  }
327 
329  template <bool IsFree>
330  typename std::enable_if<!IsFree, void>::type
331  visit_complement(const complement_t&)
332  {
333  raise(me(), ": cannot handle complement without generators");
334  }
335 
337  template <bool IsFree>
338  typename std::enable_if<IsFree, void>::type
339  visit_complement(const complement_t& e)
340  {
341  expansion_t res = to_expansion(e.sub());
342  res_.constant = ws_.is_zero(res.constant) ? ws_.one() : ws_.zero();
343 
344  // Turn the polynomials into a ratexp, and complement it.
345  for (auto l: rs_.labelset()->genset())
346  ps_.add_here
347  (res_.polynomials[l],
348  polynomial_t{{rs_.complement(es_.as_ratexp(res.polynomials[l])),
349  ws_.one()}});
350  }
351 
352 
354  {
355  transposed_ = !transposed_;
356  e.sub()->accept(*this);
357  transposed_ = !transposed_;
358  }
359 
361  {
362  expansion_t res = to_expansion(e.sub());
363  res_.constant = ws_.star(res.constant);
364  auto f = e.shared_from_this();
365  if (transposed_)
366  {
367  res_.constant = ws_.transpose(res_.constant);
368  f = rs_.transposition(f);
369  }
370 
371  for (const auto& p: res.polynomials)
372  res_.polynomials[p.first]
373  = ps_.lmul(res_.constant,
374  ps_.rmul(p.second, f));
375  }
376 
378  {
379  auto l = e.weight();
380  auto r = to_expansion(e.sub());
381  res_
382  = transposed_
383  ? es_.rmul(r, ws_.transpose(l))
384  : es_.lmul_here(l, r);
385  }
386 
388  {
389  auto l = to_expansion(e.sub());
390  auto r = e.weight();
391  res_
392  = transposed_
393  ? es_.lmul_here(ws_.transpose(r), l)
394  : es_.rmul(l, r);
395  }
396 
400  labelset_t ls_ = *rs_.labelset();
402  weightset_t ws_ = *rs_.weightset();
407 
409  bool transposed_ = false;
412  };
413 
414  } // rat::
415 
417  template <typename RatExpSet>
418  inline
420  to_expansion(const RatExpSet& rs, const typename RatExpSet::value_t& e)
421  {
423  return to_expansion.to_expansion(e);
424  }
425 
426  namespace dyn
427  {
428  namespace detail
429  {
431  template <typename RatExpSet>
432  expansion
433  to_expansion(const ratexp& exp)
434  {
435  const auto& e = exp->as<RatExpSet>();
436  const auto& rs = e.ratexpset();
438  return make_expansion(es,
439  to_expansion<RatExpSet>(rs, e.ratexp()));
440  }
441 
443  (const ratexp& e) -> expansion);
444  }
445  }
446 } // vcsn::
447 
448 #endif // !VCSN_ALGOS_TO_EXPANSION_HH
Linear combination of labels: map labels to weights.
Definition: fwd.hh:32
value_t & add_here(value_t &v, const value_t &p) const
v += p.
An inner node with multiple children.
Definition: fwd.hh:123
std::ostream & iendl(std::ostream &o)
Print an end of line, then set the indentation.
Definition: indent.cc:49
expansion make_expansion(const ExpansionSet &ps, const typename ExpansionSet::value_t &expansion)
Definition: expansion.hh:79
typename ratexpset_t::value_t ratexp_t
Definition: to-expansion.hh:48
context_t_of< ratexpset_t > context_t
Definition: to-expansion.hh:45
expansion_t operator()(const ratexp_t &v)
Definition: to-expansion.hh:67
value_t & rmul_here(value_t &res, const ratexp_t &rhs) const
In place right multiplication by a ratexp.
ratexp_polynomialset_t< RatExpSet > make_ratexp_polynomialset(const RatExpSet &rs)
From a RatExpSet to its polynomialset.
Definition: split.hh:34
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
Definition: traits.hh:34
Indentation relative functions.
ratexpset_t rs_
Manipulate the ratexps.
label_t one_(std::false_type)
ratexp_t prod_(typename prod_t::iterator begin, typename prod_t::iterator end) const
Build a product for these expressions.
std::ostream & incendl(std::ostream &o)
Increment the indentation, print an end of line, and set the indentation.
Definition: indent.cc:54
rat::expansionset< RatExpSet >::value_t to_expansion(const RatExpSet &rs, const typename RatExpSet::value_t &e)
First order expansion.
typename expansionset_t::polys_t polys_t
Definition: to-expansion.hh:60
value_t conjunction(value_t l, value_t r) const
The conjunction of l and r.
weightset_t_of< ratexpset_t > weightset_t
Definition: to-expansion.hh:49
std::shared_ptr< detail::ratexp_base > ratexp
Definition: fwd.hh:64
value_t lmul(const weight_t &w, const value_t &v) const
Left exterior product.
value_t & normalize(value_t &res) const
#define DEBUG_IF(Then)
Definition: to-expansion.hh:27
typename detail::context_t_of_impl< base_t< ValueSet >>::type context_t_of
Definition: traits.hh:32
static constexpr const char * me()
Definition: to-expansion.hh:58
void add_here(value_t &lhs, const value_t &rhs) const
In place addition.
#define REGISTER_DECLARE(Name, Signature)
Definition: fwd.hh:104
VCSN_RAT_VISIT(transposition, e)
to_expansion_visitor(const ratexpset_t &rs)
Definition: to-expansion.hh:63
value_t & ldiv_here(const weight_t &w, value_t &res) const
Inplace left-division by w of res.
std::shared_ptr< const detail::expansion_base > expansion
Definition: expansion.hh:74
typename detail::label_t_of_impl< base_t< ValueSet >>::type label_t_of
Definition: traits.hh:33
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:38
polynomialset_t ps_
Manipulate the polynomials of ratexps.
std::ostream & decendl(std::ostream &o)
Decrement the indentation, print an end of line, and set the indentation.
Definition: indent.cc:59
std::enable_if< IsFree, void >::type visit_complement(const complement_t &e)
Complement on a free labelset.
polynomial_t to_expansion_as_polynomial(const ratexp_t &e)
std::map< label_t, polynomial_t, vcsn::less< labelset_t >> polys_t
Definition: expansionset.hh:38
labelset_t ls_
Manipulate the labels.
std::ostream & print_(const expansion_t &v, std::ostream &o) const
Print an expansion.
typename ratexpset_t::const_visitor super_t
Definition: to-expansion.hh:56
typename expansionset_t::value_t expansion_t
Definition: to-expansion.hh:61
value_t atom(const label_t &l) const
A single label.
labelset_t_of< context_t > labelset_t
Definition: to-expansion.hh:46
expansion to_expansion(const ratexp &exp)
Bridge.
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:36
polynomial_t as_polynomial(const value_t &v) const
Convert an expansion to a polynomial.
An inner node implementing a weight.
Definition: fwd.hh:145
std::map< label_t, weight_t, vcsn::less< labelset_t >> value_t
std::enable_if<!IsFree, void >::type visit_complement(const complement_t &)
Cannot complement on a non-free labelset.
bool transposed_
Whether to work transposed.
expansionset_t es_
Manipulate the expansions.
typename weightset_t::value_t weight_t
Definition: to-expansion.hh:50
value_t zero() const
The zero.
zipped_maps< Dereference, Maps...> zip_maps(Maps &&...maps)
Definition: zip-maps.hh:257
ratexp_t star_child(const ratexp_t r)
If r is e*, return e.
label_t_of< context_t > label_t
Definition: to-expansion.hh:47
value_t one() const
The one.
std::ostream & print(const value_t &v, std::ostream &o, symbol format=symbol{"text"}) const
Print a first order development.
Definition: expansionset.hh:64
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: hash.hh:42
typename polynomialset_t::value_t polynomial_t
Definition: to-expansion.hh:54
expansion_t to_expansion(const ratexp_t &e)
Definition: to-expansion.hh:80
label_t one_(std::true_type)
expansion_t res_
The result.
weightset_t ws_
Manipulate the weights.
This is useful to make hashes with labels or weights as keys without using non-default constructors; ...
Definition: hash.hh:26