1 #ifndef VCSN_ALGOS_PROPER_HH
2 # define VCSN_ALGOS_PROPER_HH
5 # include <type_traits>
6 # include <unordered_map>
7 # include <unordered_set>
11 # include <boost/lexical_cast.hpp>
12 # include <boost/heap/fibonacci_heap.hpp>
16 # include <vcsn/algos/fwd.hh>
37 if (
auto cp = getenv(
"VCSN_DEBUG"))
38 return *cp ? boost::lexical_cast<
int>(cp) : 1;
47 template <
typename Aut,
54 using weight_t =
typename weightset_t::value_t;
66 ,
ws_(*aut->weightset())
88 proper_here_<weightset_t::star_status()>(aut, prune);
130 catch (
const std::runtime_error&)
164 size_t insp,
size_t in,
165 size_t outsp,
size_t out)
172 size_t outsp,
size_t out)
214 aut_->all_out(s).size());
221 for (
auto s:
aut_->states())
226 auto in =
aut_->in(s).size();
228 auto out =
aut_->all_out(s).size();
230 {s, in_sp, in, out_sp, out});
238 const char* sep =
"";
239 for (
auto i =
todo_.ordered_begin(), end =
todo_.ordered_end();
242 std::cerr << sep << *i;
253 std::cerr <<
"update heap (" << s <<
" : ";
258 todo_.update(i->second);
261 std::cerr <<
") => ";
263 std::cerr << std::endl;
304 using state_weight_t = std::pair<state_t, weight_t>;
305 std::vector<state_weight_t> closure;
306 for (
auto t : transitions)
311 star =
ws_.star(weight);
313 closure.emplace_back(src, weight);
315 aut_->del_transition(t);
332 for (
auto t:
aut_->all_out(s))
338 aut_->set_weight(t, blow);
342 for (
auto pair: closure)
346 aut_->add_transition(src, dst, label, w);
350 unsigned added =
aut_->all_out(s).size() * closure.size();
351 unsigned removed = transitions.size();
356 removed +=
aut_->all_out(s).size();
364 std::cerr <<
" -" << removed <<
"+" << added
391 std::unordered_set<state_t> neighbors;
392 while (!
todo_.empty())
396 std::cerr <<
"Before: ";
398 std::cerr << std::endl;
400 auto p =
todo_.top();
403 std::cerr <<
"Remove: " << p;
408 for (
auto t:
aut_->in(s))
412 neighbors.emplace(n);
414 for (
auto t:
aut_->out(s))
418 neighbors.emplace(n);
424 for (
auto n: neighbors)
426 for (
auto n: neighbors)
429 std::cerr <<
" #tr: "
431 <<
"/" <<
aut_->num_transitions() << std::endl;
434 std::cerr <<
"After: ";
436 std::cerr << std::endl;
439 dot(
aut_, std::cerr) << std::endl;
441 std::cerr << std::endl;
445 std::cerr <<
"Total transitions -" <<
removed_
446 <<
"+" <<
added_ << std::endl;
451 template <star_status_t Status>
453 typename std::enable_if<Status == star_status_t::TOPS>::type
457 raise(
"invalid automaton");
462 template <star_status_t Status>
464 typename std::enable_if<Status == star_status_t::ABSVAL>::type
472 template <star_status_t Status>
474 typename std::enable_if<Status == star_status_t::STARRABLE>::type
484 template <star_status_t Status>
486 typename std::enable_if<Status == star_status_t::NON_STARRABLE>::type
504 using heap_t = boost::heap::fibonacci_heap<state_profile>;
507 std::unordered_map<state_t, typename heap_t::handle_type>
handles_;
518 template <
typename Aut>
540 template <
typename Aut>
549 template <
typename Aut>
561 using tr_aut_t = decltype(tr_aut);
574 template <
typename LabelSet>
578 static std::shared_ptr<const type>
579 value(
const std::shared_ptr<const LabelSet>& ls)
585 template <
typename LabelSet>
589 static std::shared_ptr<const type>
592 return ls->labelset();
597 template <
typename LabelSet,
typename WeightSet>
603 std::shared_ptr<const typename proper_labelset::type> ls
605 std::shared_ptr<const WeightSet> ws = ctx.weightset();
611 template <
typename Aut>
632 template <
typename Aut,
typename Dir,
typename Bool>
635 const auto& a = aut->as<Aut>();
648 #endif // !VCSN_ALGOS_PROPER_HH
typename weightset_t::value_t weight_t
static constexpr void proper_here(automaton_t &, bool=true)
static std::enable_if< Status==star_status_t::ABSVAL >::type proper_here_(automaton_t &aut, bool prune=true)
ABSVAL: valid iff proper succeeds on the "absolute value" of the automaton.
static std::enable_if< Status==star_status_t::TOPS >::type proper_here_(automaton_t &aut, bool=true)
TOPS: valid iff proper succeeds.
void show_heap_() const
Show the heap, for debugging.
mutable_automaton< Context > make_mutable_automaton(const Context &ctx)
size_t out_sp
Number of outgoing spontaneous transitions.
automaton proper(const automaton &aut, direction dir, bool prune)
Bridge.
REGISTER_DECLARE(accessible,(const automaton &) -> automaton)
std::shared_ptr< detail::automaton_base > automaton
static int debug_level()
Debug level set in the user's environment.
transition_t_of< automaton_t > transition_t
typename detail::labelset_t_of_impl< base_t< ValueSet >>::type labelset_t_of
typename std::remove_cv< Aut >::type automaton_t
From a labelset, its non-nullable labelset.
size_t out_nsp
Number of outgoing non-spontaneous transitions.
auto proper(const Aut &aut, direction dir=direction::backward, bool prune=true) -> mutable_automaton< decltype(proper_context(copy(aut) ->context()))>
Eliminate spontaneous transitions.
properer(automaton_t &aut, bool prune=true)
Get ready to eliminate spontaneous transitions.
int debug_
Debug level. The higher, the more details are reported.
auto proper_context(const context< LabelSet, WeightSet > &ctx) -> context< typename proper_labelset< LabelSet >::type, WeightSet >
From a context, its non-nullable context.
void in_situ_remover_()
Remove all the states with incoming spontaneous transitions.
Implementation of labels are nullables (letter or empty).
std::shared_ptr< const detail::weight_base > weight
pair_automaton< Aut > pair(const Aut &aut, bool keep_initials=false)
automaton make_automaton(const Aut &aut)
Build a dyn::automaton.
std::shared_ptr< detail::mutable_automaton_impl< Context >> mutable_automaton
bool is_valid(const Aut &aut)
state_profile * profile(state_t s)
void build_heap_()
Build the profiles and the heap for states with incoming spontaneous transitions. ...
bool in_situ_remover(Aut &aut, bool prune=true)
Blindly eliminate epsilon transitions without checking for the validity of the automaton.
friend std::ostream & operator<<(std::ostream &o, const state_profile &p)
void in_situ_remover_(state_t s)
For each state (s), for each incoming epsilon-transitions (t), if (t) is a loop, the star of its weig...
void update_heap_(state_t s)
Update the heap for s.
bool is_proper(const Aut &aut)
Test whether an automaton is proper.
AutOut copy(const AutIn &input, Pred keep_state)
A copy of input keeping only its states that are accepted by keep_state.
std::vector< transition_t > transitions_t
void proper_here(Aut &aut, direction dir=direction::backward, bool prune=true)
Eliminate spontaneous transitions in place.
automaton_t & aut_
The automaton we work on.
typename detail::label_t_of_impl< base_t< ValueSet >>::type label_t_of
typename detail::weightset_t_of_impl< base_t< ValueSet >>::type weightset_t_of
label_t_of< automaton_t > label_t
static std::enable_if< Status==star_status_t::NON_STARRABLE >::type proper_here_(automaton_t &aut, bool prune=true)
NON_STARRABLE: valid iff there is no epsilon-circuit with weight zero.
static std::shared_ptr< const type > value(const std::shared_ptr< const nullableset< LabelSet >> &ls)
This class contains the core of the proper algorithm.
state_t_of< automaton_t > state_t
weightset_t_of< automaton_t > weightset_t
size_t num_eps_transitions(const Aut &)
typename detail::transition_t_of_impl< base_t< ValueSet >>::type transition_t_of
std::shared_ptr< const detail::label_base > label
size_t in_nsp
Number of incoming non-spontaneous transitions.
Provide a variadic mul on top of a binary mul(), and one().
std::shared_ptr< const detail::context_base > context
state_profile(state_t s, size_t insp, size_t in, size_t outsp, size_t out)
Generate a state profile.
const weightset_t & ws_
Shorthand to the weightset.
state_t state
From the heap's top, recover state to eliminate.
static void proper_here(automaton_t &aut, bool prune=true)
Remove the epsilon-transitions of the input.
Aut transpose(const transpose_automaton< Aut > &aut)
static std::enable_if< Status==star_status_t::STARRABLE >::type proper_here_(automaton_t &aut, bool prune=true)
STARRABLE: always valid.
bool prune_
Whether to prune states that become inaccessible.
void copy_into(const AutIn &in, AutOut &out, Pred keep_state)
Copy an automaton.
std::unordered_map< state_t, typename heap_t::handle_type > handles_
Map: state -> heap-handle.
bool operator<(const state_profile &r) const
Whether l < r for the max-heap.
typename std::remove_cv< Aut >::type automaton_t
static std::shared_ptr< const type > value(const std::shared_ptr< const LabelSet > &ls)
typename detail::state_t_of_impl< base_t< ValueSet >>::type state_t_of
boost::heap::fibonacci_heap< state_profile > heap_t
Max-heap to decide the order of state-elimination.
void update(size_t insp, size_t in, size_t outsp, size_t out)
size_t in_sp
Number of incoming spontaneous transitions.
label_t empty_word_
Shorthand to the empty word.
Data needed to compare the elimination order between states.
std::ostream & dot(const Aut &aut, std::ostream &out, bool dot2tex=false)
static bool in_situ_remover(automaton_t &aut, bool prune=true)
The core of the (backward) epsilon-removal.
void update_profile_(state_t s)
Update the profile of s.
void require(bool b, Args &&...args)
If b is not verified, raise an error with args as message.