Vcsn  2.1
Be Rational
expansionset.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <vcsn/algos/split.hh> // expression_polynomialset_t.
4 #include <vcsn/misc/map.hh>
5 
6 namespace vcsn
7 {
8 
9  namespace rat
10  {
11 
12  /*---------------.
13  | expansionset. |
14  `---------------*/
15 
16  template <typename ExpSet>
17  struct expansionset
18  {
19  public:
20  using expressionset_t = ExpSet;
24  using expression_t = typename expressionset_t::value_t;
26  using weight_t = typename weightset_t::value_t;
27 
30  using monomial_t = typename polynomialset_t::monomial_t;
31 
32  constexpr static const char* me() { return "expansion"; }
33 
34  // Keep it sorted to ensure determinism, and better looking
35  // results. Anyway, rough benches show no difference between
36  // map and unordered_map here.
37  using polys_t = std::map<label_t, polynomial_t, vcsn::less<labelset_t>>;
38 
40  struct value_t
41  {
44  };
45 
47  : rs_(rs)
48  {}
49 
51  static symbol sname()
52  {
53  static symbol res("expansionset<" + expressionset_t::sname() + '>');
54  return res;
55  }
56 
59  {
60  return rs_;
61  }
62 
64  std::ostream& print_set(std::ostream& o, format fmt = {}) const
65  {
66  o << "expansionset<";
67  rs_.print_set(o, fmt);
68  return o << '>';
69  }
70 
72  std::ostream& print(const value_t& v, std::ostream& o,
73  format fmt = {}) const
74  {
75  bool first = true;
76  if (!ws_.is_zero(v.constant) || v.polynomials.empty())
77  {
78  o << (fmt == format::latex ? "\\left\\langle " : "<");
79  ws_.print(v.constant, o, fmt.for_weights());
80  o << (fmt == format::latex ? "\\right\\rangle " : ">");
81  first = false;
82  }
83  for (const auto& p: v.polynomials)
84  {
85  if (!first)
86  o << (fmt == format::latex ? " \\oplus " : " + ");
87  first = false;
88  ls_.print(p.first, o, fmt.for_labels());
89  o << (fmt == format::latex ? " \\odot \\left[" : ".[");;
90  ps_.print(p.second, o, fmt);
91  o << (fmt == format::latex ? "\\right]" : "]");;
92  }
93  return o;
94  }
95 
97  value_t& normalize(value_t& res) const
98  {
99  auto has_one = bool_constant<context_t::has_one()>();
100  return normalize_(res, has_one);
101  }
102 
106  value_t& normalize_(value_t& res, std::true_type) const
107  {
108  auto one = ls_.one();
109  auto i = res.polynomials.find(one);
110  if (i != std::end(res.polynomials))
111  {
112  auto j = i->second.find(rs_.one());
113  if (j != std::end(i->second))
114  {
115  res.constant = ws_.add(res.constant, weight_of(*j));
116  i->second.erase(j);
117  if (i->second.empty())
118  res.polynomials.erase(i);
119  }
120  }
121  return res;
122  }
123 
125  value_t& normalize_(value_t& res, std::false_type) const
126  {
127  return res;
128  }
129 
131  value_t& denormalize(value_t& res) const
132  {
133  auto has_one = bool_constant<context_t::has_one()>();
134  return denormalize_(res, has_one);
135  }
136 
139  value_t& denormalize_(value_t& res, std::true_type) const
140  {
141  if (!ws_.is_zero(res.constant))
142  {
143  auto one = ls_.one();
144  ps_.add_here(res.polynomials[one],
145  polynomial_t{{rs_.one(), res.constant}});
146  res.constant = ws_.zero();
147  }
148  return res;
149  }
150 
152  value_t& denormalize_(value_t& res, std::false_type) const
153  {
154  return res;
155  }
156 
158  value_t zero() const
159  {
160  return {ws_.zero(), polys_t{}};
161  }
162 
164  value_t one() const
165  {
166  return {ws_.one(), polys_t{}};
167  }
168 
170  value_t atom(const label_t& l) const
171  {
172  return {ws_.zero(), {{l, ps_.one()}}};
173  }
174 
176  void add_here(value_t& lhs, const value_t& rhs) const
177  {
178  lhs.constant = ws_.add(lhs.constant, rhs.constant);
179  for (const auto& p: rhs.polynomials)
180  ps_.add_here(lhs.polynomials[p.first], p.second);
181  }
182 
184  value_t& lmul_here(const weight_t& w, value_t& res) const
185  {
186  res.constant = ws_.mul(w, res.constant);
187  for (auto& p: res.polynomials)
188  p.second = ps_.lmul(w, p.second);
189  return res;
190  }
191 
193  value_t rmul(const value_t& lhs, const weight_t& w) const
194  {
195  value_t res = {ws_.mul(lhs.constant, w), polys_t{}};
196  for (auto& p: lhs.polynomials)
197  for (const auto& m: p.second)
198  ps_.add_here(res.polynomials[p.first],
199  rs_.rmul(label_of(m), w), weight_of(m));
200  return res;
201  }
202 
204  value_t& rmul_here(value_t& res, const expression_t& rhs) const
205  {
206  for (auto& p: res.polynomials)
207  p.second = ps_.rmul_label(p.second, rhs);
208  return res;
209  }
210 
212  value_t& ldiv_here(const weight_t& w, value_t& res) const
213  {
214  res.constant = ws_.ldiv(w, res.constant);
215  for (auto& p: res.polynomials)
216  for (auto&& m: p.second)
217  weight_set(m, ws_.ldiv(w, weight_of(m)));
218  return normalize(res);
219  }
220 
221  private:
222  template <typename Conjunction>
223  void
224  conjunctions_with_one_(value_t&,
225  const value_t&, const value_t&,
226  std::false_type,
227  Conjunction) const
228  {}
229 
230  template <typename Conjunction>
231  void
232  conjunctions_with_one_(value_t& res,
233  const value_t& l, const value_t& r,
234  std::true_type,
235  Conjunction conjunction) const
236  {
237  // Spontaneous transitions from the lhs.
238  auto one = ls_.one();
239  {
240  auto i = l.polynomials.find(one);
241  if (i != std::end(l.polynomials))
242  for (const auto& rhs: r.polynomials)
243  if (!ls_.is_one(rhs.first))
244  ps_.add_here(res.polynomials[one],
245  conjunction(i->second,
246  ps_.lmul_label(rs_.atom(rhs.first),
247  rhs.second)));
248  }
249  // Spontaneous transitions from the rhs.
250  {
251  auto i = r.polynomials.find(one);
252  if (i != std::end(r.polynomials))
253  for (const auto& lhs: l.polynomials)
254  if (!ls_.is_one(lhs.first))
255  ps_.add_here(res.polynomials[one],
256  conjunction(ps_.lmul_label(rs_.atom(lhs.first),
257  lhs.second),
258  i->second));
259  }
260  }
261 
265  template <typename LabelSet = labelset_t, typename Conjunction>
266  auto conjunction_(value_t l, value_t r,
267  Conjunction conjunction) const
268  -> enable_if_t<detail::is_letterized_t<LabelSet>{},
269  value_t>
270  {
271  value_t res = zero();
272  denormalize(l);
273  denormalize(r);
274  res.constant = ws_.mul(l.constant, r.constant);
275  for (const auto& p: zip_maps(l.polynomials, r.polynomials))
276  res.polynomials[p.first]
277  = conjunction(std::get<0>(p.second), std::get<1>(p.second));
278 
279  auto has_one = bool_constant<context_t::has_one()>();
280  conjunctions_with_one_(res, l, r, has_one, conjunction);
281  normalize(res);
282  return res;
283  }
284 
288  template <typename LabelSet = labelset_t, typename Conjunction>
289  auto conjunction_(value_t lhs, value_t rhs,
290  Conjunction conjunction) const
291  -> enable_if_t<!detail::is_letterized_t<LabelSet>{},
292  value_t>
293  {
294  value_t res = zero();
295  res.constant = ws_.mul(lhs.constant, rhs.constant);
296  for (const auto& l: lhs.polynomials)
297  for (const auto& r: rhs.polynomials)
298  {
299  // The longest common prefix.
300  auto lcp = ls_.lgcd(l.first, r.first);
301  if (!ls_.is_one(lcp))
302  {
303  auto left = rs_.atom(ls_.ldiv(lcp, l.first));
304  auto right = rs_.atom(ls_.ldiv(lcp, r.first));
305  ps_.add_here(res.polynomials[lcp],
306  conjunction(ps_.lmul_label(left, l.second),
307  ps_.lmul_label(right, r.second)));
308  }
309  }
310  return res;
311  }
312 
314  template <typename Shuffle>
315  value_t& shuffle_(value_t& res,
316  const value_t& lhs_xpn, const expression_t& lhs_xpr,
317  const value_t& rhs_xpn, const expression_t& rhs_xpr,
318  Shuffle shuffle) const
319  {
320  // (i) lhs_xpn:rhs_xpr.
321  for (const auto& p: lhs_xpn.polynomials)
322  for (const auto& m: p.second)
323  ps_.add_here(res.polynomials[p.first],
324  shuffle(label_of(m), rhs_xpr), weight_of(m));
325  // (ii) lhs_xpr:rhs_xpn
326  for (const auto& p: rhs_xpn.polynomials)
327  for (const auto& m: p.second)
328  ps_.add_here(res.polynomials[p.first],
329  shuffle(lhs_xpr, label_of(m)), weight_of(m));
330 
331  return res;
332  }
333 
334  public:
336  value_t conjunction(value_t l, value_t r) const
337  {
338  return conjunction_(l, r,
339  [this](const polynomial_t& l,
340  const polynomial_t& r)
341  {
342  return ps_.conjunction(l, r);
343  });
344  }
345 
347  value_t shuffle(const value_t& lhs_xpn, const expression_t& lhs_xpr,
348  const value_t& rhs_xpn, const expression_t& rhs_xpr) const
349  {
350  value_t res;
351  res.constant = ws_.mul(lhs_xpn.constant, rhs_xpn.constant);
352  return shuffle_(res,
353  lhs_xpn, lhs_xpr, rhs_xpn, rhs_xpr,
354  [this](const expression_t& l, const expression_t& r)
355  {
356  return rs_.shuffle(l, r);
357  });
358  }
359 
361  value_t infiltration(const value_t& lhs_xpn, const expression_t& lhs_xpr,
362  const value_t& rhs_xpn, const expression_t& rhs_xpr) const
363  {
364  // Conjunction part: lhs_xpn&:rhs_xpn.
365  value_t res =
366  conjunction_(lhs_xpn, rhs_xpn,
367  [this](const polynomial_t& l, const polynomial_t& r)
368  {
369  return ps_.infiltration(l, r);
370  });
371 
372  // Shuffle part: lhs_xpn&:rhs_xpr + lhs_xpr&:rhs_xpn.
373  shuffle_(res,
374  lhs_xpn, lhs_xpr, rhs_xpn, rhs_xpr,
375  [this](const expression_t& l, const expression_t& r)
376  {
377  return rs_.infiltration(l, r);
378  });
379  return res;
380  }
381 
382  /*--------------.
383  | complement. |
384  `--------------*/
385 
387  value_t complement(const value_t& v) const
388  {
389  // Complement requires a free labelset.
390  return complement_<labelset_t::is_free()>(v);
391  }
392 
393  private:
395  template <bool IsFree>
396  vcsn::enable_if_t<!IsFree, value_t>
397  complement_(const value_t&) const
398  {
399  raise(me(), ": cannot handle complement without generators");
400  }
401 
403  template <bool IsFree>
404  vcsn::enable_if_t<IsFree, value_t>
405  complement_(const value_t& v) const
406  {
407  value_t res;
408  res.constant = ws_.is_zero(v.constant) ? ws_.one() : ws_.zero();
409 
410  // Turn the polynomials into expressions, and complement them.
411  for (auto l: ls_.genset())
412  {
413  auto i = v.polynomials.find(l);
414  res.polynomials[l] =
415  ps_.complement(i == end(v.polynomials) ? ps_.zero() : i->second);
416  }
417  return res;
418  }
419 
420  public:
422  value_t
423  determinize(const value_t& v) const
424  {
425  value_t res;
426  res.constant = v.constant;
427  for (const auto& lp: v.polynomials)
428  res.polynomials[lp.first] = {ps_.determinize(lp.second)};
429  return res;
430  }
431 
432  /*---------------.
433  | tuple(v...). |
434  `---------------*/
435 
437  template <unsigned Tape>
438  using focus_t
439  = expansionset<typename expressionset_t::template focus_t<Tape>>;
440 
442  template <unsigned Tape>
443  auto focus() const
444  -> focus_t<Tape>
445  {
446  return {detail::make_project<Tape>(rs_)};
447  }
448 
450  template <typename... Expansions>
451  struct tuple_impl
452  {
454  template <size_t Tape>
455  void denormalize_tape(typename focus_t<Tape>::value_t& e)
456  {
457  auto es = eset_.template focus<Tape>();
458  es.denormalize(e);
459  require(es.expressionset().weightset()->is_zero(e.constant),
460  es, ": to-expansion: cannot denormalize ", to_string(es, e),
461  ", need support for label one (the empty label)");
462  }
463 
465  template <size_t... Tape>
466  void denormalize(std::tuple<Expansions&...>& es,
467  detail::index_sequence<Tape...>)
468  {
469  using swallow = int[];
470  (void) swallow
471  {
472  (denormalize_tape<Tape>(std::get<Tape>(es)), 0)...
473  };
474  }
475 
477  void denormalize(Expansions&... es)
478  {
479  auto t = std::tuple<Expansions&...>{es...};
480  denormalize(t,
481  detail::make_index_sequence<sizeof...(Expansions)>{});
482  }
483 
484  const expansionset& eset_;
485  };
486 
541  template <typename... Expansions>
542  auto
543  tuple(Expansions&&... es) const
544  -> value_t
545  {
546  auto res = zero();
547  tuple_impl<Expansions...>{*this}.denormalize(es...);
548  detail::cross([&res, this](const auto&... ps)
549  {
550  auto l = label_t{ps.first...};
551  ps_.add_here(res.polynomials[l],
552  ps_.tuple(ps.second...));
553  },
554  es.polynomials...);
555  normalize(res);
556  return res;
557  }
558 
559  private:
561  expressionset_t rs_;
563  const labelset_t& ls_ = *rs_.labelset();
565  const weightset_t& ws_ = *rs_.weightset();
567  polynomialset_t ps_ = make_expression_polynomialset(rs_);
568  };
569  }
570 }
std::map< label_t, polynomial_t, vcsn::less< labelset_t >> polys_t
Definition: expansionset.hh:37
typename detail::label_t_of_impl< base_t< ValueSet >>::type label_t_of
Definition: traits.hh:46
labelset_t_of< context_t > labelset_t
Definition: expansionset.hh:22
static symbol sname()
The static name.
Definition: expansionset.hh:51
typename expressionset_t::value_t expression_t
Definition: expansionset.hh:24
typename detail::context_t_of_impl< base_t< ValueSet >>::type context_t_of
Definition: traits.hh:45
expansionset(const expressionset_t &rs)
Definition: expansionset.hh:46
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
Definition: traits.hh:51
const expressionset_t & expressionset() const
The expressionset.
Definition: expansionset.hh:58
std::ostream & print_set(std::ostream &o, format fmt={}) const
Print this valueset.
Definition: expansionset.hh:64
An input/output format.
Definition: format.hh:11
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:47
weightset_t_of< expressionset_t > weightset_t
Definition: expansionset.hh:25
expressionset_t rs_
The expressionset used for the expressions.
typename polynomialset_t::value_t polynomial_t
Definition: expansionset.hh:29
auto rs
Definition: lift.hh:151
symbol sname()
Definition: name.hh:67
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Definition: symbol.hh:23
typename polynomialset_t::monomial_t monomial_t
Definition: expansionset.hh:30
context_t_of< expressionset_t > context_t
Definition: expansionset.hh:21
static constexpr const char * me()
Definition: expansionset.hh:32
typename weightset_t::value_t weight_t
Definition: expansionset.hh:26