isomorph.hxx

00001 // isomorph.hxx: this file is part of the Vaucanson project.
00002 //
00003 // Vaucanson, a generic library for finite state machines.
00004 //
00005 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 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_ISOMORPH_HXX
00018 # define VCSN_ALGORITHMS_ISOMORPH_HXX
00019 
00020 # include <vaucanson/algorithms/isomorph.hh>
00021 # include <vaucanson/algorithms/determinize.hh>
00022 
00023 # include <vaucanson/automata/concept/automata_base.hh>
00024 # include <vaucanson/tools/usual_macros.hh>
00025 
00026 # include <vaucanson/algorithms/internal/skeleton.hh>
00027 
00028 # include <queue>
00029 # include <set>
00030 # include <list>
00031 # include <utility>
00032 
00033 namespace vcsn {
00034 
00035   /*--------------------------------------.
00036   | Helper for are_isomorphic algorithm.  |
00037   `--------------------------------------*/
00038 
00039   class Trie
00040   {
00041     public:
00042       Trie* insert(std::vector<int>&);
00043 
00044     public:
00045       std::list<int> A, B;
00046 
00047       // Node in list C pointing to this node
00048       std::list<Trie*>::iterator L;
00049 
00050     private:
00051       Trie* insert_suffix(std::vector<int>&, unsigned int);
00052       std::map<int, Trie> children;
00053   };
00054 
00055   // Finds node associated to the insertion of a vector of integers
00056   inline Trie* Trie::insert(std::vector<int>& S)
00057   {
00058     return insert_suffix(S, 0);
00059   }
00060 
00061   inline Trie* Trie::insert_suffix(std::vector<int>& S, unsigned int p)
00062   {
00063     if (p == S.capacity() - 1)
00064       return this;
00065 
00066     return children[S[p]].insert_suffix(S, p + 1);
00067   }
00068 
00069 
00070   /*---------------.
00071   | are_isomorphic |
00072   `---------------*/
00073 
00074   template<typename A, typename T>
00075   bool
00076   are_isomorphic(const Element<A, T>& a, const Element<A, T>& b)
00077   {
00078     typedef Element<A, T> automaton_t;
00079 
00080     AUTOMATON_TYPES(automaton_t);
00081 
00082     // We can start with good suppositions
00083     if ((a.states().size() != b.states().size())
00084         || (a.transitions().size() != b.transitions().size())
00085         || (a.initial().size() != b.initial().size())
00086         || (a.final().size() != b.final().size()))
00087       return false;
00088 
00089 
00090     int i, j , k, l;
00091     bool iso;
00092     std::list<int>::iterator it_int, it_int_B, it_int_aux;
00093 
00094     // Vector indexed by states that points to the corresponding
00095     // node of the list of states of each class of states stored in
00096     // the Tries (for automaton A).
00097     std::vector<std::list<int>::iterator> T_L_A(a.states().size());
00098 
00099     // Idem for automaton B.
00100     std::vector<std::list<int>::iterator> T_L_B(b.states().size());
00101 
00102 
00103     // Tries of classes of normal, initial and final states.
00104     Trie *T_Q_IT, *T_I, *T_T, *T_aux;
00105 
00106     T_Q_IT = new Trie();
00107     T_I = new Trie();
00108     T_T = new Trie();
00109 
00110     std::list<Trie*> C;
00111     // List of fixed states emerged from classes stored in C.
00112     std::list<int> U;
00113     // class_state_A[i] = class (node of a Trie) of state i for automaton A
00114     std::vector<Trie*> class_state_A(a.states().size());
00115     // class_state_A[i] = idem for automaton B
00116     std::vector<Trie*> class_state_B(b.states().size());
00117 
00118     // perm_A[i] = state of automaton B corresponding to state i in
00119     // the isomorphism (idem for perm_B), or -1 when the association
00120     // is yet undefined
00121     std::vector<int> perm_A(a.states().size());
00122     std::vector<int> perm_B(b.states().size());
00123 
00124     Skeleton<A, T> Sa(a);
00125     Skeleton<A, T> Sb(b);
00126 
00127     // The automata are isomorphic unless one proves the contrary
00128     iso = true;
00129 
00130     // Constructs lists of deterministic ingoing and outgoing transitions
00131     // for each state (delta_det_in[i] = list of deterministic ingoing
00132     // transitions for state i, idem for delta_det_out[i])
00133 
00134     std::vector< std::list<int> > delta_det_in_A(a.states().size());
00135     std::vector< std::list<int> > delta_det_out_A(a.states().size());
00136     std::vector< std::list<int> > delta_det_in_B(b.states().size());
00137     std::vector< std::list<int> > delta_det_out_B(b.states().size());
00138 
00139     // Automaton A
00140     for (i = 0; i < static_cast<int>(a.states().size()); i++)
00141     {
00142       if ((Sa.delta_in[i]).size() > 0)
00143       {
00144         it_int = Sa.delta_in[i].begin();
00145         // Number of transitions with the same label
00146         j = 1;
00147         for (it_int++; it_int != Sa.delta_in[i].end(); it_int++)
00148         {
00149           // It seems there is no iterator arithmetics in C++:
00150           // *(it_int - 1) doesn't compile.
00151           k = *(--it_int);
00152           it_int++;
00153           // New label?
00154           if (Sa.transitions_labels[*it_int] != Sa.transitions_labels[k])
00155             // The last transition is deterministic?
00156             if (j == 1)
00157               delta_det_in_A[i].push_back(k);
00158           // Several transitions with the same label?
00159             else
00160               // Does nothing. A series of transitions with a new label begins.
00161               j = 1;
00162           // Same label?
00163           else
00164             j++;
00165         }
00166         // The last label visited is deterministic?
00167         if (j == 1)
00168         {
00169           delta_det_in_A[i].push_back(*(--it_int));
00170           it_int++;
00171         }
00172       }
00173       if ((Sa.delta_out[i]).size() > 0)
00174       {
00175         it_int = Sa.delta_out[i].begin();
00176         // Number of transitions with the same label
00177         j = 1;
00178         for (it_int++; it_int != Sa.delta_out[i].end(); it_int++)
00179         {
00180           // It seems there is no iterator arithmetics in C++:
00181           // *(it_int - 1) doesn't compile.
00182           k = *(--it_int);
00183           it_int++;
00184           // New label?
00185           if (Sa.transitions_labels[*it_int] != Sa.transitions_labels[k])
00186             // The last transition is deterministic?
00187             if (j == 1)
00188               delta_det_out_A[i].push_back(k);
00189           // Several transitions with the same label?
00190             else
00191               // Does nothing. A series of transitions with a new label begins.
00192               j = 1;
00193           // Same label?
00194           else
00195             j++;
00196         }
00197         // The last label visited is deterministic?
00198         if (j == 1)
00199         {
00200           delta_det_out_A[i].push_back(*(--it_int));
00201           ++it_int;
00202         }
00203       }
00204     }
00205 
00206     // Automaton B
00207     for (i = 0; i < static_cast<int>(a.states().size()); i++)
00208     {
00209       if ((Sb.delta_in[i]).size() > 0)
00210       {
00211         it_int = Sb.delta_in[i].begin();
00212         // Number of transitions with the same label
00213         j = 1;
00214         for (it_int++; it_int != Sb.delta_in[i].end(); it_int++)
00215         {
00216           // It seems there is no iterator arithmetics in C++:
00217           // *(it_int - 1) doesn't compile.
00218           k = *(--it_int);
00219           it_int++;
00220           // New label?
00221           if (Sb.transitions_labels[*it_int] != Sb.transitions_labels[k])
00222             // The last transition is deterministic?
00223             if (j == 1)
00224               delta_det_in_B[i].push_back(k);
00225           // Several transitions with the same label?
00226             else
00227               // Does nothing. A series of transitions with a new label begins.
00228               j = 1;
00229           // Same label?
00230           else
00231             j++;
00232         }
00233         // The last label visited is deterministic?
00234         if (j == 1)
00235         {
00236           delta_det_in_B[i].push_back(*(--it_int));
00237           ++it_int;
00238         }
00239       }
00240       if ((Sb.delta_out[i]).size() > 0)
00241       {
00242         it_int = Sb.delta_out[i].begin();
00243         // Number of transitions with the same label
00244         j = 1;
00245         for (it_int++; it_int != Sb.delta_out[i].end(); it_int++)
00246         {
00247           // It seems there is no iterator arithmetics in C++:
00248           // *(it_int - 1) doesn't compile.
00249           k = *(--it_int);
00250           it_int++;
00251           // New label?
00252           if (Sb.transitions_labels[*it_int] != Sb.transitions_labels[k])
00253             // The last transition is deterministic?
00254             if (j == 1)
00255               delta_det_out_B[i].push_back(k);
00256           // Several transitions with the same label?
00257             else
00258               // Does nothing. A series of transitions with a new label begins.
00259               j = 1;
00260           // Same label?
00261           else
00262             j++;
00263         }
00264         // The last label visited is deterministic?
00265         if (j == 1)
00266         {
00267           delta_det_out_B[i].push_back(*(--it_int));
00268           it_int++;
00269         }
00270       }
00271     }
00272 
00273     // Constructs Tries of classes of states with the same sequence of
00274     // ingoing and outgoing transitions in lex. order (for automaton A)
00275     for (i = 0; i < static_cast<int>(a.states().size()); i++)
00276     {
00277       // Vector all_transitions_lex contains the sequence of labels of
00278       // ingoing and outgoing transitions of state i in lex. order,
00279       // separated by a mark (-1)
00280       std::vector<int> all_transitions_lex((Sa.delta_in[i]).size() +
00281                                            (Sa.delta_out[i]).size() + 1);
00282 
00283       // First stores the sequence of ingoing transitions
00284       for (it_int = Sa.delta_in[i].begin();
00285            it_int != Sa.delta_in[i].end(); ++it_int)
00286         all_transitions_lex.push_back(Sa.transitions_labels[*it_int]);
00287 
00288       all_transitions_lex.push_back(-1);
00289       // Next, outgoing transitions
00290       for (it_int = Sa.delta_out[i].begin();
00291            it_int != Sa.delta_out[i].end(); ++it_int)
00292         all_transitions_lex.push_back(Sa.transitions_labels[*it_int]);
00293 
00294       // Gets the node of the correct Trie (Trie of initial, final or normal
00295       // states) for the sequence of transitions of state i
00296       if (a.is_initial(Sa.states[i]))
00297         T_aux = T_I->insert(all_transitions_lex);
00298       else
00299         if (a.is_final(Sa.states[i]))
00300           T_aux = T_T->insert(all_transitions_lex);
00301         else
00302           T_aux = T_Q_IT->insert(all_transitions_lex);
00303 
00304       // New class?
00305       if ((T_aux->A).size() == 0)
00306       {
00307         // Inserts in list C of classes (nodes of Tries)
00308         C.push_front(T_aux);
00309 
00310         // Each Trie node points to its node in list C
00311         T_aux->L = C.begin();
00312       }
00313 
00314       // Inserts the state in the list A of its corresponding class
00315       (T_aux->A).push_front(i);
00316       // Defines class of state i
00317       class_state_A[i] = T_aux;
00318       // T_L_A[i] = node of the list of states of class of state i
00319       T_L_A[i] = (T_aux->A).begin();
00320     }
00321 
00322 
00323     // Constructs Tries of classes of states with the same sequence of
00324     // ingoing and outgoing transitions in lex. order (for automaton B)
00325     for (i = 0; (i < static_cast<int>(b.states().size())) && iso; i++)
00326     {
00327       // Vector all_transitions_lex contains the sequence of labels of
00328       // ingoing and outgoing transitions of state i in lex. order,
00329       // separated by a mark (-1)
00330       std::vector<int> all_transitions_lex((Sb.delta_in[i]).size() +
00331                                            (Sb.delta_out[i]).size() + 1);
00332       // First stores the sequence of ingoing transitions
00333       for (it_int = Sb.delta_in[i].begin();
00334            it_int != Sb.delta_in[i].end(); ++it_int)
00335         all_transitions_lex.push_back(Sb.transitions_labels[*it_int]);
00336 
00337       all_transitions_lex.push_back(-1);
00338       // Next, outgoing transitions
00339       for (it_int = Sb.delta_out[i].begin();
00340            it_int != Sb.delta_out[i].end(); ++it_int)
00341         all_transitions_lex.push_back(Sb.transitions_labels[*it_int]);
00342 
00343       // Gets the node of the correct Trie (Trie of initial, final or
00344       // normal states) for the sequence of transitions of state i
00345       if (b.is_initial(Sa.states[i]))
00346         T_aux = T_I->insert(all_transitions_lex);
00347       else
00348         if (b.is_final(Sa.states[i]))
00349           T_aux = T_T->insert(all_transitions_lex);
00350         else
00351           T_aux = T_Q_IT->insert(all_transitions_lex);
00352 
00353       // Does the class of state i have more states for automaton B
00354       // than those for automaton A ?
00355       if ((T_aux->A).size() == (T_aux->B).size())
00356         iso = false;
00357       else
00358       {
00359         // Inserts the state in the list B of its corresponding class
00360         (T_aux->B).push_front(i);
00361         // Defines class of state i
00362         class_state_B[i] = T_aux;
00363         // T_L_B[i] = node of the list of states of class of state i
00364         T_L_B[i] = (T_aux->B).begin();
00365       }
00366     }
00367 
00368     // Have we discovered that the automata are not isomorphic?
00369     if (!iso)
00370       return false;
00371 
00372     for (i = 0; i < static_cast<int>(a.states().size()); i++)
00373       perm_A[i] = perm_B[i] = -1;
00374 
00375 
00376     // Searches for classes having only one state for each
00377     // automaton. These states must be identified. These classes are
00378     // then stored in list U.
00379     // Also tests if all classes have the same number of states in
00380     // lists A and B.
00381 
00382     std::list<Trie*>::iterator itr_C;
00383 
00384     itr_C = C.begin();
00385 
00386     while ((itr_C != C.end()) && iso)
00387     {
00388       // Do automata A and B have the same number of states in the
00389       // current class?
00390       if (((*itr_C)->A).size() != ((*itr_C)->B).size())
00391       {
00392         iso = false;
00393         itr_C++;
00394       }
00395       else
00396         // Class *itr_C contains only one state of each automata?
00397         if (((*itr_C)->A).size() == 1)
00398         {
00399           // States *((*itr_C).A.begin()) and
00400           // *((*itr_C).B.begin()) have to be identified.
00401           U.push_front(k = (*(((*itr_C)->A).begin())));
00402           perm_A[k] = l = *(((*itr_C)->B).begin());
00403           perm_B[l] = k;
00404 
00405           // Just for coherence, lists A and B of class *itr_C are voided
00406           ((*itr_C)->A).erase(((*itr_C)->A).begin());
00407           ((*itr_C)->B).erase(((*itr_C)->B).begin());
00408           // Deletes current node and points to the next.
00409           itr_C = C.erase(itr_C);
00410         }
00411         else
00412           itr_C++;
00413     }
00414 
00415     // Have we discovered that the automata are not isomorphic?
00416     if (!iso)
00417       return false;
00418 
00419     // Tries to discover more fixed states implied by states in U
00420     // During the loop, a state i of A is in its Trie iff perm_A[i] = -1
00421     // Time complexity: O(m)
00422     // (obs: if the automata are deterministic, the isomorphism test
00423     // ends here)
00424     while (!U.empty() && iso)
00425     {
00426       // Each state in U has already an image (perm_A and perm_B are
00427       // defined for this state)
00428 
00429       // i = current state in automaton A, j = its image in automaton B
00430       j = perm_A[i = U.front()];
00431       U.pop_front();
00432 
00433       // Deterministic ingoing and outgoing transitions are analyzed
00434 
00435       // As states i and j are already associated, they belong to
00436       // the same class, then have the same sequence of
00437       // deterministic transitions.
00438 
00439       // First analyzes co-deterministic ingoing transitions
00440       it_int = delta_det_in_A[i].begin();
00441       it_int_aux = delta_det_in_B[j].begin();
00442       for (; it_int != delta_det_in_A[i].end() and iso; ++it_int, ++it_int_aux)
00443       {
00444 
00445         // The states being considered are the origins of current
00446         // co-deterministic transitions (k for automaton A, l for B)
00447         k = Sa.origins_transitions[*it_int];
00448         l = Sb.origins_transitions[*it_int_aux];
00449 
00450         // Has state k already been visited?
00451         if (perm_A[k] >= 0)
00452         {
00453           // If it has already been visited, does the current image
00454           // matches state l?
00455           if (perm_A[k] != l)
00456             iso = false;
00457         }
00458         else
00459           // State k has not already been visited. The same must be
00460           // true for state l.
00461           if (perm_B[l] != -1)
00462             iso = false;
00463         // Tries to associate states k and l
00464           else
00465             // Does k and l belongs to different classes?
00466             if (class_state_A[k] != class_state_B[l])
00467               iso = false;
00468         // The states k and l belong to the same class and can be
00469         // associated.
00470             else
00471             {
00472               perm_A[perm_B[l] = k] = l;
00473               // Removes k and l from theirs lists of states in theirs
00474               // classes (O(1))
00475               (class_state_A[k]->A).erase(T_L_A[k]);
00476               (class_state_B[l]->B).erase(T_L_B[l]);
00477               U.push_front(k);
00478               if ((class_state_A[k]->A).size() == 1)
00479               {
00480                 // If it remains only one state of each
00481                 // automaton in the class of the current states,
00482                 // they must be associated. Then they are
00483                 // putted in list U, and the class are removed
00484                 // from C.
00485                 // From now on k and l represent these states.
00486 
00487                 T_aux = class_state_A[k];
00488                 k = (T_aux->A).front();
00489                 l = (T_aux->B).front();
00490                 perm_A[perm_B[l] = k] = l;
00491 
00492                 U.push_front(k);
00493 
00494                 // Removes class T_aux from C
00495                 C.erase(T_aux->L);
00496 
00497               }
00498             }
00499       }
00500 
00501 
00502       // Next analyzes deterministic outgoing transitions
00503       it_int = delta_det_out_A[i].begin();
00504       it_int_aux = delta_det_out_B[j].begin();
00505       for (; it_int != delta_det_out_A[i].end() && iso; ++it_int, ++it_int_aux)
00506       {
00507 
00508         // The states being considered are the ends of current
00509         // deterministic transitions (k for automaton A, l for B)
00510         k = Sa.aims_transitions[*it_int];
00511         l = Sb.aims_transitions[*it_int_aux];
00512 
00513         // Has state k already been visited?
00514         if (perm_A[k] >= 0)
00515         {
00516           // If it has already been visited, does the current image
00517           // matches state l?
00518           if (perm_A[k] != l)
00519             iso = false;
00520         }
00521         else
00522           // State k has not already been visited. The same must be true for state l.
00523           if (perm_B[l] != -1)
00524             iso = false;
00525         // Tries to associate states k and l
00526           else
00527             // Does k and l belongs to different classes?
00528             if (class_state_A[k] != class_state_B[l])
00529               iso = false;
00530         // The states belong to the same class and can be associated.
00531             else
00532             {
00533               perm_A[perm_B[l] = k] = l;
00534               // Removes k and l from theirs lists of states in theirs
00535               // classes (O(1))
00536               (class_state_A[k]->A).erase(T_L_A[k]);
00537               (class_state_B[l]->B).erase(T_L_B[l]);
00538               U.push_front(k);
00539 
00540               if ((class_state_A[k]->A).size() == 1)
00541               {
00542                 // If it remains only one state of each
00543                 // automaton in the class of the current states,
00544                 // they must be associated. Then they are
00545                 // inserted in list U, and the class are removed
00546                 // from C.
00547                 // From now on k and l represent these states.
00548 
00549                 T_aux = class_state_A[k];
00550                 k = (T_aux->A).front();
00551                 l = (T_aux->B).front();
00552                 perm_A[perm_B[l] = k] = l;
00553 
00554                 U.push_front(k);
00555 
00556                 // Removes class T_aux from C
00557                 C.erase(T_aux->L);
00558 
00559               }
00560             }
00561       }
00562 
00563     }
00564 
00565     // Have we discovered that the automata are not isomorphic?
00566     if (!iso)
00567       return false;
00568 
00569 
00570     // Next, Tries to associate remaining states (in remaining classes
00571     // in C). This is the backtracking phase.
00572 
00573     // Stores in l the number of non-fixed states
00574     l = 0;
00575     for (itr_C = C.begin(); itr_C != C.end(); ++itr_C)
00576       l += (*itr_C)->A.size();
00577 
00578     // Vectors of classes of remaining states.  States in the same
00579     // class are stored contiguously, and in the case of vector for
00580     // automaton B, classes are separated by two enTries: one with -1,
00581     // denoting the end of the class, and the following with the
00582     // position where the class begins in this vector.
00583     std::vector<int> C_A(l);
00584     std::vector<int> C_B(l + 2 * C.size());
00585     // current[i] = position in C_B of image of state C_A[i] during
00586     // backtracking.
00587     std::vector<int> current(l);
00588 
00589 
00590     // Vector for test of correspondence of transitions of states already
00591     // attributed
00592     std::vector<int> correspondence_transitions(a.states().size());
00593 
00594     for (i = 0; i < static_cast<int>(a.states().size()); ++i)
00595       correspondence_transitions[i] = 0;
00596 
00597     // Stores states in C_A and C_B. Partial results of the
00598     // backtracking are stored in vector current, that is initialized
00599     // with the first element of each class.
00600     i = j = 0;
00601     for (itr_C = C.begin(); itr_C != C.end(); itr_C++)
00602     {
00603       it_int = ((*itr_C)->A).begin();
00604       it_int_B = ((*itr_C)->B).begin();
00605       C_A[i] = *it_int;
00606       C_B[j] = *it_int_B;
00607       current[i++] = j++;
00608       for (it_int++, it_int_B++; it_int != ((*itr_C)->A).end();
00609            it_int++, it_int_B++)
00610       {
00611         C_A[i] = *it_int;
00612         C_B[j++] = *it_int_B;
00613         current[i] = current[i - 1];
00614         i++;
00615       }
00616       // End of class
00617       C_B[j++] = -1;
00618       // Position where the class begins
00619       C_B[j++] = current[i - 1];
00620     }
00621 
00622     // Tries to associate states of C_A and C_B
00623 
00624     i = 0;
00625 
00626     // Backtracking loop. Each iteration Tries to associate state
00627     // C_A[i]. If i = C_A.size(), the automata are isomorphic.
00628     while (iso && (i < static_cast<int>(C_A.size())))
00629     {
00630       // Searches for the first free state in the class of C_A[i]
00631       for (j = current[i]; (C_B[j] != -1) && (perm_B[C_B[j]] >= 0); j++)
00632         ;
00633 
00634       // There is no possibility for state C_A[i]
00635       if (C_B[j] == -1)
00636       {
00637         // If there is no possibility for C_A[0], the automata are not
00638         // isomorphic
00639         if (i == 0)
00640           iso = false;
00641         else
00642         {
00643           // Prepares for backtracking in next iteration.
00644           // Image of C_A[i] is set to first state of its class
00645           current[i] = C_B[j + 1];
00646           // Next iteration will try to associate state i - 1
00647           // to next possible position
00648           i--;
00649           perm_B[perm_A[C_A[i]]] = -1;
00650           perm_A[C_A[i]] = -1;
00651           current[i]++;
00652         }
00653       }
00654       // Tries to associate state C_A[i] to state C_B[j]
00655       else
00656       {
00657 
00658         current[i] = j;
00659         perm_A[C_A[i]] = C_B[j];
00660         perm_B[C_B[j]] = C_A[i];
00661 
00662         // Tests correspondence of ingoing transitions, considering
00663         // states that are already in the permutation.
00664 
00665         std::list<int>::iterator int_itr_B;
00666 
00667         it_int = Sa.delta_in[C_A[i]].begin();
00668         it_int_B = Sb.delta_in[C_B[j]].begin();
00669         bool b = true;
00670 
00671         // Each iteration considers a sequence of ingoing labels
00672         // with the same label. The sequence begins at it_int
00673         while ((it_int != Sa.delta_in[C_A[i]].end()) && b)
00674         {
00675           // Searches for origins of ingoing transitions for current
00676           // label that have already been associated. For each
00677           // state visited, its position in correspondence_transitions
00678           // is incremented.
00679           k = 0;
00680           for (it_int_aux = it_int;
00681                (it_int_aux != Sa.delta_in[C_A[i]].end()) &&
00682                  (Sa.transitions_labels[*it_int_aux] ==
00683                   Sa.transitions_labels[*it_int]);
00684                it_int_aux++, k++)
00685             // Is the origin of current transition associated?
00686             if (perm_A[Sa.origins_transitions[*it_int_aux]] >= 0)
00687               correspondence_transitions[Sa.origins_transitions[*it_int_aux]]++;
00688 
00689           // Here, k = number of ingoing transitions for current label
00690 
00691           // Idem for ingoing transitions of state C_B[j], but positions in
00692           // correspondence_transitions are decremented.
00693           for (; (k > 0) && b; it_int_B++, k--)
00694             // Has the origin of current transition already been visited?
00695             if (perm_B[Sb.origins_transitions[*it_int_B]] >= 0)
00696               // Trying to decrement a position with 0 means that the
00697               // corresponding state in A is not correct.
00698               if (correspondence_transitions[perm_B[Sb.origins_transitions[*it_int_B]]] == 0)
00699                 // The association of C_A[i] and C_B[j] is impossible
00700                 b = false;
00701               else
00702                 correspondence_transitions[perm_B[Sb.origins_transitions[*it_int_B]]]--;
00703 
00704           // Verifies correspondence_transitions. The correspondence for
00705           // current label is correct iff correspondence_transitions[l] = 0
00706           // for all origin l of ingoing transitions of C_A[i] labelled by
00707           // the current label.
00708           // For this, int_itr visits all transitions until int_itr_aux.
00709 
00710           for (; it_int != it_int_aux; it_int++)
00711           {
00712             if (perm_A[Sa.origins_transitions[*it_int]] >= 0)
00713               if (correspondence_transitions[Sa.origins_transitions[*it_int]] != 0)
00714                 b = false;
00715             // All positions must be 0 for next iteration
00716             correspondence_transitions[Sa.origins_transitions[*it_int]] = 0;
00717           }
00718 
00719         } // end while for ingoing transitions
00720 
00721         // Ok for ingoing transitions? Tests outgoing transitions.
00722         if (b)
00723         {
00724           // Tests correspondence of outgoing transitions, considering
00725           // states that are already in the permutation.
00726 
00727           std::list<int>::iterator int_itr_B;
00728 
00729           it_int = Sa.delta_out[C_A[i]].begin();
00730           it_int_B = Sb.delta_out[C_B[j]].begin();
00731 
00732           // Each iteration considers a sequence of outgoing labels
00733           // with the same label. The sequence begins at it_int
00734           while ((it_int != Sa.delta_out[C_A[i]].end()) && b)
00735           {
00736             // Searches for ends of outgoing transitions for current
00737             // label that have already been associated. For each
00738             // state visited, its position in correspondence_transitions
00739             // is incremented.
00740             k = 0;
00741             for (it_int_aux = it_int;
00742                  (it_int_aux != Sa.delta_out[C_A[i]].end()) &&
00743                    (Sa.transitions_labels[*it_int_aux] ==
00744                     Sa.transitions_labels[*it_int]);
00745                  it_int_aux++, k++)
00746               // Is the end of current transition associated?
00747               if (perm_A[Sa.aims_transitions[*it_int_aux]] >= 0)
00748                 correspondence_transitions[Sa.aims_transitions[*it_int_aux]]++;
00749 
00750             // Here, k = number of outgoing transitions for current label
00751 
00752             // Idem for outgoing transitions of state C_B[j], but positions in
00753             // correspondence_transitions are decremented.
00754             for (; (k > 0) && b; it_int_B++, k--)
00755               // Has the end of current transition already been visited?
00756               if (perm_B[Sb.aims_transitions[*it_int_B]] >= 0)
00757                 // Trying to decrement a position with 0 means that
00758                 // the corresponding state in A is not correct.
00759                 if (correspondence_transitions[perm_B[Sb.aims_transitions[*it_int_B]]] == 0)
00760                   // The association of C_A[i] and C_B[j] is
00761                   // impossible
00762                   b = false;
00763                 else
00764                   correspondence_transitions[perm_B[Sb.aims_transitions[*it_int_B]]]--;
00765 
00766             // Verifies correspondence_transitions. The correspondence
00767             // for current label is correct iff
00768             // correspondence_transitions[l] = 0 for all end l of
00769             // outgoing transitions of C_A[i] labelled by the current
00770             // label.
00771             // For this, int_itr visits all transitions until int_itr_aux.
00772 
00773             for (; it_int != it_int_aux; it_int++)
00774             {
00775               if (perm_A[Sa.aims_transitions[*it_int]] >= 0)
00776                 if (correspondence_transitions[Sa.aims_transitions[*it_int]] != 0)
00777                   b = false;
00778               // All positions must be 0 for next iteration
00779               correspondence_transitions[Sa.aims_transitions[*it_int]] = 0;
00780             }
00781 
00782           } // End while for outgoing transitions
00783 
00784         } // End of test of outgoing transitions
00785 
00786         // States C_A[i] and C_B[j] can be associated.
00787         if (b)
00788           // Tries to associate state in C_A[i + 1] in next iteration
00789           i++;
00790         // Impossible to associate C_A[i] to C_B[j]
00791         else
00792         {
00793           // Tries C_A[i] to C_B[j + 1] in next iteration
00794           perm_B[perm_A[C_A[i]]] = -1;
00795           perm_A[C_A[i]] = -1;
00796           current[i]++;
00797         }
00798 
00799       } // end of association of states C_A[i] and C_B[j]
00800 
00801     } // end of backtracking loop
00802 
00803     return (iso);
00804 
00805   } // end of are_isomorphic
00806 
00807 } // vcsn
00808 
00809 #endif // ! VCSN_ALGORITHMS_ISOMORPH_HXX

Generated on Fri Jul 28 12:18:34 2006 for Vaucanson by  doxygen 1.4.6