Vcsn  2.8
Be Rational
multiply.hh
Go to the documentation of this file.
1 #pragma once
2 
3 #include <unordered_map>
4 
5 #include <vcsn/algos/add.hh>
6 #include <vcsn/algos/copy.hh>
8 #include <vcsn/algos/standard.hh>
9 #include <vcsn/algos/star.hh>
10 #include <vcsn/algos/tags.hh>
11 #include <vcsn/core/automaton.hh>
12 #include <vcsn/core/join.hh>
14 #include <vcsn/dyn/automaton.hh> // dyn::make_automaton
15 #include <vcsn/dyn/value.hh>
16 #include <vcsn/misc/raise.hh> // require
17 #include <vcsn/misc/to.hh> // to
18 #include <vcsn/misc/type_traits.hh> // to
19 #include <vcsn/misc/vector.hh> // make_vector
20 
21 namespace vcsn
22 {
23  /*----------------------------------.
24  | multiply(automaton, automaton). |
25  `----------------------------------*/
26 
32  template <Automaton Aut1, Automaton Aut2>
33  Aut1&
34  multiply_here(Aut1& res, const Aut2& b, deterministic_tag)
35  {
36  static_assert(labelset_t_of<Aut1>::is_free(),
37  "multiply_here: requires free labelset");
38  multiply_here(res, b, standard_tag{});
39  res = determinize(res)->strip();
40  return res;
41  }
42 
46  template <Automaton Aut1, Automaton Aut2>
47  Aut1&
48  multiply_here(Aut1& res, const Aut2& b, general_tag)
49  {
50  const auto& ls = *res->labelset();
51  const auto& ws = *res->weightset();
52  const auto& bws = *b->weightset();
53 
54  // The set of the current (left-hand side) final transitions.
55  // Store these transitions by copy.
56  auto final_ts = detail::make_vector(final_transitions(res));
57 
58  // The set of the current (right-hand side) initial transitions.
59  // Store these transitions by copy.
60  auto init_ts = detail::make_vector(initial_transitions(b));
61 
62  auto copy = make_copier(b, res);
63  copy([](state_t_of<Aut2>) { return true; },
64  // Import all the B transitions, except the initial ones.
65  [b] (transition_t_of<Aut2> t) { return b->src_of(t) != b->pre(); });
66  const auto& map = copy.state_map();
67 
68  // Branch all the final transitions of res to the initial ones in b.
69  for (auto t1: final_ts)
70  {
71  auto s1 = res->src_of(t1);
72  auto w1 = res->weight_of(t1);
73  res->del_transition(t1);
74  for (auto t2: init_ts)
75  res->new_transition(s1,
76  map.at(b->dst_of(t2)),
77  ls.one(),
78  ws.mul(w1,
79  ws.conv(bws, b->weight_of(t2))));
80  }
81  return res;
82  }
83 
87  template <Automaton Aut1, Automaton Aut2>
88  Aut1&
89  multiply_here(Aut1& res, const Aut2& b, standard_tag = {})
90  {
91  const auto& ls = *res->labelset();
92  const auto& bls = *b->labelset();
93  const auto& ws = *res->weightset();
94  const auto& bws = *b->weightset();
95 
96  // The set of the current (left-hand side) final transitions.
97  // Store these transitions by copy.
98  auto final_ts = detail::make_vector(final_transitions(res));
99 
100  // The set of the current (right-hand side) initial transitions.
101  // Store these transitions by copy.
102  auto init_ts = detail::make_vector(initial_transitions(b));
103 
104  auto copy = make_copier(b, res);
105  copy(// In order to keep b's transitions unbroken we have to keep its
106  // initial states which have at least one incoming transition.
107  [b](state_t_of<Aut2> s)
108  {
109  return !b->is_initial(s) || !in(b, s).empty();
110  },
111  // Import b's transitions, except the initial ones (and those
112  // from its (genuine) initial state).
113  [b] (transition_t_of<Aut2> t) { return b->src_of(t) != b->pre(); });
114  const auto& map = copy.state_map();
115 
116  // Branch all the final transitions of res to the successors of
117  // b's initial states.
118  for (auto t1: final_ts)
119  {
120  // Remove the previous final transition first, as we might add
121  // a final transition for the same state later.
122  //
123  // For instance on "<2>a+(<3>\e+<5>a)", the final state s1 of
124  // <2>a will be made final thanks to <3>\e. So if we compute
125  // the new transitions from s1 and then remove t1, we will
126  // have removed the fact that s1 is final thanks to <3>\e.
127  //
128  // Besides, s1 will become final with weight <3>, which might
129  // interfere with <5>a too.
130  auto s1 = res->src_of(t1);
131  auto w1 = res->weight_of(t1);
132  res->del_transition(t1);
133  for (auto t2: init_ts)
134  {
135  auto w2 = b->weight_of(t2);
136  for (auto t3: all_out(b, b->dst_of(t2)))
137  res->set_transition(s1,
138  map.at(b->dst_of(t3)),
139  ls.conv(bls, b->label_of(t3)),
140  ws.mul(w1,
141  ws.conv(bws, w2),
142  ws.conv(bws, b->weight_of(t3))));
143  }
144  }
145  return res;
146  }
147 
149  template <Automaton Aut1, Automaton Aut2, typename Tag = general_tag>
150  auto
151  multiply(const Aut1& lhs, const Aut2& rhs, Tag tag = {})
152  -> decltype(lhs->null_state(), // SFINAE.
153  rhs->null_state(), // SFINAE.
154  detail::make_join_automaton(tag, lhs, rhs))
155  {
156  auto res = detail::make_join_automaton(tag, lhs, rhs);
157  copy_into(lhs, res);
158  multiply_here(res, rhs, tag);
159  return res;
160  }
161 
162  namespace dyn
163  {
164  namespace detail
165  {
167  template <Automaton Lhs, Automaton Rhs, typename String>
168  automaton
169  multiply(const automaton& lhs, const automaton& rhs,
170  const std::string& algo)
171  {
172  const auto& l = lhs->as<Lhs>();
173  const auto& r = rhs->as<Rhs>();
175  (algo == "auto" ? "standard" : algo,
176  [l, r](auto tag)
177  {
178  return automaton(::vcsn::multiply(l, r, tag));
179  },
180  l, r);
181  }
182  }
183  }
184 
185  /*---------------------------------.
186  | multiply(automaton, min, max). |
187  `---------------------------------*/
188 
194  // The return type, via SFINAE on aut->null_state(), makes the
195  // difference with another overload, `<ValueSet>(ValueSet, value,
196  // value)`, which coincides in the case ValueSet = Z, hence value =
197  // int.
198  //
199  // Unfortunately, fresh_automaton_t_of, which uses
200  // context_t_of<Aut>, is not SFINAE transparent: it causes a hard
201  // failure instead of being ignored.
202  //
203  // FIXME: if you know how to use fresh_automaton_t_of instead, let
204  // me know.
205  template <Automaton Aut, typename Tag = general_tag>
206  auto
207  multiply(const Aut& aut, to exp, Tag tag = {})
208  -> decltype(aut->null_state(), // SFINAE.
209  detail::make_join_automaton(tag, aut))
210  {
211  auto res = detail::make_join_automaton(tag, aut);
212  if (exp.max == -1)
213  {
214  res = star(aut, tag);
215  if (exp.min)
216  res = multiply(multiply(aut, to{exp.min}, tag), res, tag);
217  }
218  else
219  {
220  if (exp.min == 0)
221  {
222  //automatonset::one().
223  auto s = res->new_state();
224  res->set_initial(s);
225  res->set_final(s);
226  }
227  else
228  {
229  auto tag_aut = detail::make_join_automaton(tag, aut);
230  copy_into(aut, res);
231  copy_into(aut, tag_aut);
232  for (int n = 1; n < exp.min; ++n)
233  res = multiply(res, tag_aut, tag);
234  }
235  if (exp.min < exp.max)
236  {
237  // Aut sum = automatonset.one();
238  auto sum = detail::make_join_automaton(tag, aut);
239  {
240  auto s = sum->new_state();
241  sum->set_initial(s);
242  sum->set_final(s);
243  }
244  for (int n = 1; n <= exp.max - exp.min; ++n)
245  sum = strip(add(sum, multiply(aut, to{n}, tag), tag));
246  res = multiply(res, sum, tag);
247  }
248  }
249  return res;
250  }
251 
252  namespace dyn
253  {
254  namespace detail
255  {
257  template <Automaton Aut, typename Int1, typename Int2, typename String>
258  automaton
259  multiply_repeated(const automaton& a, int min, int max,
260  const std::string& algo)
261  {
262  const auto& aut = a->as<Aut>();
264  [aut, min, max](auto tag)
265  {
266  return automaton(::vcsn::multiply(aut, to{min, max}, tag));
267  },
268  aut);
269  }
270  }
271  }
272 
273 
274  /*------------------------------------.
275  | multiply(expression, expression). |
276  `------------------------------------*/
277 
279  template <typename ValueSet>
280  typename ValueSet::value_t
281  multiply(const ValueSet& vs,
282  const typename ValueSet::value_t& lhs,
283  const typename ValueSet::value_t& rhs)
284  {
285  return vs.mul(lhs, rhs);
286  }
287 
288  namespace dyn
289  {
290  namespace detail
291  {
293  template <typename ExpSetLhs, typename ExpSetRhs>
294  expression
295  multiply_expression(const expression& lhs, const expression& rhs)
296  {
297  auto join_elts = join<ExpSetLhs, ExpSetRhs>(lhs, rhs);
298  return {std::get<0>(join_elts),
299  ::vcsn::multiply(std::get<0>(join_elts),
300  std::get<1>(join_elts),
301  std::get<2>(join_elts))};
302  }
303  }
304  }
305 
306  namespace dyn
307  {
308  namespace detail
309  {
311  template <typename ExpSetLhs, typename ExpSetRhs>
312  expression
314  {
315  auto join_elts = join<ExpSetLhs, ExpSetRhs>(lhs, rhs);
316  auto res = std::get<0>(join_elts).concat(std::get<1>(join_elts),
317  std::get<2>(join_elts));
318  return {std::get<0>(join_elts), res};
319  }
320  }
321  }
322 
323 
324  /*-----------------------------.
325  | multiply(value, min, max). |
326  `-----------------------------*/
327 
329  template <typename ValueSet>
330  using add_mem_fn_t
331  = decltype(std::declval<ValueSet>()
332  .add(std::declval<typename ValueSet::value_t>(),
333  std::declval<typename ValueSet::value_t>()));
334 
336  template <typename ValueSet>
338 
344  template <typename ValueSet>
345  auto
346  multiply(const ValueSet& vs, const typename ValueSet::value_t& v,
347  const to& exp)
348  -> std::enable_if_t<!has_add_mem_fn<ValueSet>{},
349  typename ValueSet::value_t>
350  {
351  VCSN_REQUIRE(exp.single() && exp.finite(),
352  vs, ": invalid range exponent: ", exp);
353  return detail::static_if<detail::has_power_mem_fn<ValueSet>{}>
354  ([](const auto& vs, const auto& v, auto n){ return vs.power(v, n); },
355  [](const auto& vs, const auto& v, auto n)
356  {
357  auto res = vs.one();
358  if (!vs.is_one(v))
359  while (n--)
360  res = vs.mul(res, v);
361  return res;
362  })(vs, v, exp.min);
363  }
364 
374  template <typename ValueSet>
375  auto
376  multiply(const ValueSet& vs, const typename ValueSet::value_t& v,
377  const to& exp)
378  -> std::enable_if_t<has_add_mem_fn<ValueSet>{},
379  typename ValueSet::value_t>
380  {
381  auto res = typename ValueSet::value_t{};
382  if (exp.max == -1)
383  {
384  res = vs.star(v);
385  if (exp.min)
386  res = vs.mul(vs.power(v, exp.min), res);
387  }
388  else
389  {
390  res = vs.power(v, exp.min);
391  if (exp.min < exp.max)
392  {
393  auto sum = vs.one();
394  for (int n = 1; n <= exp.max - exp.min; ++n)
395  sum = vs.add(sum, vs.power(v, n));
396  res = vs.mul(res, sum);
397  }
398  }
399  return res;
400  }
401 
402  namespace dyn
403  {
404  namespace detail
405  {
407  template <typename ExpSet, typename Int1, typename Int2>
408  expression
409  multiply_expression_repeated(const expression& re, int min, int max)
410  {
411  const auto& r = re->as<ExpSet>();
412  return {r.valueset(),
413  ::vcsn::multiply(r.valueset(), r.value(), to{min, max})};
414  }
415  }
416  }
417 
418 
419  /*--------------------------.
420  | multiply(label, label). |
421  `--------------------------*/
422 
423  namespace dyn
424  {
425  namespace detail
426  {
428  template <typename LabelSetLhs, typename LabelSetRhs>
429  label
430  multiply_label(const label& lhs, const label& rhs)
431  {
432  const auto& l = lhs->as<LabelSetLhs>();
433  const auto& r = rhs->as<LabelSetRhs>();
434  auto rs = join(l.valueset(), r.valueset());
435  auto lr = rs.conv(l.valueset(), l.value());
436  auto rr = rs.conv(r.valueset(), r.value());
437  return {rs, multiply(rs, lr, rr)};
438  }
439 
441  template <typename LabelSet, typename Int>
442  label
443  multiply_label_repeated(const label& re, int exp)
444  {
445  const auto& r = re->as<LabelSet>();
446  return {r.valueset(),
447  ::vcsn::multiply(r.valueset(), r.value(), to{exp})};
448  }
449  }
450  }
451 
452 
453  /*------------------------------------.
454  | multiply(polynomial, polynomial). |
455  `------------------------------------*/
456 
457  namespace dyn
458  {
459  namespace detail
460  {
462  template <typename PolynomialSetLhs, typename PolynomialSetRhs>
463  polynomial
464  multiply_polynomial(const polynomial& lhs, const polynomial& rhs)
465  {
466  auto join_elts = join<PolynomialSetLhs, PolynomialSetRhs>(lhs, rhs);
467  return {std::get<0>(join_elts), multiply(std::get<0>(join_elts),
468  std::get<1>(join_elts),
469  std::get<2>(join_elts))};
470  }
471  }
472  }
473 
474  /*----------------------------.
475  | multiply(weight, weight). |
476  `----------------------------*/
477 
478  namespace dyn
479  {
480  namespace detail
481  {
483  template <typename WeightSetLhs, typename WeightSetRhs>
484  weight
485  multiply_weight(const weight& lhs, const weight& rhs)
486  {
487  const auto& l = lhs->as<WeightSetLhs>();
488  const auto& r = rhs->as<WeightSetRhs>();
489  auto ws = join(l.valueset(), r.valueset());
490  auto lw = ws.conv(l.valueset(), l.value());
491  auto rw = ws.conv(r.valueset(), r.value());
492  return {ws, ::vcsn::multiply(ws, lw, rw)};
493  }
494 
496  template <typename WeightSet, typename Int1, typename Int2>
497  weight
498  multiply_weight_repeated(const weight& wgt, int min, int max)
499  {
500  const auto& w = wgt->as<WeightSet>();
501  return {w.valueset(),
502  ::vcsn::multiply(w.valueset(), w.value(), to{min, max})};
503  }
504  }
505  }
506 }
A dyn automaton.
Definition: automaton.hh:17
automaton multiply_repeated(const automaton &a, int min, int max, const std::string &algo)
Bridge (multiply).
Definition: multiply.hh:259
auto initial_transitions(const Aut &aut) -> decltype(aut->all_out(aut->pre()))
Indexes of transitions to (visible) initial states.
Definition: automaton.hh:167
weightset_mixin< detail::r_impl > r
Definition: fwd.hh:54
void copy_into(const AutIn &in, AutOut &out, KeepState keep_state, KeepTrans keep_trans)
Copy selected states and transitions of an automaton.
Definition: copy.hh:267
Aut1 & multiply_here(Aut1 &res, const Aut2 &b, deterministic_tag)
Append automaton b to res.
Definition: multiply.hh:34
auto multiply(const ValueSet &vs, const typename ValueSet::value_t &v, const to &exp) -> std::enable_if_t<!has_add_mem_fn< ValueSet >
Repeated multiplication of values that cannot be added.
Definition: multiply.hh:346
typename detail::transition_t_of_impl< base_t< ValueSet > >::type transition_t_of
Definition: traits.hh:65
typename detail::state_t_of_impl< base_t< ValueSet > >::type state_t_of
Definition: traits.hh:64
auto multiply(const Aut1 &lhs, const Aut2 &rhs, Tag tag={}) -> decltype(lhs->null_state(), rhs->null_state(), detail::make_join_automaton(tag, lhs, rhs))
Concatenate two automata, general case.
Definition: multiply.hh:151
polynomial multiply_polynomial(const polynomial &lhs, const polynomial &rhs)
Bridge (multiply).
Definition: multiply.hh:464
Tag for operations on deterministic automata.
Definition: tags.hh:19
return exp min
Definition: multiply.hh:362
auto & as()
Extract wrapped typed value.
Definition: value.hh:55
std::vector< typename Cont::value_type > make_vector(const Cont &cont)
The content of cont as a vector.
Definition: vector.hh:18
context join(const context &c1, const context &c2)
Bridge.
Tag for operations on standard automata.
Definition: tags.hh:32
auto final_transitions(const Aut &aut) -> decltype(aut->all_in(aut->post()))
Indexes of transitions from (visible) final states.
Definition: automaton.hh:178
weight multiply_weight(const weight &lhs, const weight &rhs)
Bridge (multiply).
Definition: multiply.hh:485
label multiply_label(const label &lhs, const label &rhs)
Bridge (multiply).
Definition: multiply.hh:430
label multiply_label_repeated(const label &re, int exp)
Bridge (multiply).
Definition: multiply.hh:443
ExpansionSet::value_t determinize(const ExpansionSet &xs, const typename ExpansionSet::value_t &x)
Determinize an expansion.
weight multiply_weight_repeated(const weight &wgt, int min, int max)
Bridge (multiply).
Definition: multiply.hh:498
auto all_out(const Aut &aut, state_t_of< Aut > s)
Indexes of transitions leaving state s.
Definition: automaton.hh:67
automaton multiply(const automaton &lhs, const automaton &rhs, const std::string &algo)
Bridge.
Definition: multiply.hh:169
decltype(std::declval< ValueSet >() .add(std::declval< typename ValueSet::value_t >(), std::declval< typename ValueSet::value_t >())) add_mem_fn_t
The type of the add member function in valuesets.
Definition: multiply.hh:333
Provide a variadic mul on top of a binary mul(), and one().
Definition: fwd.hh:46
A dyn Value/ValueSet.
Definition: fwd.hh:29
auto copy(const AutIn &input, KeepState keep_state, KeepTrans keep_trans) -> decltype(keep_state(input->null_state()), keep_trans(input->null_transition()), make_fresh_automaton< AutIn, AutOut >(input))
A copy of input keeping only its states that are accepted by keep_state, and transitions accepted by ...
Definition: copy.hh:322
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
Definition: traits.hh:63
expression multiply_expression_repeated(const expression &re, int min, int max)
Bridge (multiply).
Definition: multiply.hh:409
Definition: a-star.hh:8
auto in(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions arriving to state s.
Definition: automaton.hh:135
Tag for operations on all automata.
Definition: tags.hh:22
detail::copier< AutIn, AutOut > make_copier(const AutIn &in, AutOut &out, bool safe=true)
Build an automaton copier.
Definition: copy.hh:256
auto & as()
Extract wrapped typed automaton.
Definition: automaton.hh:37
expression concatenate_expression(const expression &lhs, const expression &rhs)
Bridge (concatenate).
Definition: multiply.hh:313
auto dispatch_tags(std::string algo, Operation op, Aut &&... auts)
Dispatch an operation between automata depending on their nature.
Definition: tags.hh:46
int min
Definition: to.hh:68
return v
Definition: multiply.hh:362
value_impl< detail::expression_tag > expression
Definition: fwd.hh:31
automaton star(const automaton &a, const std::string &algo)
Bridge.
Definition: star.hh:124
An exponent, or range of exponents.
Definition: to.hh:25
bool single() const
Whether features a single exponent.
Definition: to.hh:63
expression multiply_expression(const expression &lhs, const expression &rhs)
Bridge (multiply).
Definition: multiply.hh:295
automaton strip(const automaton &aut)
Bridge.
Definition: strip.hh:46
automaton add(const automaton &lhs, const automaton &rhs, const std::string &algo)
Bridge.
Definition: add.hh:124
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
Definition: raise.hh:98
auto make_join_automaton(deterministic_tag, Auts &&... auts) -> decltype(join_automata(std::forward< Auts >(auts)...))
Make an empty automaton which is a supertype of others.
Definition: tags.hh:101
return res
Definition: multiply.hh:399
int max
Definition: to.hh:69
weightset_mixin< detail::b_impl > b
Definition: fwd.hh:48
bool finite() const
Whether the max exponent is finte.
Definition: to.hh:57