Generated on Thu Apr 11 13:59:08 2019 for Gecode by doxygen 1.6.3

dfa.cpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Christian Schulte <schulte@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Christian Schulte, 2004
00008  *
00009  *  This file is part of Gecode, the generic constraint
00010  *  development environment:
00011  *     http://www.gecode.org
00012  *
00013  *  Permission is hereby granted, free of charge, to any person obtaining
00014  *  a copy of this software and associated documentation files (the
00015  *  "Software"), to deal in the Software without restriction, including
00016  *  without limitation the rights to use, copy, modify, merge, publish,
00017  *  distribute, sublicense, and/or sell copies of the Software, and to
00018  *  permit persons to whom the Software is furnished to do so, subject to
00019  *  the following conditions:
00020  *
00021  *  The above copyright notice and this permission notice shall be
00022  *  included in all copies or substantial portions of the Software.
00023  *
00024  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00025  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00026  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00027  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00028  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00029  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00030  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00031  *
00032  */
00033 
00034 #include <gecode/int.hh>
00035 
00036 namespace Gecode { namespace Int { namespace Extensional {
00037 
00041   class TransByI_State {
00042   public:
00043     forceinline bool
00044     operator ()(const DFA::Transition& x, const DFA::Transition& y) {
00045       return x.i_state < y.i_state;
00046     }
00047     forceinline static void
00048     sort(DFA::Transition t[], int n) {
00049       TransByI_State tbis;
00050       Support::quicksort<DFA::Transition,TransByI_State>(t,n,tbis);
00051     }
00052   };
00053 
00057   class TransBySymbol {
00058   public:
00059     forceinline bool
00060     operator ()(const DFA::Transition& x, const DFA::Transition& y) {
00061       return x.symbol < y.symbol;
00062     }
00063     forceinline static void
00064     sort(DFA::Transition t[], int n) {
00065       TransBySymbol tbs;
00066       Support::quicksort<DFA::Transition,TransBySymbol>(t,n,tbs);
00067     }
00068   };
00069 
00073   class TransBySymbolI_State {
00074   public:
00075     forceinline bool
00076     operator ()(const DFA::Transition& x, const DFA::Transition& y) {
00077       return ((x.symbol < y.symbol) ||
00078               ((x.symbol == y.symbol) && (x.i_state < y.i_state)));
00079     }
00080     forceinline static void
00081     sort(DFA::Transition t[], int n) {
00082       TransBySymbolI_State tbsi;
00083       Support::quicksort<DFA::Transition,TransBySymbolI_State>(t,n,tbsi);
00084     }
00085   };
00086 
00090   class TransByO_State {
00091   public:
00092     forceinline bool
00093     operator ()(const DFA::Transition& x, const DFA::Transition& y) {
00094       return x.o_state < y.o_state;
00095     }
00096     forceinline static void
00097     sort(DFA::Transition t[], int n) {
00098       TransByO_State tbos;
00099       Support::quicksort<DFA::Transition,TransByO_State>(t,n,tbos);
00100     }
00101   };
00102 
00103 
00107   class StateGroup {
00108   public:
00109     int state;
00110     int group;
00111   };
00112 
00116   class StateGroupByGroup {
00117   public:
00118     forceinline bool
00119     operator ()(const StateGroup& x, const StateGroup& y) {
00120       return ((x.group < y.group) ||
00121               ((x.group == y.group) && (x.state < y.state)));
00122     }
00123     static void
00124     sort(StateGroup sg[], int n) {
00125       StateGroupByGroup o;
00126       Support::quicksort<StateGroup,StateGroupByGroup>(sg,n,o);
00127     }
00128   };
00129 
00133   class GroupStates {
00134   public:
00135     StateGroup* fst;
00136     StateGroup* lst;
00137   };
00138 
00140   enum StateInfo {
00141     SI_NONE       = 0, 
00142     SI_FROM_START = 1, 
00143     SI_TO_FINAL   = 2, 
00144     SI_FINAL      = 4  
00145   };
00146 
00147 }}}
00148 
00149 namespace Gecode {
00150 
00151   void
00152   DFA::init(int start, Transition t_spec[], int f_spec[], bool minimize) {
00153     using namespace Int;
00154     using namespace Extensional;
00155     Region region;
00156 
00157     // Compute number of states and transitions
00158     int n_states = start;
00159     int n_trans  = 0;
00160     for (Transition* t = &t_spec[0]; t->i_state >= 0; t++) {
00161       n_states = std::max(n_states,t->i_state);
00162       n_states = std::max(n_states,t->o_state);
00163       n_trans++;
00164     }
00165     for (int* f = &f_spec[0]; *f >= 0; f++)
00166       n_states = std::max(n_states,*f);
00167     n_states++;
00168 
00169     // Temporary structure for transitions
00170     Transition* trans = region.alloc<Transition>(n_trans);
00171     for (int i=0; i<n_trans; i++)
00172       trans[i] = t_spec[i];
00173     // Temporary structures for finals
00174     int* final = region.alloc<int>(n_states+1);
00175     bool* is_final = region.alloc<bool>(n_states+1);
00176     int n_finals = 0;
00177     for (int i=0; i<n_states+1; i++)
00178       is_final[i] = false;
00179     for (int* f = &f_spec[0]; *f != -1; f++) {
00180       is_final[*f]      = true;
00181       final[n_finals++] = *f;
00182     }
00183 
00184     if (minimize) {
00185       // Sort transitions by symbol and i_state
00186       TransBySymbolI_State::sort(trans, n_trans);
00187       Transition** idx = region.alloc<Transition*>(n_trans+1);
00188       //  idx[i]...idx[i+1]-1 gives where transitions for symbol i start
00189       int n_symbols = 0;
00190       {
00191         int j = 0;
00192         while (j < n_trans) {
00193           idx[n_symbols++] = &trans[j];
00194           int s = trans[j].symbol;
00195           while ((j < n_trans) && (s == trans[j].symbol))
00196             j++;
00197         }
00198         idx[n_symbols] = &trans[j];
00199         assert(j == n_trans);
00200       }
00201       // Map states to groups
00202       int* s2g = region.alloc<int>(n_states+1);
00203       StateGroup* part = region.alloc<StateGroup>(n_states+1);
00204       GroupStates* g2s = region.alloc<GroupStates>(n_states+1);
00205       // Initialize: final states is group one, all other group zero
00206       for (int i=0; i<n_states+1; i++) {
00207         part[i].state = i;
00208         part[i].group = is_final[i] ? 1 : 0;
00209         s2g[i]        = part[i].group;
00210       }
00211       // Important: the state n_state is the dead state, conceptually
00212       // if there is no transition for a symbol and input state, it is
00213       // assumed that there is an implicit transition to n_state
00214 
00215       // Set up the indexing data structure, sort by group
00216       StateGroupByGroup::sort(part,n_states+1);
00217       int n_groups;
00218       if (part[0].group == part[n_states].group) {
00219         // No final states, just one group
00220         g2s[0].fst = &part[0]; g2s[0].lst = &part[n_states+1];
00221         n_groups = 1;
00222       } else  {
00223         int i = 0;
00224         assert(part[0].group == 0);
00225         do i++; while (part[i].group == 0);
00226         g2s[0].fst = &part[0]; g2s[0].lst = &part[i];
00227         g2s[1].fst = &part[i]; g2s[1].lst = &part[n_states+1];
00228         n_groups = 2;
00229       }
00230 
00231       // Do the refinement
00232       {
00233         int m_groups;
00234         do {
00235           m_groups = n_groups;
00236           // Iterate over symbols
00237           for (int sidx = n_symbols; sidx--; ) {
00238             // Iterate over groups
00239             for (int g = n_groups; g--; ) {
00240               // Ignore singleton groups
00241               if (g2s[g].lst-g2s[g].fst > 1) {
00242                 // Apply transitions to group states
00243                 // This exploits that both transitions as well as
00244                 // stategroups are sorted by (input) state
00245                 Transition* t     = idx[sidx];
00246                 Transition* t_lst = idx[sidx+1];
00247                 for (StateGroup* sg = g2s[g].fst; sg<g2s[g].lst; sg++) {
00248                   while ((t < t_lst) && (t->i_state < sg->state))
00249                     t++;
00250                   // Compute group resulting from transition
00251                   if ((t < t_lst) && (t->i_state == sg->state))
00252                     sg->group = s2g[t->o_state];
00253                   else
00254                     sg->group = s2g[n_states]; // Go to dead state
00255                 }
00256                 // Sort group by groups from transitions
00257                 StateGroupByGroup::sort(g2s[g].fst,
00258                                         static_cast<int>(g2s[g].lst-g2s[g].fst));
00259                 // Group must be split?
00260                 if (g2s[g].fst->group != (g2s[g].lst-1)->group) {
00261                   // Skip first group
00262                   StateGroup* sg = g2s[g].fst+1;
00263                   while ((sg-1)->group == sg->group)
00264                     sg++;
00265                   // Start splitting
00266                   StateGroup* lst = g2s[g].lst;
00267                   g2s[g].lst = sg;
00268                   while (sg < lst) {
00269                     s2g[sg->state] = n_groups;
00270                     g2s[n_groups].fst  = sg++;
00271                     while ((sg < lst) && ((sg-1)->group == sg->group)) {
00272                       s2g[sg->state] = n_groups; sg++;
00273                     }
00274                     g2s[n_groups++].lst = sg;
00275                   }
00276                 }
00277               }
00278             }
00279           }
00280         } while (n_groups != m_groups);
00281         // New start state
00282         start = s2g[start];
00283         // Compute new final states
00284         n_finals = 0;
00285         for (int g = n_groups; g--; )
00286           for (StateGroup* sg = g2s[g].fst; sg < g2s[g].lst; sg++)
00287             if (is_final[sg->state]) {
00288               final[n_finals++] = g;
00289               break;
00290             }
00291         // Compute representatives
00292         int* s2r = region.alloc<int>(n_states+1);
00293         for (int i=0; i<n_states+1; i++)
00294           s2r[i] = -1;
00295         for (int g=0; g<n_groups; g++)
00296           s2r[g2s[g].fst->state] = g;
00297         // Clean transitions
00298         int j = 0;
00299         for (int i = 0; i<n_trans; i++)
00300           if (s2r[trans[i].i_state] != -1) {
00301             trans[j].i_state = s2g[trans[i].i_state];
00302             trans[j].symbol  = trans[i].symbol;
00303             trans[j].o_state = s2g[trans[i].o_state];
00304             j++;
00305           }
00306         n_trans  = j;
00307         n_states = n_groups;
00308       }
00309     }
00310 
00311     // Do a reachability analysis for all states starting from start state
00312     Gecode::Support::StaticStack<int,Region> visit(region,n_states);
00313     int* state = region.alloc<int>(n_states);
00314     for (int i=0; i<n_states; i++)
00315       state[i] = SI_NONE;
00316 
00317     Transition** idx = region.alloc<Transition*>(n_states+1);
00318     {
00319       // Sort all transitions according to i_state and create index structure
00320       //  idx[i]...idx[i+1]-1 gives where transitions for state i start
00321       TransByI_State::sort(trans, n_trans);
00322       {
00323         int j = 0;
00324         for (int i=0; i<n_states; i++) {
00325           idx[i] = &trans[j];
00326           while ((j < n_trans) && (i == trans[j].i_state))
00327             j++;
00328         }
00329         idx[n_states] = &trans[j];
00330         assert(j == n_trans);
00331       }
00332 
00333       state[start] = SI_FROM_START;
00334       visit.push(start);
00335       while (!visit.empty()) {
00336         int s = visit.pop();
00337         for (Transition* t = idx[s]; t < idx[s+1]; t++)
00338           if (!(state[t->o_state] & SI_FROM_START)) {
00339             state[t->o_state] |= SI_FROM_START;
00340             visit.push(t->o_state);
00341           }
00342       }
00343     }
00344 
00345     // Do a reachability analysis for all states to a final state
00346     {
00347       // Sort all transitions according to o_state and create index structure
00348       //  idx[i]...idx[i+1]-1 gives where transitions for state i start
00349       TransByO_State::sort(trans, n_trans);
00350       {
00351         int j = 0;
00352         for (int i=0; i<n_states; i++) {
00353           idx[i] = &trans[j];
00354           while ((j < n_trans) && (i == trans[j].o_state))
00355             j++;
00356         }
00357         idx[n_states] = &trans[j];
00358         assert(j == n_trans);
00359       }
00360 
00361       for (int i=0; i<n_finals; i++) {
00362         state[final[i]] |= (SI_TO_FINAL | SI_FINAL);
00363         visit.push(final[i]);
00364       }
00365       while (!visit.empty()) {
00366         int s = visit.pop();
00367         for (Transition* t = idx[s]; t < idx[s+1]; t++)
00368           if (!(state[t->i_state] & SI_TO_FINAL)) {
00369             state[t->i_state] |= SI_TO_FINAL;
00370             visit.push(t->i_state);
00371           }
00372       }
00373     }
00374 
00375     // Now all reachable states are known (also the final ones)
00376     int* re = region.alloc<int>(n_states);
00377     for (int i=0; i<n_states; i++)
00378       re[i] = -1;
00379 
00380     // Renumber states
00381     int m_states = 0;
00382     // Start state gets zero
00383     re[start] = m_states++;
00384 
00385     // Renumber final states
00386     for (int i=n_states; i--; )
00387       if ((state[i] == (SI_FINAL | SI_FROM_START | SI_TO_FINAL)) && (re[i] < 0))
00388         re[i] = m_states++;
00389     // If start state is final, final states start from zero, otherwise from one
00390     int final_fst = (state[start] & SI_FINAL) ? 0 : 1;
00391     int final_lst = m_states;
00392     // final_fst...final_lst-1 are the final states
00393 
00394     // Renumber remaining states
00395     for (int i=n_states; i--; )
00396       if ((state[i] == (SI_FROM_START | SI_TO_FINAL)) && (re[i] < 0))
00397         re[i] = m_states++;
00398 
00399     // Count number of remaining transitions
00400     int m_trans = 0;
00401     for (int i=n_trans; i--; )
00402       if ((re[trans[i].i_state] >= 0) && (re[trans[i].o_state] >= 0))
00403         m_trans++;
00404 
00405     // All done... Construct the automaton
00406     DFAI* d = new DFAI(m_trans);
00407     d->n_states  = m_states;
00408     d->n_trans   = m_trans;
00409     d->final_fst = final_fst;
00410     d->final_lst = final_lst;
00411     {
00412       int j = 0;
00413       Transition* r = &d->trans[0];
00414       for (int i = 0; i<n_trans; i++)
00415         if ((re[trans[i].i_state] >= 0) && (re[trans[i].o_state] >= 0)) {
00416           r[j].symbol  = trans[i].symbol;
00417           r[j].i_state = re[trans[i].i_state];
00418           r[j].o_state = re[trans[i].o_state];
00419           j++;
00420         }
00421       TransBySymbol::sort(r,m_trans);
00422     }
00423     {
00424       // Count number of symbols
00425       unsigned int n_symbols = 0;
00426       for (int i = 0; i<m_trans; ) {
00427         int s = d->trans[i++].symbol;
00428         n_symbols++;
00429         while ((i<m_trans) && (d->trans[i].symbol == s))
00430           i++;
00431       }
00432       d->n_symbols = n_symbols;
00433     }
00434     {
00435       // Compute maximal degree
00436       unsigned int max_degree = 0;
00437       unsigned int* deg = region.alloc<unsigned int>(m_states);
00438 
00439       // Compute in-degree per state
00440       for (int i=0; i<m_states; i++)
00441         deg[i] = 0;
00442       for (int i=0; i<m_trans; i++)
00443         deg[d->trans[i].o_state]++;
00444       for (int i=0; i<m_states; i++)
00445         max_degree = std::max(max_degree,deg[i]);
00446 
00447       // Compute out-degree per state
00448       for (int i=0; i<m_states; i++)
00449         deg[i] = 0;
00450       for (int i=0; i<m_trans; i++)
00451         deg[d->trans[i].i_state]++;
00452       for (int i=0; i<m_states; i++)
00453         max_degree = std::max(max_degree,deg[i]);
00454 
00455       // Compute transitions per symbol
00456       {
00457         int i=0;
00458         while (i < m_trans) {
00459           int j=i++;
00460           while ((i < m_trans) &&
00461                  (d->trans[j].symbol == d->trans[i].symbol))
00462             i++;
00463           max_degree = std::max(max_degree,static_cast<unsigned int>(i-j));
00464         }
00465       }
00466 
00467       d->max_degree = max_degree;
00468     }
00469 
00470     d->fill();
00471     object(d);
00472   }
00473 
00474   DFA::DFA(int start, Transition t_spec[], int f_spec[], bool minimize) {
00475     init(start,t_spec,f_spec,minimize);
00476   }
00477 
00478   DFA::DFA(int start, std::initializer_list<Transition> tl,
00479            std::initializer_list<int> fl, bool minimize) {
00480     Region reg;
00481     int nt = static_cast<int>(tl.size());
00482     int nf = static_cast<int>(fl.size());
00483     Transition* ts = reg.alloc<Transition>(nt + 1);
00484     {
00485       int i=0;
00486       for (const Transition& t : tl)
00487         ts[i++] = t;
00488       ts[nt].i_state = -1;
00489     }
00490     int* fs = reg.alloc<int>(nf + 1);
00491     {
00492       int i=0;
00493       for (const int& f : fl)
00494         fs[i++] = f;
00495       fs[nf] = -1;
00496     }
00497     init(start,ts,fs,minimize);
00498   }
00499 
00500   bool
00501   DFA::equal(const DFA& d) const {
00502     assert(n_states() == d.n_states());
00503     assert(n_transitions() == d.n_transitions());
00504     assert(n_symbols() == d.n_symbols());
00505     assert(final_fst() == d.final_fst());
00506     assert(final_lst() == d.final_lst());
00507     DFA::Transitions me(*this);
00508     DFA::Transitions they(d);
00509     while (me()) {
00510       if (me.i_state() != they.i_state())
00511         return false;
00512       if (me.symbol() != they.symbol())
00513         return false;
00514       if (me.o_state() != they.o_state())
00515         return false;
00516       ++me;
00517       ++they;
00518     }
00519     return true;
00520   }
00521 
00522 }
00523 
00524 // STATISTICS: int-prop
00525