20 template <
typename ExpSet>
31 using weight_t =
typename weightset_t::value_t;
37 constexpr
static const char*
me() {
return "expansion"; }
42 using polys_t = std::map<label_t, polynomial_t, vcsn::less<labelset_t>>;
89 o <<
"\\mathsf{Expansion}[";
90 rs_.print_set(o, fmt);
95 rs_.print_set(o, fmt);
101 rs_.print_set(o, fmt);
113 std::ostream& o = std::cout,
117 if (!
ws_.is_zero(v.constant) || v.polynomials.empty())
122 ws_.print(v.constant, o, fmt.for_weights());
128 for (
const auto& p: v.polynomials)
135 ls_.print(p.first, o, fmt.for_labels());
139 ps_.print(p.second, o, fmt);
150 return detail::static_if<context_t::has_one()>
151 ([](
const auto& ls,
const value_t& x)
153 return !
has(x.polynomials, ls.one());
155 [](
const auto&,
const value_t&)
169 return ps_.is_zero(p.second);
183 auto i = res.polynomials.find(
one);
184 if (i != std::end(res.polynomials))
186 auto j = i->second.find(
rs_.one());
187 if (j != std::end(i->second))
191 if (
ps_.is_zero(i->second))
192 res.polynomials.erase(i);
221 if (!
ws_.is_zero(res.constant))
224 ps_.add_here(res.polynomials[
one],
226 res.constant =
ws_.zero();
249 template <
typename OtherExpSet>
275 return {
ws_.zero(), {{l,
ps_.one()}}};
281 lhs.constant =
ws_.add(lhs.constant, rhs.constant);
282 for (
const auto& p: rhs.polynomials)
283 ps_.add_here(lhs.polynomials[p.first], p.second);
309 for (
auto& p: res.polynomials)
310 p.second =
ps_.lweight(w, p.second);
320 for (
auto& p: lhs.polynomials)
321 for (
const auto& m: p.second)
322 ps_.add_here(
res.polynomials[p.first],
330 assert(
ws_.is_zero(res.constant));
331 for (
auto& p: res.polynomials)
332 p.second =
ps_.rmul_label(p.second, rhs);
340 for (
auto& p: res.polynomials)
341 for (
auto&& m: p.second)
347 template <
typename Conjunction>
355 template <
typename Conjunction>
362 const auto one =
ls_.one();
369 if (!
ws_.is_zero(l.constant))
370 for (
const auto& rhs: r.polynomials)
371 if (
ls_.is_one(rhs.first))
372 ps_.add_here(res.polynomials[rhs.first],
373 ps_.conjunction(
ps_.lweight(l.constant,
ps_.one()),
378 auto i = l.polynomials.find(
one);
379 if (i != std::end(l.polynomials))
380 for (
const auto& rhs: r.polynomials)
381 if (!
ls_.is_one(rhs.first))
382 ps_.add_here(res.polynomials[
one],
383 conjunction(i->second,
384 ps_.lmul_label(
rs_.atom(rhs.first),
391 if (!
ws_.is_zero(r.constant))
392 for (
const auto& lhs: l.polynomials)
393 if (
ls_.is_one(lhs.first))
394 ps_.add_here(res.polynomials[lhs.first],
395 ps_.conjunction(lhs.second,
396 ps_.lweight(r.constant,
ps_.one())));
400 auto i = r.polynomials.find(
one);
401 if (i != std::end(r.polynomials))
402 for (
const auto& lhs: l.polynomials)
403 if (!
ls_.is_one(lhs.first))
404 ps_.add_here(res.polynomials[
one],
405 conjunction(
ps_.lmul_label(
rs_.atom(lhs.first),
414 template <
typename LabelSet = labelset_t,
typename Conjunction>
417 -> std::enable_if_t<detail::is_letterized_t<LabelSet>{},
421 for (
const auto& p:
zip_maps(l.polynomials,
r.polynomials))
422 res.polynomials[p.first]
423 =
conjunction(std::get<0>(p.second), std::get<1>(p.second));
434 template <
typename LabelSet = labelset_t,
typename Conjunction>
437 -> std::enable_if_t<!detail::is_letterized_t<LabelSet>{},
441 for (
const auto& l: lhs.polynomials)
442 for (
const auto&
r: rhs.polynomials)
445 auto lcp =
ls_.lgcd(l.first,
r.first);
446 if (!
ls_.is_one(lcp))
448 auto left =
rs_.atom(
ls_.ldivide(lcp, l.first));
449 auto right =
rs_.atom(
ls_.ldivide(lcp,
r.first));
450 ps_.add_here(
res.polynomials[lcp],
452 ps_.lmul_label(right,
r.second)));
460 template <
typename Shuffle>
467 for (
const auto& p: lhs_xpn.polynomials)
468 for (
const auto& m: p.second)
469 ps_.add_here(res.polynomials[p.first],
472 for (
const auto& p: rhs_xpn.polynomials)
473 for (
const auto& m: p.second)
474 ps_.add_here(res.polynomials[p.first],
488 return ps_.conjunction(l, r);
503 return rs_.shuffle(l, r);
516 return ps_.infiltrate(l, r);
524 return rs_.infiltrate(l, r);
543 return complement_<detail::is_letterized_t<labelset_t>{}>(
v);
548 template <
bool IsLetterized>
549 std::enable_if_t<!IsLetterized, value_t>
553 ": complement: labelset must be letterized: ",
ls_);
557 template <
bool IsLetterized>
558 std::enable_if_t<IsLetterized, value_t>
563 detail::static_if<labelset_t::has_one()>
564 ([
this](
const auto&
v,
const auto& ls)
567 me(),
": complement: expansion must be normalized: ",
573 detail::static_if<detail::has_generators_mem_fn<labelset_t>{}>
574 ([
this, &
res](
const auto&
v,
const auto& ls)
576 for (
auto l: ls.generators())
578 auto i = v.polynomials.find(l);
580 ps_.complement(i == end(v.polynomials)
581 ?
ps_.zero() : i->second);
596 for (
const auto& p: v.polynomials)
599 *
this,
": cannot transpose an expansion " 600 "with proper firsts: ",
to_string(*
this, v));
601 res.polynomials[p.first] =
ps_.transpose(p.second);
612 auto& res_one =
res.polynomials[
one];
615 for (
const auto& p:
zip_maps(lhs.polynomials, rhs.polynomials))
616 ps_.add_ldivide_here(res_one,
617 std::get<0>(p.second),
618 std::get<1>(p.second));
621 if (
has(lhs.polynomials,
one))
622 for (
const auto& rhsp: rhs.polynomials)
623 if (!
ls_.is_one(rhsp.first))
624 ps_.add_ldivide_here(res_one,
625 lhs.polynomials[
one],
626 ps_.lmul_label(
rs_.atom(rhsp.first),
630 if (
has(rhs.polynomials,
one))
631 for (
const auto& lhsp: lhs.polynomials)
632 if (!
ls_.is_one(lhsp.first))
633 ps_.add_ldivide_here(res_one,
634 ps_.lmul_label(
rs_.atom(lhsp.first),
636 rhs.polynomials[
one]);
639 if (
ps_.is_zero(res_one))
640 res.polynomials.erase(
one);
651 for (
const auto& lp: v.polynomials)
652 res.polynomials[lp.first] = {
ps_.determinize(lp.second)};
661 template <
unsigned Tape>
666 template <
unsigned Tape>
670 return {
rs_.template project<Tape>()};
674 template <
typename... Expansions>
679 template <
size_t Tape>
683 auto es =
eset_.template project<Tape>();
686 VCSN_REQUIRE(es.expressionset().weightset()->is_zero(res.constant),
687 es,
": to-expansion: cannot denormalize ",
689 ", need support for label one (the empty label)");
690 return res.polynomials;
694 template <
size_t... Tape>
697 -> std::tuple<typename project_t<Tape>::polys_t...>
699 using res_t = std::tuple<typename project_t<Tape>::polys_t...>;
700 return res_t{denormalize_tape<Tape>(std::get<Tape>(es))...};
706 auto t =
std::tuple<
const Expansions&...>{es...};
707 constexpr
auto indices
717 auto polys =
denormalize(std::forward<Expansions>(es)...);
719 ([&
res,
this](
const auto&... ps)
786 template <
typename... Expansions>
791 auto t = tuple_impl<Expansions...>{*
this};
792 return t.tuple(std::forward<Expansions>(es)...);
796 template <
size_t Tape>
799 auto xs = project<Tape>();
800 const auto& ps = xs.polynomialset();
801 using res_t =
typename decltype(xs)::
value_t;
803 res.constant = v.constant;
804 for (
const auto& p: v.polynomials)
805 ps.add_here(
res.polynomials[
ls_.template project<Tape>(p.first)],
806 ps_.template project<Tape>(p.second));
816 std::false_type)
const 822 std::true_type)
const 834 assert(
ws_.is_zero(l.constant));
835 assert(
ws_.is_zero(r.constant));
836 const auto& ls0 =
ls_.template set<0>();
837 const auto& ls1 =
ls_.template set<1>();
840 for (
const auto& lhs: l.polynomials)
841 if (ls1.is_one(std::get<1>(lhs.first)))
842 for (
const auto& rhs: r.polynomials)
843 if (!ls0.is_one(std::get<0>(rhs.first)))
845 ps_.add_here(res.polynomials[lhs.first],
846 ps_.compose(lhs.second,
847 ps_.lmul_label(
rs_.atom(rhs.first),
850 for (
const auto& rhs: r.polynomials)
851 if (ls0.is_one(std::get<0>(rhs.first)))
852 for (
const auto& lhs: l.polynomials)
853 if (!ls1.is_one(std::get<1>(lhs.first)))
855 ps_.add_here(res.polynomials[rhs.first],
856 ps_.compose(
ps_.lmul_label(
rs_.atom(lhs.first),
865 const auto& ls0 =
ls_.template set<0>();
866 const auto& ls1 =
ls_.template set<1>();
869 for (
const auto& lhs: l.polynomials)
870 if (ls1.is_one(std::get<1>(lhs.first)))
871 for (
const auto& rhs: r.polynomials)
872 if (!ls0.is_one(std::get<0>(rhs.first)))
876 auto l0 =
ls_.tuple(
ls_.template project<0>(lhs.first),
877 ls_.template project<1>(rhs.first));
879 auto l1 =
ls_.tuple(
ls_.template project<0>(rhs.first),
880 ls_.template project<1>(lhs.first));
881 ps_.add_here(res.polynomials[l0],
882 ps_.compose(lhs.second,
883 ps_.lmul_label(
rs_.atom(l1),
890 if (!
ws_.is_zero(l.constant))
891 for (
const auto& rhs: r.polynomials)
892 if (ls0.is_one(std::get<0>(rhs.first)))
893 ps_.add_here(res.polynomials[rhs.first],
894 ps_.compose(
ps_.lweight(l.constant,
ps_.one()),
898 for (
const auto& rhs: r.polynomials)
899 if (ls0.is_one(std::get<0>(rhs.first)))
900 for (
const auto& lhs: l.polynomials)
901 if (!ls1.is_one(std::get<1>(lhs.first)))
905 auto l0 =
ls_.tuple(
ls_.template project<0>(lhs.first),
906 ls_.template project<1>(rhs.first));
908 auto l1 =
ls_.tuple(
ls_.template project<0>(rhs.first),
909 ls_.template project<1>(lhs.first));
910 ps_.add_here(res.polynomials[l0],
920 if (!
ws_.is_zero(r.constant))
921 for (
const auto& lhs: l.polynomials)
922 if (ls0.is_one(std::get<1>(lhs.first)))
923 ps_.add_here(res.polynomials[lhs.first],
924 ps_.compose(lhs.second,
925 ps_.lweight(r.constant,
ps_.one())));
930 template <
typename Ctx = context_t>
932 -> std::enable_if_t<are_composable<Ctx, Ctx>()
939 constexpr
auto in = 0;
946 for (
const auto& lm: l.polynomials)
947 for (
const auto& rm:
r.polynomials)
948 if (
ls_.template set<out>().equal(std::get<out>(
label_of(lm)),
953 ps_.add_here(
res.polynomials[l],
954 ps_.compose(lm.second, rm.second));
977 bool denorm_ = old_way_ || !!getenv(
"VCSN_DENORM");
981 template <
typename Context>
991 template <
typename Ctx1,
typename Ctx2>
1000 return type(
vcsn::join(lhs.expressionset(), rhs.expressionset()));
auto denormalize(std::tuple< const Expansions &... > &es, detail::index_sequence< Tape... >) const -> std::tuple< typename project_t< Tape >::polys_t... >
Denormalize on all these tapes.
value_t & denormalize(value_t &res) const
Move the constant to the polynomial associated to one.
Print as a parsable type string.
weightset_t_of< expressionset_t > weightset_t
auto project() const -> project_t< Tape >
The expansionset for tape Tape.
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
void compose_with_one_old_(value_t &res, const value_t &l, const value_t &r) const
value_t & normalize(value_t &res) const
Normalize: eliminate null polynomials and move the constant term from the label one.
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
bool denorm_
Denormalize if requested explicitly, or if running the old way.
std::enable_if_t<!IsLetterized, value_t > complement_(const value_t &) const
Complement on an invalid labelset.
value_t complement(const value_t &v) const
The complement of v.
Denormalize a pack of one-tape expansions.
typename expressionset_t::value_t expression_t
size_t size(const ExpSet &rs, const typename ExpSet::value_t &r)
void cross_tuple(Fun f, const std::tuple< Ts... > &ts)
auto label_one(const LabelSet &ls) -> typename LabelSet::value_t
Enjoy type inference.
zipped_maps< Dereference, Maps... > zip_maps(Maps &&... maps)
value_t & normalize_(value_t &res, std::true_type) const
Normalize res.
expansionset(const expressionset_t &rs)
auto tuple(Expansions &&... es) const -> value_t
The tuplization of single-tape expansions into a multitape expansion.
An inner node with multiple children.
value_t & rmul_label_here(value_t &res, const expression_t &rhs) const
In place right multiplication by an expression.
const weightset_t & ws_
Shorthand to the weightset.
std::map< label_t, polynomial_t, vcsn::less< labelset_t > > polys_t
void compose_with_one_(value_t &, const value_t &, const value_t &, std::false_type) const
static value_t conv(self_t, const value_t &v)
Conversion from (this and) other weightsets.
auto conjunction_(const value_t &lhs, const value_t &rhs, Conjunction conjunction) const -> std::enable_if_t<!detail::is_letterized_t< LabelSet >
The conjunction of l and r.
const polynomialset_t & polynomialset() const
The polynomialset.
typename weightset_t::value_t weight_t
auto denormalize_tape(const typename project_t< Tape >::value_t &e) const -> typename project_t< Tape >::polys_t
Denormalize on this tape: from expansion to pure polynomial.
value_t & denormalize_(value_t &res, std::true_type) const
Denormalize res move the constant to the polynomial associated to one.
value_t conjunction(const value_t &l, const value_t &r) const
The conjunction of l and r.
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
value_t rweight(const value_t &lhs, const weight_t &w) const
Right-multiplication of lhs by w.
polynomialset_t ps_
The polynomialset for the polynomials.
const labelset_t & ls_
Shorthand to the labelset.
auto project(const value_t &v) const
Project a multitape expansion.
expressionset_t rs_
The expressionset used for the expressions.
std::ostream & print_set(std::ostream &o, format fmt={}) const
Print this valueset.
typename detail::context_t_of_impl< base_t< ValueSet > >::type context_t_of
Print as rich UTF-8 text, escaped.
An input/output format for valuesets.
Provide a variadic mul on top of a binary mul(), and one().
void conjunctions_with_one_(value_t &, const value_t &, const value_t &, std::false_type, Conjunction) const
bool old_way_
Whether to running the old composition code.
value_t add(value_t res, const value_t &rhs) const
Addition.
value_t & denormalize_(value_t &res, std::false_type) const
Denormalize when there is no label one: identity.
std::integral_constant< bool, B > bool_constant
auto join(const ValueSet &vs) -> ValueSet
The join of a single valueset.
void erase_if(Container &c, Predicate p)
In place removal of entries matching the predicate.
auto denormalize(const Expansions &... es) const
Entry point: Denormalize all these expansions.
A structure that implements the computation of join(V1, V2).
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
value_t & lweight_here(const weight_t &w, value_t &res) const
Inplace left-multiplication by w of res.
Build the static sequence of size_t [0, N[.
auto conjunction_(value_t l, value_t r, Conjunction conjunction) const -> std::enable_if_t< detail::is_letterized_t< LabelSet >
The conjunction of l and r.
value_t conv(const expansionset< OtherExpSet > &other, const typename expansionset< OtherExpSet >::value_t &v) const
Convert from another expansionset to self.
const expansionset & eset_
value_t one() const
The one.
expressionset_t expressionset_t
typename polynomialset_t::monomial_t monomial_t
auto in(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions arriving to state s.
std::enable_if_t< IsLetterized, value_t > complement_(const value_t &v) const
Complement on a letterized labelset.
std::ostream & print(const value_t &v, std::ostream &o=std::cout, format fmt={}) const
Print this expansion.
std::string type(const automaton &a)
The implementation type of a.
context_t_of< expressionset_t > context_t
typename detail::label_t_of_impl< base_t< ValueSet > >::type label_t_of
value_t & normalize_(value_t &res, std::false_type) const
Normalize when there is no label one: identity.
expansionset< expressionset< Context > > make_expansionset(const expressionset< Context > &es)
auto tuple(Expansions &&... es) const -> value_t
labelset_t_of< context_t > labelset_t
Print as plain (ASCII) text, escaped.
value_t lweight(const weight_t &w, value_t res) const
Left-multiplication by w of rhs.
void weight_set(welement< Label, Weight > &m, const Weight &w)
Set the weight of a welement.
static constexpr const char * me()
std::string to_string(identities i)
Wrapper around operator<<.
void compose_with_one_new_(value_t &res, const value_t &l, const value_t &r) const
value_t zero() const
The zero.
auto weight_of(const welement< Label, Weight > &m) -> decltype(m.weight())
The weight of a welement.
auto label_of(const welement< Label, Weight > &m) -> decltype(m.label())
The label of a welement.
value_t ldivide(value_t lhs, value_t rhs) const
Print as is. For instance, don't try to escape labels.
value_t & shuffle_(value_t &res, const value_t &lhs_xpn, const expression_t &lhs_xpr, const value_t &rhs_xpn, const expression_t &rhs_xpr, Shuffle shuffle) const
The shuffle product of l and r.
void compose_with_one_(value_t &res, const value_t &l, const value_t &r, std::true_type) const
expression_polynomialset_t< ExpSet > make_expression_polynomialset(const ExpSet &rs)
From a ExpSet to its polynomialset.
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.
static type join(const expansionset< expressionset< Ctx1 >> &lhs, const expansionset< expressionset< Ctx2 >> &rhs)
label_t_of< context_t > label_t
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
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.
value_t determinize(const value_t &v) const
Turn the polynomials into (normalized) monomials.
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.
static symbol sname()
The static name.
bool is_normal(const value_t &x) const
Whether an expansion is normal.
const context_t & context() const
The context.
typename polynomialset_t::value_t polynomial_t
#define VCSN_REQUIRE(Cond,...)
A macro similar to require.
void conjunctions_with_one_(value_t &res, const value_t &l, const value_t &r, std::true_type, Conjunction conjunction) const
value_t & ldivide_here(const weight_t &w, value_t &res) const
Inplace left-division by w of res.
const expressionset_t & expressionset() const
The expressionset.
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.
auto out(const Aut &aut, state_t_of< Aut > s)
Indexes of visible transitions leaving state s.