Vaucanson 1.4
eps_removal.hxx
00001 // eps_removal.hxx: this file is part of the Vaucanson project.
00002 //
00003 // Vaucanson, a generic library for finite state machines.
00004 //
00005 // Copyright (C) 2004, 2005, 2006, 2008, 2010, 2011 The Vaucanson Group.
00006 //
00007 // This program is free software; you can redistribute it and/or
00008 // modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2
00010 // of the License, or (at your option) any later version.
00011 //
00012 // The complete GNU General Public Licence Notice can be found as the
00013 // `COPYING' file in the root directory.
00014 //
00015 // The Vaucanson Group consists of people listed in the `AUTHORS' file.
00016 //
00017 #ifndef VCSN_ALGORITHMS_EPS_REMOVAL_HXX
00018 # define VCSN_ALGORITHMS_EPS_REMOVAL_HXX
00019 
00020 # include <vaucanson/algorithms/eps_removal.hh>
00021 
00022 # include <vaucanson/automata/concept/automata_base.hh>
00023 # include <vaucanson/algebra/concept/freemonoid_product.hh>
00024 # include <vaucanson/misc/usual_macros.hh>
00025 
00026 # include <list>
00027 # include <map>
00028 # include <utility>
00029 
00030 namespace vcsn {
00031 
00032   // For automata.
00033   template <class A, typename M, typename AI>
00034   bool
00035   do_is_proper(const AutomataBase<A>&, const M&, const Element<A, AI>& a)
00036   {
00037     BENCH_TASK_SCOPED("is_proper (automaton)");
00038     typedef Element<A, AI> automaton_t;
00039     AUTOMATON_TYPES(automaton_t);
00040 
00041     for_all_const_transitions(e, a)
00042       {
00043         // A transition labelled by "1+a" is not considered to be
00044         // spontaneous by is_spontaneous(), yet it cannot belong to a
00045         // proper automaton.
00046         series_set_elt_t label = a.series_of(*e);
00047         for_all_const_(series_set_elt_t::support_t, it, label.supp())
00048           if ((*it).empty())
00049             return false;
00050       }
00051     return true;
00052   }
00053 
00054   // For FMP.
00055   template <class A, typename F, typename S, typename AI>
00056   bool
00057   do_is_proper(const AutomataBase<A>&,
00058                const algebra::FreeMonoidProduct<F, S>&,
00059                const Element<A, AI>& a)
00060   {
00061     BENCH_TASK_SCOPED("is_proper (FMP)");
00062     typedef Element<A, AI> automaton_t;
00063     AUTOMATON_TYPES(automaton_t);
00064 
00065     for_all_const_transitions(e, a)
00066       {
00067         series_set_elt_t label = a.series_of(*e);
00068         for_all_const_(series_set_elt_t::support_t, it, label.supp())
00069           if ((*it).first.empty() && (*it).second.empty())
00070             return false;
00071       }
00072     return true;
00073   }
00074 
00075   template <typename A, typename AI>
00076   bool
00077   is_proper(const Element<A, AI>& a)
00078   {
00079     return do_is_proper(a.structure(), a.series().monoid(), a);
00080   }
00081 
00082 
00083   // Forward declaration.
00084   template <class A_, typename Auto, typename Weight>
00085   class EpsilonRemover;
00086 
00087   template <class A_, typename Auto, typename Weight, int>
00088   struct test_for_non_positive_semiring
00089   {
00090     bool run(const Auto&) const
00091     {
00092       return true;
00093     }
00094   };
00095 
00096   template <class A_, typename Auto, typename Weight>
00097   struct test_for_non_positive_semiring<A_, Auto, Weight, 0>
00098   {
00099     bool run(const Auto& a) const; // See After the EpsilonRemover declaration.
00100   };
00101 
00102   /*--------------------------------------.
00103   | EpsilonRemover for weighted automaton |
00104   `--------------------------------------*/
00105 
00106   template <class A_, typename Auto, typename Weight>
00107   class EpsilonRemover
00108   {
00109     AUTOMATON_TYPES(Auto);
00110         typedef typename series_set_elt_t::support_t support_t;
00111 
00112     friend struct test_for_non_positive_semiring
00113     <A_, Auto, Weight, semiring_traits<semiring_t,
00114                                        semiring_elt_value_t>::is_positive>;
00115 
00116 
00117     automaton_t&        a;
00118     // zero and identity of used algebraic structure.
00119     series_set_elt_t    null_series;
00120     semiring_elt_t      semiring_elt_zero,
00121       semiring_elt_unit;
00122     monoid_elt_t        monoid_identity;
00123 
00124 
00125   public:
00126     EpsilonRemover(const AutomataBase<A_>&,
00127                    Auto& aut)
00128       : a(aut),
00129         null_series(aut.series().zero_),
00130         semiring_elt_zero(aut.series().semiring().wzero_),
00131         semiring_elt_unit(aut.series().semiring().wone_),
00132         monoid_identity(aut.series().monoid().VCSN_EMPTY_)
00133     {}
00134 
00135     void operator()(misc::direction_type dir)
00136     {
00137       test_for_non_positive_semiring
00138         <A_, Auto, Weight, semiring_traits<semiring_t,
00139                                            semiring_elt_value_t>::is_positive>
00140         nps;
00141       result_not_computable_if(!nps.run(a));
00142       std::list<hstate_t> eps_states;
00143        if (dir == misc::backward)
00144         this->epsilon_covering(eps_states);
00145       else
00146         this->epsilon_co_covering(eps_states);
00147       result_not_computable_if(!spontaneous_suppression(eps_states));
00148       merge_transitions();
00149     }
00150 
00151     private:
00152 
00153         /* This method computes a covering of the automaton such
00154            that, in this covering, there are two kinds of states:
00155            -- states whose incoming transitions are not spontaneous;
00156            -- non initial states whose incoming transitions are spontaneous.
00157            The argument is filled with the states which belong to the second kind.
00158         */
00159     void epsilon_covering(std::list<hstate_t>& spontaneous_states)
00160     {
00161       //list of states to split
00162       std::list<hstate_t> split_states;
00163       for_all_states(s, a)
00164         {
00165           bool eps_in = false;
00166           bool other_in = a.is_initial(*s);
00167 
00168           // Test whether there are different types of incoming transitions.
00169 
00170           std::list<htransition_t> transitions;
00171           for (rdelta_iterator e(a.value(), *s); ! e.done(); e.next())
00172             transitions.push_back(*e);
00173           for_all_(std::list<htransition_t>, e, transitions)
00174             {
00175               series_set_elt_t t = a.series_of(*e);
00176               semiring_elt_t eps_weight= t.get(monoid_identity);
00177               if (eps_weight == semiring_elt_zero)
00178                 other_in = true ;
00179               else
00180                 {
00181                   eps_in=true;
00182                   if (t.supp().size() > 1)
00183                     other_in = true;
00184                 }
00185             }
00186           if (eps_in)
00187             {
00188               if (other_in)
00189                 split_states.push_back(*s);
00190               else
00191                 spontaneous_states.push_back(*s);
00192             }
00193         }
00194       //Split the states which have to
00195       for_all_(std::list<hstate_t>, s, split_states)
00196         {
00197           hstate_t eps_state = a.add_state();
00198           spontaneous_states.push_back(eps_state);
00199           //incoming transitions (the original state remains initial if it is)
00200           std::list<htransition_t> transitions;
00201           for (rdelta_iterator e(a.value(), *s); ! e.done(); e.next())
00202             transitions.push_back(*e);
00203           for_all_(std::list<htransition_t>, e, transitions)
00204             {
00205               series_set_elt_t t = a.series_of(*e);
00206               semiring_elt_t eps_weight= t.get(monoid_identity);
00207               if (eps_weight == semiring_elt_zero)
00208                 continue;
00209               series_set_elt_t eps_label(a.structure().series());
00210               eps_label.assoc(monoid_identity.value(), eps_weight.value());
00211               //which remains on the transition without epsilon:
00212               t.assoc(monoid_identity.value(), semiring_elt_zero.value());
00213               hstate_t source=a.src_of(*e);
00214               a.add_series_transition(source, eps_state, eps_label);
00215               if (t != null_series)
00216                 a.add_series_transition(source, *s, t);
00217               a.del_transition(*e);
00218             }
00219           //outgoing transitions and final states
00220           if (a.is_final(*s))
00221             a.set_final(eps_state,a.get_final(*s));
00222           for (delta_iterator e(a.value(), *s); ! e.done(); e.next())
00223             a.add_series_transition(eps_state, a.dst_of(*e), a.series_of(*e));
00224           /* Notice that if there is a loop on *s, with label a+1, the
00225              step "incoming transitions" turns it into a loop with
00226              label 'a' and a transition from *s to eps_state with
00227              label 1, and the step "outgoing transitions" build a
00228              transition from eps_state to *s with label '1' and a loop
00229              on eps_state with label 1, which is what it is
00230              expected */
00231         }
00232     }
00233 
00234     /* Initial and final cleaner. This method adds if necessary an
00235        initial and/or a final state such that series labelling initial
00236        and final arrows are constant. This method is presently unused.
00237     */
00238     void initial_final_cleaner()
00239     {
00240       {
00241         //Initial
00242         std::list<hstate_t> initial_states;
00243         for_all_initial_states(s, a)
00244           initial_states.push_back(*s);
00245         hstate_t new_initial=a.add_state();
00246         for_all_(std::list<hstate_t>, s, initial_states)
00247           {
00248             series_set_elt_t t = a.get_initial(*s);
00249             semiring_elt_t eps_weight= t.get(monoid_identity);
00250             t.assoc(monoid_identity, semiring_elt_zero.value());
00251             if (t != null_series)
00252               {
00253                 a.unset_initial(*s);
00254                 a.add_series_transition(new_initial, *s, t);
00255                 if (eps_weight != semiring_elt_zero)
00256                   {
00257                     series_set_elt_t cst(a.structure().series());
00258                     cst.assoc(monoid_identity, eps_weight.value());
00259                     a.set_initial(*s, cst);
00260                   }
00261               }
00262           }
00263         delta_iterator test(a.value(), new_initial);
00264         if (test.done())
00265           a.del_state(new_initial);
00266         else
00267           a.set_initial(new_initial);
00268       }
00269       {
00270         //Final
00271         std::list<hstate_t> final_states;
00272         for_all_final_states(s, a)
00273           final_states.push_back(*s);
00274         hstate_t new_final=a.add_state();
00275         for_all_(std::list<hstate_t>, s, final_states)
00276           {
00277             series_set_elt_t t = a.get_final(*s);
00278             semiring_elt_t eps_weight= t.get(monoid_identity);
00279             t.assoc(monoid_identity, semiring_elt_zero.value());
00280             if (t != null_series)
00281               {
00282                 a.unset_final(*s);
00283                 a.add_series_transition(*s, new_final, t);
00284                 if(eps_weight != semiring_elt_zero)
00285                   {
00286                     series_set_elt_t cst(a.structure().series());
00287                     cst.assoc(monoid_identity, eps_weight.value());
00288                     a.set_final(*s, cst);
00289                   }
00290               }
00291           }
00292         rdelta_iterator test(a.value(), new_final);
00293         if (test.done())
00294           a.del_state(new_final);
00295         else
00296           a.set_final(new_final);
00297       }
00298     }
00299 
00300     /* This method computes a co-covering of the automaton such
00301        that, in this co-covering, there are two kinds of states:
00302        -- states whose outgoing transitions are not spontaneous;
00303        -- non final states whose outgoing transitions are spontaneous.
00304        The argument is filled with the states which belong to the second kind.
00305     */
00306     void epsilon_co_covering(std::list<hstate_t>& spontaneous_states)
00307     {
00308       //list of states to split
00309       std::list<hstate_t> split_states;
00310       for_all_states(s, a)
00311         {
00312           bool eps_out = false;
00313           bool other_out = a.is_final(*s);
00314 
00315           // Test whether there are different types of outgoing transitions.
00316 
00317           std::list<htransition_t> transitions;
00318           for (delta_iterator e(a.value(), *s); !e.done(); e.next())
00319             transitions.push_back(*e);
00320           for_all_(std::list<htransition_t>, e, transitions)
00321             {
00322               series_set_elt_t t = a.series_of(*e);
00323               semiring_elt_t eps_weight= t.get(monoid_identity);
00324               if(eps_weight == semiring_elt_zero)
00325                 other_out=true ;
00326               else
00327                 {
00328                   eps_out=true;
00329                   if (t.supp().size() > 1)
00330                     other_out=true;
00331                 }
00332             }
00333           if (eps_out)
00334             {
00335               if (other_out)
00336                 split_states.push_back(*s);
00337               else
00338                 spontaneous_states.push_back(*s);
00339             }
00340         }
00341       //Split the states which have to
00342       for_all_(std::list<hstate_t>, s, split_states)
00343         {
00344           hstate_t eps_state = a.add_state();
00345           spontaneous_states.push_back(eps_state);
00346           //outgoing transitions (the original state remains final if it is)
00347           std::list<htransition_t> transitions;
00348           for (delta_iterator e(a.value(), *s); !e.done(); e.next())
00349             transitions.push_back(*e);
00350           for_all_(std::list<htransition_t>, e, transitions)
00351             {
00352               series_set_elt_t t = a.series_of(*e);
00353               semiring_elt_t eps_weight= t.get(monoid_identity);
00354               if (eps_weight == semiring_elt_zero)
00355                 continue;
00356               series_set_elt_t eps_label(a.structure().series());
00357               eps_label.assoc(monoid_identity.value(), eps_weight.value());
00358               //which remains on the transition without epsilon:
00359               t.assoc(monoid_identity.value(), semiring_elt_zero.value());
00360               hstate_t target=a.dst_of(*e);
00361               a.add_series_transition(eps_state, target, eps_label);
00362               if (t != null_series)
00363                 a.add_series_transition(*s, target, t);
00364               a.del_transition(*e);
00365             }
00366           //incoming transitions and initial states
00367           if (a.is_initial(*s))
00368             a.set_initial(eps_state,a.get_initial(*s));
00369           for (rdelta_iterator e(a.value(), *s); ! e.done(); e.next())
00370             a.add_series_transition(a.src_of(*e), eps_state, a.series_of(*e));
00371           /* Notice that if there is a loop on *s, with label a+1, the
00372              step "outgoing transitions" turns it into a loop with
00373              label 'a' and a transition from eps_state to *s with
00374              label 1, and the step "incoming transitions" build a
00375              transition from *s to eps_state with label '1' and a loop
00376              on eps_state with label 1, which is what it is
00377              expected */
00378         }
00379     }
00380 
00381     /* This method computes an equivalent K-automaton with only
00382        positive transitions (excepted final arrows).  A second copy of
00383        the automaton is built, a negative weight makes switch from a
00384        copy to another.  Two final states are added, one where
00385        positive paths end, the other one where negative paths end. In
00386        the result, all the edges have positive weight; the two final
00387        states have resp.  weights equal to 1 and -1.
00388     */
00389         void positive_path_covering()
00390         {
00391           std::map<hstate_t,hstate_t> clones;
00392           std::list<hstate_t> states;
00393           for_all_states(s, a)
00394             states.push_back(*s);
00395           for_all_(std::list<hstate_t>, s, states)
00396             clones[*s]=a.add_state();
00397           hstate_t pos_final_state=a.add_state();
00398           hstate_t neg_final_state=a.add_state();
00399           std::list<htransition_t> transitions;
00400           for_all_transitions(e, a)
00401              transitions.push_back(*e);
00402           for_all_(std::list<htransition_t>, e, transitions)
00403           {
00404             series_set_elt_t posit = a.series_of(*e);
00405             series_set_elt_t negat(a.structure().series());
00406             support_t su = posit.supp();
00407             for_all_(support_t, x, su)
00408                 {
00409                   semiring_elt_t weight=posit.get(*x);
00410                   if (weight < semiring_elt_zero)
00411                         {
00412                           negat.assoc(*x,-weight.value());
00413                           posit.assoc(*x,semiring_elt_zero.value());
00414                         }
00415                 }
00416           hstate_t src=a.src_of(*e), dst=a.dst_of(*e);
00417           if (posit != null_series)
00418                 a.add_series_transition(clones[src], clones[dst], posit);
00419           if (negat != null_series)
00420                 {
00421                   a.add_series_transition(src, clones[dst], negat);
00422                   a.add_series_transition(clones[src], dst, negat);
00423                   if (posit != null_series)
00424                 a.add_series_transition(src, dst, posit);
00425                   a.del_transition(*e);
00426                 }
00427         }
00428           states.clear();
00429           for_all_initial_states(s, a)
00430         states.push_back(*s);
00431           for_all_(std::list<hstate_t>, s, states)
00432         {
00433           series_set_elt_t posit = a.get_initial(*s);
00434           series_set_elt_t negat(a.structure().series());
00435           support_t su = posit.supp();
00436           for_all_(support_t, x, su)
00437                 {
00438                   semiring_elt_t weight = posit.get(*x);
00439                   if (weight < semiring_elt_zero)
00440                         {
00441                           negat.assoc(*x,-weight.value());
00442                           posit.assoc(*x,semiring_elt_zero.value());
00443                         }
00444                 }
00445           if (negat != null_series)
00446                 {
00447                   a.set_initial(clones[*s], negat);
00448                   a.unset_initial(*s);
00449                   if (posit != null_series)
00450                 a.set_initial(*s,posit);
00451                 }
00452         }
00453           states.clear();
00454           for_all_final_states(s, a)
00455         states.push_back(*s);
00456           for_all_(std::list<hstate_t>, s, states)
00457         {
00458           series_set_elt_t posit = a.get_final(*s);
00459           series_set_elt_t negat(a.structure().series());
00460           support_t su = posit.supp();
00461           for_all_(support_t, x, su)
00462                 {
00463                   semiring_elt_t weight=posit.get(*x);
00464                   if (weight < semiring_elt_zero)
00465                         {
00466                           negat.assoc(*x,-weight.value());
00467                           posit.assoc(*x,semiring_elt_zero.value());
00468                         }
00469                 }
00470           if (negat != null_series)
00471                 {
00472                   a.add_series_transition(*s, neg_final_state, negat);
00473                   a.add_series_transition(clones[*s], pos_final_state, negat);
00474                 }
00475           a.unset_final(*s);
00476           if (posit != null_series)
00477                 {
00478                   a.add_series_transition(*s, pos_final_state, posit);
00479                   a.add_series_transition(clones[*s], neg_final_state, posit);
00480                 }
00481         }
00482           a.set_final(pos_final_state);
00483           series_set_elt_t mss = a.get_final(pos_final_state);
00484           mss.assoc(monoid_identity,-semiring_elt_unit.value());
00485           a.set_final(neg_final_state,mss);
00486           accessible_here(a);
00487         }
00488 
00489     /* This method makes every weight in the K-automaton positive
00490     */
00491         void absolute_weight()
00492         {
00493           std::list<htransition_t> transitions;
00494           for_all_transitions(e, a)
00495              transitions.push_back(*e);
00496           for_all_(std::list<htransition_t>, e, transitions)
00497           {
00498             series_set_elt_t label = a.series_of(*e);
00499             support_t support = label.supp();
00500             for_all_(support_t, x, support)
00501                 {
00502                   semiring_elt_t weight=label.get(*x);
00503                   if (weight < semiring_elt_zero) 
00504                           label.assoc(*x,-weight.value());
00505                 }
00506           hstate_t src=a.src_of(*e), dst=a.dst_of(*e);
00507           a.del_transition(*e);
00508           a.add_series_transition(src, dst, label);
00509           }
00510           std::list<hstate_t> states;
00511           for_all_initial_states(s, a)
00512         states.push_back(*s);
00513           for_all_(std::list<hstate_t>, s, states)
00514           {
00515           series_set_elt_t label = a.get_initial(*s);
00516           support_t support = label.supp();
00517           for_all_(support_t, x, support)
00518                 {
00519                   semiring_elt_t weight = label.get(*x);
00520                   if (weight < semiring_elt_zero)
00521                           label.assoc(*x,-weight.value());
00522                 }
00523                 a.set_initial(*s,label);
00524       }
00525           states.clear();
00526           for_all_final_states(s, a)
00527         states.push_back(*s);
00528           for_all_(std::list<hstate_t>, s, states)
00529         {
00530           series_set_elt_t label = a.get_final(*s);
00531           support_t support = label.supp();
00532           for_all_(support_t, x, support)
00533                 {
00534                   semiring_elt_t weight = label.get(*x);
00535                   if (weight < semiring_elt_zero)
00536                           label.assoc(*x,-weight.value());
00537                 }
00538                 a.set_final(*s,label);
00539         }
00540         }
00541         
00542     /*supression of "epsilon-states"
00543       epsilon_covering should have been called before
00544       This part of the algorithm is symmetrical and is exactly
00545       the "elimination state method" applicated to a list of states.
00546       We consider the case where the state is initial or final, even if
00547       in the backward case the 'epsilon state' cannot be initial for instance
00548      */
00549     bool spontaneous_suppression(std::list<hstate_t>& sp_states)
00550     {
00551       for_all_(std::list<hstate_t>, s, sp_states)
00552         {
00553           std::list<htransition_t> incoming_transitions;
00554           //list of incoming transitions, beginning with loops
00555           for (rdelta_iterator e(a.value(), *s); ! e.done(); e.next())
00556             {
00557               if (a.src_of(*e) == a.dst_of(*e))
00558                 incoming_transitions.push_front(*e);
00559               else
00560                 incoming_transitions.push_back(*e);
00561             }
00562           bool hasloop=false;
00563           series_set_elt_t loop_series(a.structure().series());
00564           //loops are removed from incoming transitions;
00565           while (!incoming_transitions.empty())
00566             {
00567               htransition_t& loop=incoming_transitions.front();
00568               if(a.src_of(loop)==a.dst_of(loop))
00569                 {
00570                   hasloop=true;
00571                   loop_series += a.series_of(loop);
00572                   incoming_transitions.pop_front();
00573                 }
00574               else
00575                 break;
00576             }
00577           if (hasloop)
00578             {
00579               if (!loop_series.get(monoid_identity).starable())
00580                 return false;
00581               loop_series = loop_series.star();
00582             }
00583           std::list<htransition_t> outgoing_transitions;
00584           for (delta_iterator e(a.value(), *s); ! e.done(); e.next())
00585               if (a.src_of(*e)!=a.dst_of(*e))
00586                 outgoing_transitions.push_back(*e);
00587           for_all_(std::list<htransition_t>, e, incoming_transitions)
00588             for_all_(std::list<htransition_t>, f, outgoing_transitions)
00589               if (hasloop)
00590                 a.add_series_transition(a.src_of(*e), a.dst_of(*f),
00591                                         a.series_of(*e)*loop_series*a.series_of(*f));
00592               else
00593                 a.add_series_transition(a.src_of(*e), a.dst_of(*f),
00594                                         a.series_of(*e)*a.series_of(*f));
00595           if (a.is_final(*s))
00596             {
00597               series_set_elt_t final_s = a.get_final(*s);
00598               for_all_(std::list<htransition_t>, e, incoming_transitions)
00599                 {
00600                   hstate_t p = a.src_of(*e);
00601                   series_set_elt_t t = a.get_final(p);
00602                   if (hasloop)
00603                     t += a.series_of(*e)*loop_series*final_s;
00604                   else
00605                     t += a.series_of(*e)*final_s;
00606                   a.unset_final(p);
00607                   if (t != null_series)
00608                     a.set_final(p,t);
00609                 }
00610             }
00611           if (a.is_initial(*s))
00612             {
00613               series_set_elt_t initial_s=a.get_initial(*s);
00614               for_all_(std::list<htransition_t>, f, outgoing_transitions)
00615                 {
00616                   hstate_t p = a.dst_of(*f);
00617                   series_set_elt_t t = a.get_initial(p);
00618                   if (hasloop)
00619                     t += initial_s*loop_series*a.series_of(*f);
00620                   else
00621                     t += initial_s*a.series_of(*f);
00622                   a.unset_initial(p);
00623                   if (t != null_series)
00624                     a.set_initial(p,t);
00625                 }
00626             }
00627           a.del_state(*s);
00628         }
00629       return true;
00630     }
00631 
00632     //merge transitions with the same ends
00633     void merge_transitions()
00634     {
00635       typedef std::map<hstate_t, series_set_elt_t> map_t;
00636       for_all_states(s, a)
00637         {
00638           map_t map;
00639           std::list<htransition_t> transitions;
00640           for (delta_iterator e(a.value(), *s); ! e.done(); e.next())
00641             {
00642               hstate_t target = a.dst_of(*e);
00643               transitions.push_back(*e);
00644               typename map_t::iterator it = map.find(target);
00645               if (it == map.end())
00646                 map.insert(std::pair<hstate_t, series_set_elt_t>(target,
00647                                                                  a.series_of(*e)));
00648               else
00649                 it->second += a.series_of(*e);
00650             }
00651           for_all_(std::list<htransition_t>, e, transitions)
00652             a.del_transition(*e);
00653           for_all_(map_t, it, map)
00654             if(it->second != null_series)
00655                     a.add_series_transition(*s, it->first, it->second);
00656         }
00657     }
00658 
00659   };
00660 
00661 
00662   template <class A_, typename Auto, typename Weight>
00663   bool test_for_non_positive_semiring<A_, Auto, Weight, 0>::run(const Auto& a) const
00664   {
00665     AUTOMATON_TYPES(Auto);
00666 
00667     std::list<hstate_t> eps_states;
00668     automaton_t test(a);
00669     EpsilonRemover<A_, Auto, Weight> epsTest(test.structure(), test);
00670     epsTest.absolute_weight();
00671     epsTest.epsilon_covering(eps_states);
00672     return epsTest.spontaneous_suppression(eps_states);
00673   }
00674 
00675 
00676 
00677 
00678   /*--------------.
00679     | eps_removal.  |
00680     `--------------*/
00681 
00682   template<class A_, typename Auto, typename Weight>
00683   void
00684   do_eps_removal_here(const AutomataBase<A_>& a_set,
00685                       const Weight&,
00686                       Auto& a,
00687                       misc::direction_type dir)
00688   {
00689     BENCH_TASK_SCOPED("eps_removal");
00690     AUTOMATON_TYPES(Auto);
00691     EpsilonRemover<A_, Auto, Weight> algo(a_set, a);
00692     algo(dir);
00693   }
00694 
00695   template<typename  A, typename  AI>
00696   void
00697   eps_removal_here(Element<A, AI>& a, misc::direction_type dir)
00698   {
00699     typedef Element<A, AI> automaton_t;
00700     AUTOMATON_TYPES(automaton_t);
00701 
00702     do_eps_removal_here(a.structure(),
00703                         SELECT(semiring_elt_value_t),
00704                         a, dir);
00705   }
00706 
00707   template<typename  A, typename  AI>
00708   Element<A, AI>
00709   eps_removal(const Element<A, AI>& a, misc::direction_type dir)
00710   {
00711     typedef Element<A, AI> automaton_t;
00712     AUTOMATON_TYPES(automaton_t);
00713 
00714     automaton_t ret(a);
00715     do_eps_removal_here(ret.structure(),
00716                         SELECT(semiring_elt_value_t),
00717                         ret, dir);
00718     return ret;
00719   }
00720 
00721   template<typename  A, typename  AI>
00722   void
00723   backward_eps_removal_here(Element<A, AI>& a)
00724   {
00725     typedef Element<A, AI> automaton_t;
00726     AUTOMATON_TYPES(automaton_t);
00727 
00728     do_eps_removal_here(a.structure(),
00729                         SELECT(semiring_elt_value_t),
00730                         a, misc::backward);
00731   }
00732 
00733   template<typename  A, typename  AI>
00734   Element<A, AI>
00735   backward_eps_removal(const Element<A, AI>& a)
00736   {
00737     typedef Element<A, AI> automaton_t;
00738     AUTOMATON_TYPES(automaton_t);
00739 
00740     automaton_t ret(a);
00741     do_eps_removal_here(ret.structure(),
00742                         SELECT(semiring_elt_value_t),
00743                         ret, misc::backward);
00744     return ret;
00745   }
00746 
00747   template<typename  A, typename  AI>
00748   void
00749   forward_eps_removal_here(Element<A, AI>& a)
00750   {
00751     typedef Element<A, AI> automaton_t;
00752     AUTOMATON_TYPES(automaton_t);
00753 
00754     do_eps_removal_here(a.structure(),
00755                         SELECT(semiring_elt_value_t),
00756                         a, misc::forward);
00757   }
00758 
00759   template<typename  A, typename  AI>
00760   Element<A, AI>
00761   forward_eps_removal(const Element<A, AI>& a)
00762   {
00763     typedef Element<A, AI> automaton_t;
00764     AUTOMATON_TYPES(automaton_t);
00765 
00766     automaton_t ret(a);
00767     do_eps_removal_here(ret.structure(),
00768                         SELECT(semiring_elt_value_t),
00769                         ret, misc::forward);
00770     return ret;
00771   }
00772 
00773 } // vcsn
00774 
00775 #endif // ! VCSN_ALGORITHMS_EPS_REMOVAL_HXX