38 false, Lazy, Aut, Auts...>
41 "product: requires letterized labels");
52 template <Automaton A>
55 template <
size_t... I>
56 using seq =
typename super_t::template
seq<I...>;
70 o <<
"product_automaton";
71 return aut_->print_set_(o, fmt);
79 using label_t =
typename labelset_t::value_t;
80 using weight_t =
typename weightset_t::value_t;
104 while (!
aut_->todo_.empty())
106 const auto& p =
aut_->todo_.front();
108 aut_->todo_.pop_front();
113 template <
bool L = Lazy>
114 std::enable_if_t<
sizeof...(Auts) == 2 && !
L>
ldivide()
116 static_assert(labelset_t::has_one(),
117 "ldivide: labelset must have a neutral");
120 while (!
aut_->todo_.empty())
122 const auto& p =
aut_->todo_.front();
124 aut_->todo_.pop_front();
129 template <
bool L = Lazy>
130 std::enable_if_t<
sizeof...(Auts) == 2 && !
L>
add()
134 constexpr
bool bb = (std::is_same<weightset_t_of<lhs_t>,
b>::value
135 && std::is_same<weightset_t_of<rhs_t>,
b>::value);
136 static_assert(bb,
"add: requires Boolean weightset");
139 while (!
aut_->todo_.empty())
141 const auto& p =
aut_->todo_.front();
143 aut_->todo_.pop_front();
148 template <
bool L = Lazy>
154 auto new_initials = std::vector<state_t_of<rhs_t>>();
156 const auto& lhs = std::get<0>(
aut_->auts_);
157 auto& rhs = std::get<1>(
aut_->auts_);
159 while (!
aut_->todo_.empty())
161 const auto& p =
aut_->todo_.front();
162 const auto& state_name = std::get<0>(p);
166 if (lhs->is_final(std::get<0>(state_name)))
167 new_initials.push_back(std::get<1>(state_name));
168 aut_->todo_.pop_front();
172 rhs->unset_initial(rhs->dst_of(t));
173 for (
auto s: new_initials)
181 if (!std::is_same<weightset_t, b>{})
184 "shuffle: invalid lhs:" 185 " weighted automata with spontaneous" 186 " transitions are not supported");
188 "shuffle: invalid rhs:" 189 " weighted automata with spontaneous" 190 " transitions are not supported");
195 while (!
aut_->todo_.empty())
197 const auto& p =
aut_->todo_.front();
198 add_shuffle_transitions<false>(std::get<1>(p), std::get<0>(p));
199 aut_->todo_.pop_front();
224 "infiltrate: variadic product does not work");
227 if (!std::is_same<weightset_t, b>{})
230 "infiltrate: invalid lhs:" 231 " weighted automata with spontaneous" 232 " transitions are not supported");
234 "infiltrate: invalid rhs:" 235 " weighted automata with spontaneous" 236 " transitions are not supported");
244 while (!
aut_->todo_.empty())
246 const auto& p =
aut_->todo_.front();
253 add_shuffle_transitions<true>(std::get<1>(p), std::get<0>(p));
255 aut_->todo_.pop_front();
297 if (!
aut_->labelset()->is_one(t.first))
304 ws_.mul(ts.weight()...));
316 template <
bool L = Lazy>
317 std::enable_if_t<
sizeof...(Auts) == 2 && !
L>
320 const auto& ls = *
aut_->labelset();
321 const auto& lhs = std::get<0>(
aut_->auts_);
322 const auto& rhs = std::get<1>(
aut_->auts_);
323 const auto& lstate = std::get<0>(psrc);
324 const auto& rstate = std::get<1>(psrc);
326 if (lhs->is_final(lstate) || lstate == lhs->post())
328 for (
auto ts:
all_out(rhs, rstate))
330 const auto&
lweight = lhs->is_final(lstate)
331 ? lhs->get_final_weight(lstate) :
ws_.one();
333 state(lhs->post(), rhs->dst_of(ts)),
339 if (!ls.is_one(t.first)
340 && (!ls.is_special(t.first) || src ==
aut_->pre()))
346 ls.is_special(t.first)
347 ? t.first : ls.one(),
348 ws_.mul(ts.weight()...));
356 template <
bool L = Lazy>
357 std::enable_if_t<
sizeof...(Auts) == 2 && !
L>
360 const auto& lhs = std::get<0>(
aut_->auts_);
361 const auto& rhs = std::get<1>(
aut_->auts_);
362 const auto& lstate = std::get<0>(psrc);
363 const auto& rstate = std::get<1>(psrc);
365 auto common_labels = std::set<label_t_of<Aut>>{};
368 common_labels.insert(t.first);
377 for (
auto t:
all_out(lhs, lstate))
378 if (!
has(common_labels, lhs->label_of(t)))
381 for (
auto t:
all_out(rhs, rstate))
382 if (!
has(common_labels, rhs->label_of(t)))
389 template <std::size_t... I>
394 using swallow =
int[];
397 (add_one_transitions_<I>(*(std::get<I>(
aut_->auts_)->
labelset()),
403 template <std::
size_t I,
typename LS>
404 std::enable_if_t<!LS::has_one(), void>
410 template <std::
size_t I,
typename LS>
411 std::enable_if_t<LS::has_one(), void>
424 if (!tmap.empty() && ls.is_one(tmap.begin()->first))
425 for (
auto t : tmap.begin()->second)
428 std::get<I>(pdst) = t.dst;
429 this->new_transition(src,
state(pdst), ls.one(), t.weight());
436 template <std::size_t... I>
439 return all(is_proper_in<I>(psrc)...);
444 template <std::size_t... I>
447 return all(has_proper_out<I>(psrc)...);
452 template <Automaton Aut_>
453 std::enable_if_t<labelset_t_of<Aut_>::has_one(),
bool>
456 return aut->labelset()->is_one(aut->label_of(tr));
461 template <Automaton Aut_>
462 constexpr std::enable_if_t<!labelset_t_of<Aut_>::has_one(),
bool>
472 -> std::enable_if_t<!labelset_t_of<input_automaton_t<I>>::has_one(),
485 -> std::enable_if_t<labelset_t_of<input_automaton_t<I>>::has_one(),
491 const auto& aut = std::get<I>(
aut_->auts_);
492 auto s = std::get<I>(sn);
493 auto rin =
all_in(aut, s);
494 auto rtr = rin.begin();
497 return rtr == rin.end() || !
is_one(aut, *rtr);
510 auto s = tmap.size();
516 return !std::get<I>(
aut_->auts_)->
labelset()->is_one(tmap.begin()->first);
523 template <
bool Infiltrate = false>
528 = add_shuffle_transitions_<Infiltrate>(src, psrc,
aut_->indices);
529 aut_->set_final(src,
final);
536 template <
bool Infiltrate,
size_t... I>
542 using swallow =
int[];
546 add_shuffle_transitions_<Infiltrate, I>(src, psrc)),
562 template <
bool Infiltrate,
size_t I>
572 if (std::get<I>(
aut_->auts_)->labelset()->is_special(t.first))
573 res = t.second.front().weight();
585 for (
auto d: t.second)
588 std::get<I>(pdst) = d.dst;
590 || std::get<I>(psrc) == d.dst)
610 return make_shared_ptr<res_t>(aut, auts...);
649 template <
typename Auts,
size_t... I>
661 template <
typename Auts,
typename Bool>
667 return conjunction_<Auts>(as, lazy, indices);
681 template <Automaton Aut1, Automaton Aut2>
685 return detail::static_if<std::is_same<weightset_t_of<Aut1>,
b>::value
686 && std::is_same<weightset_t_of<Aut2>,
b>::value>
687 ([] (
const auto& lhs,
const auto& rhs)
691 [] (
const auto& lhs,
const auto& rhs)
698 template <Automaton Aut1, Automaton Aut2>
703 detail::static_if<labelset_t_of<Aut2>::has_one()>
704 ([](
const auto& rhs){
return insplit(rhs); },
705 [](
const auto& rhs){
return copy(rhs); })
709 prod->ldivide_here();
713 template <Automaton Aut1, Automaton Aut2>
718 detail::make_product_automaton<false>(
join_automata(lhs, rhs), lhs, rhs);
720 return prod->strip();
729 template <Automaton Aut1, Automaton Aut2>
733 const auto& a1 = aut1->
as<Aut1>();
734 const auto& a2 = aut2->
as<Aut2>();
735 return vcsn::ldivide<Aut1, Aut2>(a1, a2);
750 template <Automaton Aut1, Automaton Aut2>
764 template <Automaton Aut1, Automaton Aut2>
768 const auto& a1 = aut1->
as<Aut1>();
769 const auto& a2 = aut2->
as<Aut2>();
789 detail::make_product_automaton<false>(
join_automata(as...), as...);
799 template <
typename Auts,
size_t... I>
808 template <
typename Auts>
814 return shuffle_<Auts>(as, indices);
825 template <Automaton A1, Automaton A2>
832 detail::make_product_automaton<false>(
join_automata(a1, a2), a1, a2);
840 infiltrate(
const A1& a1,
const A2& a2,
const A3& a3,
const Auts&... as)
852 template <
typename Auts,
size_t... I>
861 template <
typename Auts>
867 return infiltrate_<Auts>(as, indices);
882 template <Automaton Aut>
893 "conjunction: exponent must be single, ", exp);
895 "conjunction: exponent must be finite, ", exp);
896 unsigned n = exp.min;
900 auto s =
res->new_state();
903 for (
auto l:
res->context().labelset()->generators())
904 res->new_transition(s, s, l);
915 static bool iterative = getenv(
"VCSN_ITERATIVE");
917 for (
size_t i = 0; i < n; ++i)
921 auto power =
strip(aut);
943 template <Automaton Aut,
typename Un
signed>
947 const auto& a = aut->
as<Aut>();
Aut transpose(const transpose_automaton< Aut > &aut)
The transpose of a transpose automaton is the original automaton.
auto initial_transitions(const Aut &aut) -> decltype(aut->all_out(aut->pre()))
Indexes of transitions to (visible) initial states.
ATTRIBUTE_PURE bool has(const boost::container::flat_set< Key, Compare, Allocator > &s, const Key &e)
Whether e is member of s.
typename super_t::state_t state_t
auto all_in(Args &&... args) const -> decltype(aut_-> all_in(std::forward< Args >(args)...))
typename detail::weightset_t_of_impl< base_t< ValueSet > >::type weightset_t_of
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...
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...
auto conjunction_lazy(const Aut &a, const Auts &... as)
Build the (accessible part of the) conjunction, on-the-fly.
labelset_t_of< context_t > labelset_t
typename detail::transition_t_of_impl< base_t< ValueSet > >::type transition_t_of
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.
void cross_tuple(Fun f, const std::tuple< Ts... > &ts)
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.
bool is_proper(const Aut &aut)
Test whether an automaton is proper.
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.
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...
typename tuple_automaton_impl::state_name_t state_name_t
Decorator implementing the laziness for an algorithm.
Build the (accessible part of the) product.
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...
void add_transitions(const state_t src, const state_name_t &psrc)
Tell lazy_tuple_automaton how to add the transitions to a state.
typename weightset_t::value_t weight_t
context_t_of< Aut > context_t
The context of the result.
product_automaton_impl(Aut aut, const Auts &... auts)
Build a product automaton.
typename super_t::state_name_t state_name_t
auto shuffle(const Auts &... as) -> tuple_automaton< decltype(join_automata(as...)), Auts... >
The (accessible part of the) shuffle product.
product_automaton_impl self_t
auto infiltrate(const A1 &a1, const A2 &a2) -> tuple_automaton< decltype(join_automata(a1, a2)), A1, A2 >
The (accessible part of the) infiltration product.
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.
Request for the weighted version of an algorithm.
state_t state(Args &&... args)
Conversion from state name to state number.
boost::flyweight< std::string, boost::flyweights::no_tracking, boost::flyweights::intermodule_holder > symbol
An internalized string.
automaton_t aut_
The wrapped automaton, possibly const.
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.
auto conjunction(const Aut &aut, to exp) -> fresh_automaton_t_of< Aut >
Repeated conjunction of a automaton.
auto rdivide(const Aut1 &a1, const Aut2 &a2)
Compute the right quotient.
static symbol sname_(const T &... t)
std::ostream & print_set(std::ostream &o, format fmt={}) const
auto tuple(const Auts &... as)
Build the (accessible part of the) tuple.
base_t< tuple_element_t< I, automata_t > > input_automaton_t
The type of the Ith input automaton, unqualified.
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).
bool are_proper_in(const state_name_t &psrc, seq< I... >) const
Whether no tapes in the sequence have spontaneous incoming transitions.
automaton conjunction_(const std::vector< automaton > &as, bool lazy, vcsn::detail::index_sequence< I... >)
Bridge helper.
typename detail::context_t_of_impl< base_t< ValueSet > >::type context_t_of
An input/output format for valuesets.
typename std::tuple_element< I, T >::type tuple_element_t
C++14.
Provide a variadic mul on top of a binary mul(), and one().
void infiltrate()
Compute the (accessible part of the) infiltration product.
auto make_product_automaton(Aut aut, const Auts &... auts) -> product_automaton< Lazy, Aut, Auts... >
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.
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 ...
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.
std::enable_if_t< sizeof...(Auts)==2 &&!L > ldivide()
Compute the left quotient.
auto add_transition(Args &&... args) -> decltype(aut_-> add_transition(std::forward< Args >(args)...))
Tag to request the most appropriate version of an algorithm.
void initialize_shuffle()
Fill the worklist with the initial source-state pairs, as needed for the shuffle algorithm.
auto labelset(Args &&... args) const -> decltype(aut_-> labelset(std::forward< Args >(args)...))
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 ...
typename detail::labelset_t_of_impl< base_t< ValueSet > >::type labelset_t_of
typename labelset_t::value_t label_t
Aut automaton_t
The type of the resulting automaton.
void shuffle()
Compute the (accessible part of the) shuffle product.
Build the static sequence of size_t [0, N[.
weightset_t_of< context_t > weightset_t
std::remove_cv_t< std::remove_reference_t< T > > base_t
T without reference or const/volatile qualifiers.
std::enable_if_t< sizeof...(Auts)==2 &&!L > ldivide_here()
Compute the left quotient in-place.
auto new_transition(Args &&... args) -> decltype(aut_-> new_transition(std::forward< Args >(args)...))
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...
std::enable_if_t< sizeof...(Auts)==2 &&!L > add()
Compute the deterministic sum of two deterministic automata.
auto conjunction(const Aut &a, const Auts &... as)
Build the (accessible part of the) conjunction.
auto lweight(Args &&... args) -> decltype(aut_-> lweight(std::forward< Args >(args)...))
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::shared_ptr< detail::tuple_automaton_impl< Auts... > > tuple_automaton
A tuple automaton as a shared pointer.
typename super_t::template seq< I... > seq
auto & as()
Extract wrapped typed automaton.
typename super_t::template transition_map_t< A > transition_map_t
AutOut make_fresh_automaton(const AutIn &model)
Create an empty, mutable, automaton, based on another one.
Request the Boolean specialization for determinization (B and F2).
typename tuple_automaton_impl::state_t state_t
std::tuple< typename transition_map_t< Auts >::map_t &... > out_(const state_name_t &ss)
The outgoing tuple of transitions from state tuple ss.
automaton infiltrate_(const std::vector< automaton > &as, vcsn::detail::index_sequence< I... >)
Variadic bridge helper.
void conjunction()
Compute the (accessible part of the) conjunction.
void initialize_conjunction()
Fill the worklist with the initial source-state pairs, as needed for the conjunction algorithm...
std::tuple< transition_map_t< Auts >... > transition_maps_
Transition caches.
automaton_t strip()
The automaton we decorate.
An exponent, or range of exponents.
void require(Bool b, Args &&... args)
If b is not verified, raise an error with args as message.
std::tuple< Auts... > automata_t
The type of input automata.
automaton shuffle_(const std::vector< automaton > &as, vcsn::detail::index_sequence< I... >)
Variadic bridge helper.
auto all_out(state_t s) const -> decltype(all_out(aut_, s))
All the outgoing 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.
const weightset_t & ws_
The resulting weightset.
typename Aut::element_type::template fresh_automaton_t< Context > fresh_automaton_t_of
Given an automaton type, the type of its copies.
zipped_maps< Dereference, Maps... > zip_map_tuple(const std::tuple< Maps... > &maps)
automaton conjunction_repeated(const automaton &aut, unsigned n)
Bridge (conjunction).
bool all(Bool &&... values)
Whether all the values evaluate as true.
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.
std::shared_ptr< detail::product_automaton_impl< Lazy, Aut, Auts... > > product_automaton
A product automaton as a shared pointer.
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)...