39 false, Lazy, Aut, Auts...>
42 "product: requires letterized labels");
53 template <Automaton A>
56 template <
size_t... I>
57 using seq =
typename super_t::template
seq<I...>;
71 o <<
"product_automaton";
72 return aut_->print_set_(o, fmt);
80 using label_t =
typename labelset_t::value_t;
81 using weight_t =
typename weightset_t::value_t;
105 while (!
aut_->todo_.empty())
107 const auto& p =
aut_->todo_.front();
109 aut_->todo_.pop_front();
114 template <
bool L = Lazy>
115 std::enable_if_t<
sizeof...(Auts) == 2 && !
L>
ldivide()
117 static_assert(labelset_t::has_one(),
118 "ldivide: labelset must have a neutral");
121 while (!
aut_->todo_.empty())
123 const auto& p =
aut_->todo_.front();
125 aut_->todo_.pop_front();
130 template <
bool L = Lazy>
131 std::enable_if_t<
sizeof...(Auts) == 2 && !
L>
add()
135 constexpr
bool bb = (std::is_same<weightset_t_of<lhs_t>,
b>::value
136 && std::is_same<weightset_t_of<rhs_t>,
b>::value);
137 static_assert(bb,
"add: requires Boolean weightset");
140 while (!
aut_->todo_.empty())
142 const auto& p =
aut_->todo_.front();
144 aut_->todo_.pop_front();
149 template <
bool L = Lazy>
155 auto new_initials = std::vector<state_t_of<rhs_t>>();
157 const auto& lhs = std::get<0>(
aut_->auts_);
158 auto& rhs = std::get<1>(
aut_->auts_);
160 while (!
aut_->todo_.empty())
162 const auto& p =
aut_->todo_.front();
163 const auto& state_name = std::get<0>(p);
167 if (lhs->is_final(std::get<0>(state_name)))
168 new_initials.push_back(std::get<1>(state_name));
169 aut_->todo_.pop_front();
173 rhs->unset_initial(rhs->dst_of(t));
174 for (
auto s: new_initials)
182 if (!std::is_same<weightset_t, b>{})
185 "shuffle: invalid lhs:"
186 " weighted automata with spontaneous"
187 " transitions are not supported");
189 "shuffle: invalid rhs:"
190 " weighted automata with spontaneous"
191 " transitions are not supported");
196 while (!
aut_->todo_.empty())
198 const auto& p =
aut_->todo_.front();
199 add_shuffle_transitions<false>(std::get<1>(p), std::get<0>(p));
200 aut_->todo_.pop_front();
225 "infiltrate: variadic product does not work");
228 if (!std::is_same<weightset_t, b>{})
231 "infiltrate: invalid lhs:"
232 " weighted automata with spontaneous"
233 " transitions are not supported");
235 "infiltrate: invalid rhs:"
236 " weighted automata with spontaneous"
237 " transitions are not supported");
245 while (!
aut_->todo_.empty())
247 const auto& p =
aut_->todo_.front();
254 add_shuffle_transitions<true>(std::get<1>(p), std::get<0>(p));
256 aut_->todo_.pop_front();
298 if (!
aut_->labelset()->is_one(t.first))
305 ws_.mul(ts.weight()...));
317 template <
bool L = Lazy>
318 std::enable_if_t<
sizeof...(Auts) == 2 && !
L>
321 const auto& ls = *
aut_->labelset();
322 const auto& lhs = std::get<0>(
aut_->auts_);
323 const auto& rhs = std::get<1>(
aut_->auts_);
324 const auto& lstate = std::get<0>(psrc);
325 const auto& rstate = std::get<1>(psrc);
327 if (lhs->is_final(lstate) || lstate == lhs->post())
329 for (
auto ts:
all_out(rhs, rstate))
331 const auto&
lweight = lhs->is_final(lstate)
332 ? lhs->get_final_weight(lstate) :
ws_.one();
334 state(lhs->post(), rhs->dst_of(ts)),
340 if (!ls.is_one(t.first)
341 && (!ls.is_special(t.first) || src ==
aut_->pre()))
347 ls.is_special(t.first)
348 ? t.first : ls.one(),
349 ws_.ldivide(ts.weight()...));
357 template <
bool L = Lazy>
358 std::enable_if_t<
sizeof...(Auts) == 2 && !
L>
361 const auto& lhs = std::get<0>(
aut_->auts_);
362 const auto& rhs = std::get<1>(
aut_->auts_);
363 const auto& lstate = std::get<0>(psrc);
364 const auto& rstate = std::get<1>(psrc);
366 auto common_labels = std::set<label_t_of<Aut>>{};
369 common_labels.insert(t.first);
378 for (
auto t:
all_out(lhs, lstate))
379 if (!
has(common_labels, lhs->label_of(t)))
382 for (
auto t:
all_out(rhs, rstate))
383 if (!
has(common_labels, rhs->label_of(t)))
390 template <std::size_t... I>
395 using swallow =
int[];
398 (add_one_transitions_<I>(*(std::get<I>(
aut_->auts_)->
labelset()),
404 template <std::
size_t I,
typename LS>
405 std::enable_if_t<!LS::has_one(), void>
411 template <std::
size_t I,
typename LS>
412 std::enable_if_t<LS::has_one(), void>
425 if (!tmap.empty() && ls.is_one(tmap.begin()->first))
426 for (
auto t : tmap.begin()->second)
429 std::get<I>(pdst) = t.dst;
430 this->new_transition(src,
state(pdst), ls.one(), t.weight());
437 template <std::size_t... I>
440 return all(is_proper_in<I>(psrc)...);
445 template <std::size_t... I>
448 return all(has_proper_out<I>(psrc)...);
453 template <Automaton Aut_>
454 std::enable_if_t<labelset_t_of<Aut_>::has_one(),
bool>
457 return aut->labelset()->is_one(aut->label_of(tr));
462 template <Automaton Aut_>
463 constexpr std::enable_if_t<!labelset_t_of<Aut_>::has_one(),
bool>
486 -> std::enable_if_t<labelset_t_of<input_automaton_t<I>>::has_one(),
492 const auto& aut = std::get<I>(
aut_->auts_);
493 auto s = std::get<I>(sn);
494 auto rin =
all_in(aut, s);
495 auto rtr = rin.begin();
498 return rtr == rin.end() || !
is_one(aut, *rtr);
511 auto s = tmap.size();
517 return !std::get<I>(
aut_->auts_)->
labelset()->is_one(tmap.begin()->first);
524 template <
bool Infiltrate = false>
529 = add_shuffle_transitions_<Infiltrate>(src, psrc,
aut_->indices);
530 aut_->set_final(src,
final);
537 template <
bool Infiltrate,
size_t... I>
543 using swallow =
int[];
547 add_shuffle_transitions_<Infiltrate, I>(src, psrc)),
563 template <
bool Infiltrate,
size_t I>
573 if (std::get<I>(
aut_->auts_)->labelset()->is_special(t.first))
574 res = t.second.front().weight();
586 for (
auto d: t.second)
589 std::get<I>(pdst) = d.dst;
591 || std::get<I>(psrc) == d.dst)
611 return make_shared_ptr<res_t>(aut, auts...);
650 template <
typename Auts,
size_t... I>
662 template <
typename Auts,
typename Bool>
668 return conjunction_<Auts>(as, lazy, indices);
682 template <Automaton Aut1, Automaton Aut2>
686 return detail::static_if<std::is_same<weightset_t_of<Aut1>,
b>::value
687 && std::is_same<weightset_t_of<Aut2>,
b>::value>
688 ([] (
const auto& lhs,
const auto& rhs)
690 return ldivide(lhs, rhs, boolean_tag{});
692 [] (
const auto& lhs,
const auto& rhs)
694 return ldivide(lhs, rhs, weighted_tag{});
699 template <Automaton Aut1, Automaton Aut2>
706 prod->ldivide_here();
710 template <Automaton Aut1, Automaton Aut2>
715 detail::make_product_automaton<false>(
join_automata(lhs, rhs), lhs, rhs);
717 return prod->strip();
726 template <Automaton Aut1, Automaton Aut2>
730 const auto& a1 = aut1->
as<Aut1>();
731 const auto& a2 = aut2->
as<Aut2>();
732 return vcsn::ldivide<Aut1, Aut2>(a1, a2);
747 template <Automaton Aut1, Automaton Aut2>
761 template <Automaton Aut1, Automaton Aut2>
765 const auto& a1 = aut1->
as<Aut1>();
766 const auto& a2 = aut2->
as<Aut2>();
786 detail::make_product_automaton<false>(
join_automata(as...), as...);
796 template <
typename Auts,
size_t... I>
805 template <
typename Auts>
811 return shuffle_<Auts>(as, indices);
822 template <
typename ValueSet>
823 typename ValueSet::value_t
825 const typename ValueSet::value_t& lhs,
826 const typename ValueSet::value_t& rhs)
828 return vs.shuffle(lhs, rhs);
836 template <
typename ExpSetLhs,
typename ExpSetRhs>
840 auto join_elts = join<ExpSetLhs, ExpSetRhs>(lhs, rhs);
841 return {std::get<0>(join_elts),
843 std::get<1>(join_elts),
844 std::get<2>(join_elts))};
855 template <Automaton A1, Automaton A2>
862 detail::make_product_automaton<false>(
join_automata(a1, a2), a1, a2);
870 infiltrate(
const A1& a1,
const A2& a2,
const A3& a3,
const Auts&... as)
882 template <
typename Auts,
size_t... I>
891 template <
typename Auts>
897 return infiltrate_<Auts>(as, indices);
907 template <
typename ValueSet>
908 typename ValueSet::value_t
910 const typename ValueSet::value_t& lhs,
911 const typename ValueSet::value_t& rhs)
913 return vs.infiltrate(lhs, rhs);
921 template <
typename ExpSetLhs,
typename ExpSetRhs>
925 auto join_elts = join<ExpSetLhs, ExpSetRhs>(lhs, rhs);
926 return {std::get<0>(join_elts),
928 std::get<1>(join_elts),
929 std::get<2>(join_elts))};
945 template <Automaton Aut>
956 "conjunction: exponent must be single, ", exp);
958 "conjunction: exponent must be finite, ", exp);
959 unsigned n = exp.min;
963 auto s =
res->new_state();
966 for (
auto l:
res->context().labelset()->generators())
967 res->new_transition(s, s, l);
978 static bool iterative = getenv(
"VCSN_ITERATIVE");
980 for (
size_t i = 0; i < n; ++i)
984 auto power =
strip(aut);
1006 template <Automaton Aut,
typename Un
signed>
1010 const auto& a = aut->
as<Aut>();
1021 template <
typename ValueSet>
1022 typename ValueSet::value_t
1024 const typename ValueSet::value_t& lhs,
1025 const typename ValueSet::value_t& rhs)
1027 return rs.conjunction(lhs, rhs);
1039 template <
typename ExpSetLhs,
typename ExpSetRhs>
1043 auto join_elts = join<ExpSetLhs, ExpSetRhs>(lhs, rhs);
1044 return {std::get<0>(join_elts),
1046 std::get<1>(join_elts),
1047 std::get<2>(join_elts))};
1061 template <
typename ExpSetLhs,
typename ExpSetRhs>
1065 auto join_elts = join<ExpSetLhs, ExpSetRhs>(lhs, rhs);
1066 return {std::get<0>(join_elts),
1068 std::get<1>(join_elts),
1069 std::get<2>(join_elts))};
1083 template <
typename PolynomialSetLhs,
typename PolynomialSetRhs>
1087 auto join_elts = join<PolynomialSetLhs, PolynomialSetRhs>(lhs, rhs);
1088 return {std::get<0>(join_elts),
1090 std::get<1>(join_elts),
1091 std::get<2>(join_elts))};
void conjunction()
Compute the (accessible part of the) conjunction.
polynomial conjunction_polynomial(const polynomial &lhs, const polynomial &rhs)
Bridge (conjunction).
auto join_automata(Auts &&...auts) -> decltype(pass(auts->null_state()...), make_mutable_automaton(join(auts->context()...)))
An automaton whose type is the join between those of auts.
std::enable_if_t< LS::has_one(), void > add_one_transitions_(const LS &ls, const state_t src, const state_name_t &psrc)
If the I-th labelset has one, add the relevant spontaneous transitions leaving the state...
auto labelset(Args &&...args) const -> decltype(aut_-> labelset(std::forward< Args >(args)...))
product_automaton_impl self_t
base_t< tuple_element_t< I, automata_t >> input_automaton_t
The type of the Ith input automaton, unqualified.
auto conjunction_lazy(const Aut &a, const Auts &...as)
Build the (accessible part of the) conjunction, on-the-fly.
std::ostream & print_set(std::ostream &o, format fmt={}) const
Aut transpose(const transpose_automaton< Aut > &aut)
typename std::tuple_element< I, T >::type tuple_element_t
C++14.
std::shared_ptr< detail::tuple_automaton_impl< Auts... >> tuple_automaton
A tuple automaton as a shared pointer.
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
Aut automaton_t
The type of the resulting automaton.
std::shared_ptr< const node< Context >> expression
std::tuple< transition_map_t< Auts >... > transition_maps_
Transition caches.
constexpr std::enable_if_t<!labelset_t_of< Aut_ >::has_one(), bool > is_one(const Aut_ &, transition_t_of< Aut_ >) const
Same as above, but for labelsets without one, so it's always false.
automaton_t strip()
The automaton we decorate.
auto all_in(Args &&...args) const -> decltype(aut_-> all_in(std::forward< Args >(args)...))
std::shared_ptr< detail::product_automaton_impl< Lazy, Aut, Auts... >> product_automaton
A product automaton as a shared pointer.
typename detail::transition_t_of_impl< base_t< ValueSet >>::type transition_t_of
static symbol sname_(const T &...t)
bool are_proper_in(const state_name_t &psrc, seq< I... >) const
Whether no tapes in the sequence have spontaneous incoming transitions.
weight_t add_shuffle_transitions_(const state_t src, const state_name_t &psrc)
Let Ith automaton advance, and add the corresponding transitions in the output.
typename super_t::state_name_t state_name_t
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
bool have_proper_out(const state_name_t &psrc, seq< I... >)
Whether all the tapes in the sequence have proper outgoing transitions (but possibly spontaneous too)...
typename tuple_automaton_impl::state_name_t state_name_t
typename detail::context_t_of_impl< base_t< ValueSet >>::type context_t_of
auto conjunction(const Aut &a, const Auts &...as)
Build the (accessible part of the) conjunction.
expansion conjunction_expansion(const expansion &lhs, const expansion &rhs)
Bridge (conjunction).
std::enable_if_t< sizeof...(Auts)==2 &&!L > ldivide()
Compute the left quotient.
Tag to request the most appropriate version of an algorithm.
std::enable_if_t< sizeof...(Auts)==2 &&!L > add_add_transitions(const state_t src, const state_name_t &psrc)
Behaves similarly to add_conjunction_transitions on a Boolean weightset, but use post() as a special ...
void require(Bool b, Args &&...args)
If b is not verified, raise an error with args as message.
std::enable_if_t< labelset_t_of< Aut_ >::has_one(), bool > is_one(const Aut_ &aut, transition_t_of< Aut_ > tr) const
Check if the transition is spontaneous (in the case of a labelset with one).
Build the (accessible part of the) product.
auto make_product_automaton(Aut aut, const Auts &...auts) -> product_automaton< Lazy, Aut, Auts... >
typename weightset_t::value_t weight_t
typename super_t::template seq< I... > seq
void shuffle()
Compute the (accessible part of the) shuffle product.
typename super_t::template transition_map_t< A > transition_map_t
void add_conjunction_transitions(const state_t src, const state_name_t &psrc)
Add transitions to the result automaton, starting from the given result input state, which must correspond to the given pair of input state automata.
std::enable_if_t< sizeof...(Auts)==2 &&!L > add()
Compute the deterministic sum of two deterministic automata.
auto tuple(const Auts &...as)
Build the (accessible part of the) tuple.
void infiltrate()
Compute the (accessible part of the) infiltration product.
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
std::enable_if_t< sizeof...(Auts)==2 &&!L > add_ldivide_transitions(const state_t src, const state_name_t &psrc)
Behave similarly to add_conjunction_transitions, with three main differences: the algorithm continues...
typename tuple_automaton_impl::state_t state_t
weightset_t_of< context_t > weightset_t
auto shuffle(const Auts &...as) -> tuple_automaton< decltype(join_automata(as...)), Auts... >
The (accessible part of the) shuffle product.
const weightset_t & ws_
The resulting weightset.
AutOut make_fresh_automaton(const AutIn &model)
Create an empty, mutable, automaton, based on another one.
std::enable_if_t<!LS::has_one(), void > add_one_transitions_(const LS &, const state_t, const state_name_t &)
In the case where the labelset doesn't have one, do nothing.
weight_t add_shuffle_transitions_(const state_t src, const state_name_t &psrc, seq< I... >)
Let all automata advance one after the other, and add the corresponding transitions in the output...
auto insplit(Aut aut, bool lazy=false) -> std::enable_if_t< labelset_t_of< Aut >::has_one(), decltype(make_insplit_automaton(aut))>
Insplit an automaton with possible spontaneous transitions.
Request the Boolean specialization for determinization (B and F2).
automaton conjunction_(const std::vector< automaton > &as, bool lazy, vcsn::detail::index_sequence< I... >)
Bridge helper.
expression shuffle_expression(const expression &lhs, const expression &rhs)
Bridge (shuffle).
typename Aut::element_type::template fresh_automaton_t< Context > fresh_automaton_t_of
Given an automaton type, the type of its copies.
automaton shuffle_(const std::vector< automaton > &as, vcsn::detail::index_sequence< I... >)
Variadic bridge helper.
void initialize_shuffle()
Fill the worklist with the initial source-state pairs, as needed for the shuffle algorithm.
An input/output format for valuesets.
value_impl< detail::polynomial_tag > polynomial
auto rdivide(const Aut1 &a1, const Aut2 &a2)
Compute the right quotient.
auto infiltrate(const A1 &a1, const A2 &a2) -> tuple_automaton< decltype(join_automata(a1, a2)), A1, A2 >
The (accessible part of the) infiltration product.
Request for the weighted version of an algorithm.
expression conjunction_expression(const expression &lhs, const expression &rhs)
Bridge (conjunction).
bool has_proper_out(const state_name_t &psrc)
Whether the Ith state of psrc in the Ith input automaton has proper outgoing transitions (but possibl...
auto meet_automata(Auts &&...auts) -> decltype(pass(auts->null_state()...), make_mutable_automaton(meet(auts->context()...)))
An automaton whose type is the meet between those of auts.
auto all_out(state_t s) const -> decltype(all_out(aut_, s))
All the outgoing transitions.
automaton infiltrate_(const std::vector< automaton > &as, vcsn::detail::index_sequence< I... >)
Variadic bridge helper.
value_impl< detail::expansion_tag > expansion
std::enable_if_t< sizeof...(Auts)==2 &&!L > ldivide_here()
Compute the left quotient in-place.
std::remove_cv_t< std::remove_reference_t< T >> base_t
T without reference or const/volatile qualifiers.
bool all(Bool &&...values)
Whether all the values evaluate as true.
constexpr auto is_proper_in(const state_name_t &) const -> std::enable_if_t<!labelset_t_of< input_automaton_t< I >>::has_one(), bool >
Whether the state has only proper incoming transitions.
std::tuple< Auts... > automata_t
The type of input automata.
void add_one_transitions_(const state_t src, const state_name_t &psrc, seq< I... >)
Add the spontaneous transitions leaving state src, if it is relevant (i.e.
ValueSet::value_t conjunction(const ValueSet &rs, const typename ValueSet::value_t &lhs, const typename ValueSet::value_t &rhs)
Intersection/Hadamard product of expressions/polynomials.
bool is_proper(const Aut &aut)
Test whether an automaton is proper.
auto conjunction(const Aut &aut, to exp) -> fresh_automaton_t_of< Aut >
Repeated conjunction of a automaton.
void initialize_conjunction()
Fill the worklist with the initial source-state pairs, as needed for the conjunction algorithm...
product_automaton_impl(Aut aut, const Auts &...auts)
Build a product automaton.
auto initial_transitions(const Aut &aut) -> decltype(aut->all_out(aut->pre()))
Indexes of transitions to (visible) initial states.
typename super_t::state_t state_t
state_t state(Args &&...args)
Conversion from state name to state number.
zipped_maps< Dereference, Maps... > zip_map_tuple(const std::tuple< Maps... > &maps)
automaton conjunction_repeated(const automaton &aut, unsigned n)
Bridge (conjunction).
auto add_transition(Args &&...args) -> decltype(aut_-> add_transition(std::forward< Args >(args)...))
void cross_tuple(Fun f, const std::tuple< Ts... > &ts)
weightset_mixin< detail::b_impl > b
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
automaton_t aut_
The wrapped automaton, possibly const.
context_t_of< Aut > context_t
The context of the result.
auto & as()
Extract wrapped typed automaton.
void add_transitions(const state_t src, const state_name_t &psrc)
Tell lazy_tuple_automaton how to add the transitions to a state.
std::tuple< typename transition_map_t< Auts >::map_t &... > out_(const state_name_t &ss)
The outgoing tuple of transitions from state tuple ss.
void add_shuffle_transitions(const state_t src, const state_name_t &psrc)
Add transitions to the given result automaton, starting from the given result input state...
An exponent, or range of exponents.
Decorator implementing the laziness for an algorithm.
Provide a variadic mul on top of a binary mul(), and one().
typename labelset_t::value_t label_t
labelset_t_of< context_t > labelset_t
value_impl< detail::expression_tag > expression
auto lweight(Args &&...args) -> decltype(aut_-> lweight(std::forward< Args >(args)...))
expression infiltrate_expression(const expression &lhs, const expression &rhs)
Bridge (infiltrate).
auto new_transition(Args &&...args) -> decltype(aut_-> new_transition(std::forward< Args >(args)...))
auto is_proper_in(const state_name_t &sn) const -> std::enable_if_t< labelset_t_of< input_automaton_t< I >>::has_one(), bool >
Whether the state has only proper incoming transitions.