Vaucanson 1.4
universal.hxx
00001 // universal.hxx: this file is part of the Vaucanson project.
00002 //
00003 // Vaucanson, a generic library for finite state machines.
00004 //
00005 // Copyright (C) 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_UNIVERSAL_HXX
00018 # define VCSN_ALGORITHMS_UNIVERSAL_HXX
00019 
00020 
00021 # include <map>
00022 # include <set>
00023 
00024 # include <vaucanson/boolean_automaton.hh>
00025 # include <vaucanson/algorithms/determinize.hh>
00026 # include <vaucanson/algorithms/transpose.hh>
00027 # include <vaucanson/algorithms/complete.hh>
00028 
00029 # include <vaucanson/misc/usual_macros.hh>
00030 
00031 namespace vcsn {
00032 
00033   namespace universal_internal {
00034 
00035     // Returns the intersection of two sets.
00036     template<typename Set>
00037     Set intersection_structure(const Set& set1, const Set& set2)
00038     {
00039       Set tmp;
00040       std::insert_iterator<Set> i(tmp, tmp.begin());
00041       std::set_intersection(set1.begin(), set1.end(),
00042                             set2.begin(), set2.end(),
00043                             i);
00044       return tmp;
00045     }
00046 
00047     // A simple intersection closure.
00048     template<typename Set>
00049     std::set<Set> intersection_closure(const std::set<Set>& s)
00050     {
00051       std::set<Set> tmp = s;
00052       std::set<Set> ret = s;
00053 
00054       do {
00055         std::swap(ret, tmp);
00056         for_all_const_(std::set<Set>, s1, tmp)
00057           for_all_const_(std::set<Set>, s2, tmp)
00058           ret.insert(intersection_structure(*s1, *s2));
00059       } while (ret.size() != tmp.size());
00060       return ret;
00061     }
00062 
00063     // Return the image of a map.
00064     template<typename K, typename V>
00065     std::set<V> image(const std::map<K,V>& m)
00066     {
00067       std::set<V> ret;
00068       for(typename std::map<K,V>::const_iterator a=m.begin(); a!= m.end(); ++a)
00069         ret.insert(a->second);
00070       return ret;
00071     }
00072 
00073     // Return true if a set1 \subset set2.
00074     template <class Container1, class Container2>
00075     bool includes(const Container1& set1, const Container2& set2)
00076     {
00077       return std::includes(set2.begin(), set2.end(),
00078                            set1.begin(), set1.end());
00079     }
00080   } //univeral_internal
00081 
00082 
00083 // And now, the algorithm:
00084   template<typename A, typename AI>
00085   void do_universal(const AutomataBase<A>&,
00086                     const Element<A,AI>& a,
00087                     Element<A,AI>& u)
00088   {
00089     typedef Element<A, AI> Auto;
00090     AUTOMATON_TYPES(Auto);
00091     AUTOMATON_FREEMONOID_TYPES(Auto);
00092 
00093     typedef std::set<std::set<hstate_t> >               pstate_t;
00094     typedef std::set<hstate_t>                  state_set_t;
00095     typedef std::map<hstate_t, state_set_t>     map_t;
00096 
00097     using namespace universal_internal;
00098 
00099     Auto automaton(a);
00100 
00101     if(!is_deterministic(automaton))
00102       automaton = determinize(automaton);
00103     if(!is_complete(automaton))
00104       automaton = complete(automaton);
00105 
00106 
00107     // let i, be the initial state of automaton.
00108     hstate_t i = *automaton.initial().begin();
00109 
00110     // compute the co-determinized of the minimal automaton
00111     // and retrieve the origin of each state.
00112     map_t origin;
00113     Auto transposed = transpose(automaton);
00114     Auto co_det = determinize(transposed, origin);
00115 
00116     // the 'origin' is a map from co_det's hstate_t to
00117     // minimal's std::set<hstate_t>.
00118     // let 'transp_states' be the image of 'origin'.
00119     pstate_t transp_states = image(origin);
00120 
00121     // the universal automaton's state set is its intersection closure.
00122     pstate_t univers_states(intersection_closure(transp_states));
00123 
00124     // we have to save the state set associated to each automaton.
00125     map_t subset_label;
00126 
00127     // X = univers_states \ {}.
00128     for_all_const_(pstate_t, s, univers_states)
00129       if (s->size() != 0)
00130       {
00131         hstate_t new_s = u.add_state();
00132         subset_label[new_s] = *s;
00133         // J = { X | i in X }
00134         if (s->find(i) != s->end())
00135           u.set_initial(new_s);
00136         // U = { X | X \subset T }
00137         if (includes(*s, automaton.final()))
00138           u.set_final(new_s);
00139       }
00140 
00141     // finally, the transition set.
00142     for_all_states(x, u)
00143       for_all_states(y, u)
00144       for_all_letters(a, u.series().monoid().alphabet())
00145     {
00146       bool cont = false;
00147       std::set<hstate_t> delta_ret;
00148       for_all_const_(state_set_t, s, subset_label[*x])
00149       {
00150         bool empty = true;
00151         // FIXME: bmig complains "Assertion failed: has_state(s)" for
00152         // the line below.
00153         for (typename automaton_t::delta_iterator dst(automaton.value(), *s);
00154              ! dst.done(); dst.next())
00155         {
00156           monoid_elt_t w(automaton.series_of(*dst).structure().monoid(), *a);
00157           if (automaton.series_of(*dst).get(w)
00158               != automaton.series().semiring().wzero_)
00159           {
00160             empty = false;
00161             delta_ret.insert(automaton.dst_of(*dst));
00162           }
00163         }
00164         if (empty)
00165         {
00166           cont = true;
00167           break;
00168         }
00169       }
00170       // case 1: \exists p \in X, p.a = {}
00171       if (cont)
00172         continue;
00173       // case 2: X.a \subset Y ?
00174       if (includes(delta_ret, subset_label[*y]))
00175         u.add_letter_transition(*x, *y, *a);
00176     }
00177   }
00178 
00179   template<typename  A, typename  AI>
00180   Element<A, AI>
00181   universal(const Element<A, AI>& a)
00182   {
00183     precondition(is_realtime(a));
00184 
00185     Element<A, AI> ret(a.structure());
00186     do_universal(a.structure(), a, ret);
00187     return ret;
00188   }
00189 
00190 } // vcsn
00191 #endif // !VCSN_ALGORITHMS_UNIVERSAL_HXX