• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

C:/CVUT/diplomka/Automata_editor/algorithms/algorithms.cpp

Go to the documentation of this file.
00001 #include "algorithms.h"
00002 
00003 #include "interfaces/iautomaton.h"
00004 #include "interfaces/istate.h"
00005 #include "interfaces/itransition.h"
00006 
00007 #include <QSet>
00008 #include <QQueue>
00009 #include <QStringList>
00010 #include <QMap>
00011 
00012 #include <QDialog>
00013 #include <QGridLayout>
00014 #include <QCheckBox>
00015 #include <QPushButton>
00016 
00017 #include <QtPlugin>
00018 
00019 #include "utility/dbglog.h"
00020 #include "utility/utils.h"
00021 
00022 #define DBGLOG_ALGO(x) DBGLOG_("ALGORITHMS", x)
00023 
00024 //<-- SettingsDialog -----------------------------------------------------------------------
00025 
00026 class SettingsDialog : public QDialog
00027 {
00028 public:
00029     SettingsDialog(BasicAlgorithmWithSettings &algorithm, QWidget *parent)
00030     :   QDialog(parent), m_algorithm(algorithm)        
00031     {
00032         m_checkPreserveNames = new QCheckBox(tr("Preserve state names"), this);
00033         m_checkPreserveNames->setChecked(m_algorithm.preserveNames());
00034         
00035         m_checkPreserveLabels = new QCheckBox(tr("Preserve state labels"), this);
00036         m_checkPreserveLabels->setChecked(m_algorithm.preserveLabels());
00037         
00038         // buttons
00039         QWidget *hBox = new QWidget(this);
00040         QPushButton *buttonOk = new QPushButton("Ok");
00041         QPushButton *buttonCancel = new QPushButton("Cancel");
00042         QHBoxLayout *hBoxLayout = new QHBoxLayout;
00043         hBoxLayout->addWidget(buttonOk);
00044         hBoxLayout->addWidget(buttonCancel);
00045         hBox->setLayout(hBoxLayout);    
00046         hBox->setMaximumWidth(300);
00047         connect(buttonOk, SIGNAL(clicked()), this, SLOT(accept()));
00048         connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
00049         
00050         QGridLayout *gridLayout = new QGridLayout(this);
00051         gridLayout->addWidget(m_checkPreserveNames, 0, 0);
00052         gridLayout->addWidget(m_checkPreserveLabels, 1, 0);
00053         gridLayout->addWidget(hBox, 2, 0);
00054         
00055         QString s = m_algorithm.getName() + " - settings";        
00056         setWindowTitle(s);
00057         setWindowIcon(QIcon(":images/grid.xpm"));
00058     }
00059     
00060     bool preserveNames() const { return m_checkPreserveNames->checkState() == Qt::Checked; }
00061     bool preserveLabels() const { return m_checkPreserveLabels->checkState() == Qt::Checked; }
00062     
00063 private:
00064     QCheckBox                   *m_checkPreserveNames;
00065     QCheckBox                   *m_checkPreserveLabels;
00066     BasicAlgorithmWithSettings  &m_algorithm;
00067 };
00068 
00069 //----------------------------------------------------------------------- SettingsDialog -->
00070 
00071 
00072 
00073 //<-- BasicAlgorithm -----------------------------------------------------------------------
00074 
00075 BasicAlgorithm::BasicAlgorithm()
00076 :   m_creator(QSharedPointer<IAutomataCreator>(NULL))    
00077 {}
00078 
00079 void BasicAlgorithm::setAutomataCreator(const QSharedPointer<IAutomataCreator> &creator)
00080 {
00081     m_creator = creator;
00082 }
00083 
00084 bool BasicAlgorithm::run(const IAutomaton::TAutomataList &input,
00085                          QSharedPointer<IAutomaton> &result,
00086                          QString *report) const
00087 {    
00088     m_report = "";
00089     
00090     if (!m_creator)
00091     {
00092         addReport("Creator is not set, contact plugin's developer");
00093         RELLOG(getName() << " -> creator is not set!!!");
00094         return false;
00095     }
00096 
00097     DBGLOG_ALGO(getName() << " -> " << input.count()
00098                 << (input.count() != 1 ? "automata" : "automaton") << "on input");
00099 
00100     bool ret = runInternal(input, result);
00101     
00102     // fill report if required
00103     if (report)
00104     {
00105         *report = m_report;
00106     }
00107     
00108     return ret;
00109 }
00110 
00111 IState::TIStateNameSet BasicAlgorithm::getEpsilonClosure
00112     (const QSharedPointer<IAutomaton> &automaton, const QSharedPointer<IState> &state) const
00113 {
00114     IState::TIStateNameSet result;
00115     
00116     QQueue<QSharedPointer<IState> > openedStates;
00117     openedStates.enqueue(state);
00118 
00119     QSharedPointer<IState> currentState;
00120     QString workState;
00121 
00122     while(!openedStates.empty())
00123     {
00124         currentState = openedStates.dequeue();
00125         result << currentState->getName();
00126 
00127         foreach(const QSharedPointer<ITransition> &tr, currentState->getTransitions())
00128         {            
00129             if (tr->getCharacters().contains(automaton->getEpsilonSymbol()))
00130             {
00131                 workState = tr->getDestinationState();
00132                 
00133                 if (result.contains(workState)) continue;
00134                 result << workState;
00135 
00136                 openedStates << automaton->getState(workState);
00137             }
00138         }
00139     }
00140 
00141     return result;
00142 }
00143 
00144 bool BasicAlgorithm::removeEpsilonTransitions(QSharedPointer<IAutomaton> &automaton) const
00145 {
00146     QSharedPointer<IAlgorithm> epsAlgorithm(new RemoveEpsilonAlgorithm());
00147     epsAlgorithm->setAutomataCreator(m_creator);
00148 
00149     IAutomaton::TAutomataList automata;
00150     automata << automaton;
00151     
00152     QString report;
00153     if (!epsAlgorithm->run(automata, automaton, &report))
00154     {
00155         addReport(report);
00156         return false;
00157     }
00158     
00159     return true;
00160 }
00161 
00162 bool BasicAlgorithm::removeMultipleInitials(QSharedPointer<IAutomaton> &automaton) const
00163 {
00164     QSharedPointer<IAlgorithm> miAlgorithm(new RemoveMultipleInitialsAlgorithm());
00165     miAlgorithm->setAutomataCreator(m_creator);
00166 
00167     IAutomaton::TAutomataList automata;
00168     automata << automaton;
00169     
00170     QString report;
00171     if (!miAlgorithm->run(automata, automaton, &report))
00172     {
00173         addReport(report);
00174         return false;
00175     }
00176     
00177     return true;
00178 }
00179 
00180 bool BasicAlgorithm::determinize(QSharedPointer<IAutomaton> &automaton) const
00181 {
00182     QSharedPointer<IAlgorithm> determinizeAlg(new DeterminizeAlgorithm());
00183     determinizeAlg->setAutomataCreator(m_creator);
00184     
00185     IAutomaton::TAutomataList automata;
00186     automata << automaton;
00187     
00188     QString report;
00189     if (!determinizeAlg->run(automata, automaton, &report))
00190     {
00191         addReport(report);
00192         return false;
00193     }
00194     
00195     return true;
00196 }
00197 
00198 void BasicAlgorithm::makeSureNameUnique(const QSharedPointer<IAutomaton> &automaton,
00199                                         QString &name) const
00200 {
00201     bool changed = false;
00202     while(automaton->hasState(name))
00203     {
00204         name += "*";
00205         changed = true;
00206     }
00207 }
00208 
00209 void BasicAlgorithm::makeSureNamesUnique(const QSharedPointer<IAutomaton> &automaton1,
00210                                          const QSharedPointer<IAutomaton> &automaton2) const
00211 {
00212     IState::TIStateList a2States = automaton2->getStates();
00213     foreach(const QSharedPointer<IState> &state, a2States)
00214     {
00215         bool changed = false;
00216         QString newName = state->getName();
00217         while(automaton1->hasState(newName) || 
00218              (changed && automaton2->hasState(newName)))
00219         {
00220             newName += "*";
00221             changed = true;
00222         }
00223         if (changed)
00224             automaton2->renameState(state, newName);
00225     }
00226 }
00227 
00228 void BasicAlgorithm::addReport(const QString &text) const
00229 {
00230     m_report += text;
00231 }
00232 
00233 bool BasicAlgorithm::tryMergeAlphabet(const ITransition::TCharSet &alphabet1,
00234                                       const ITransition::TCharSet &alphabet2,
00235                                       ITransition::TCharSet &alphabet) const
00236 {
00237     // check if one of alphabets if subset of the other
00238     ITransition::TCharSet intersection = alphabet1 & alphabet2;
00239     if (!(alphabet1 - intersection).empty() &&
00240         !(alphabet2 - intersection).empty())
00241     {
00242         return false;
00243     }
00244 
00245     alphabet = alphabet1;
00246     alphabet |= alphabet2;
00247     return true;
00248 }
00249 
00250 //----------------------------------------------------------------------- BasicAlgorithm -->
00251 
00252 
00253 
00254 //<-- BasicAlgorithmWithSettings -----------------------------------------------------------
00255 
00256 BasicAlgorithmWithSettings::BasicAlgorithmWithSettings(bool preserveNames, bool preserveLabels)
00257 :   m_preserveNames(preserveNames), m_preserveLabels(preserveLabels)
00258 {}
00259 
00260 void BasicAlgorithmWithSettings::runSettingsDialog(QWidget *parent)
00261 {
00262     SettingsDialog sd(*this, parent);
00263     
00264     if (sd.exec() == QDialog::Rejected) return;
00265     
00266     setPreserveNames(sd.preserveNames());
00267     setPreserveLabels(sd.preserveLabels());
00268     
00269     // TODO: make settings persistent (store it somewhere)
00270 }
00271 
00272 QString BasicAlgorithmWithSettings::chooseStateName(QSharedPointer<IAutomaton> &automaton,
00273                                                     const QStringList &nameList, int num) const
00274 {
00275     QString name;
00276     if (preserveNames())
00277         name = nameList.join(""); // don't use '[', ']' and ',' symbols due to VauCanSon-G format!
00278     else
00279         name = QString("Q%1").arg(num);
00280     
00281     makeSureNameUnique(automaton, name);
00282     return name;
00283 }
00284 
00285 QString BasicAlgorithmWithSettings::chooseStateLabel(const QStringList &labelList, int num) const
00286 {
00287     QString label;
00288     if (preserveLabels())
00289         label = labelList.join("");
00290     else
00291         label = QString("%1").arg(num);
00292     return label;
00293 }
00294 
00295 //----------------------------------------------------------- BasicAlgorithmWithSettings -->
00296 
00297 
00298 
00299 //<-- RemoveEpsilonAlgorithm ---------------------------------------------------------------
00300 
00301 RemoveEpsilonAlgorithm::~RemoveEpsilonAlgorithm()
00302 {
00303     DBGLOG_ALGO("deleted");
00304 }
00305 
00306 QString RemoveEpsilonAlgorithm::getName() const
00307 {
00308     return "Remove epsilon transitions";
00309 }
00310 
00311 bool RemoveEpsilonAlgorithm::runInternal(const IAutomaton::TAutomataList &input,
00312                                          QSharedPointer<IAutomaton> &result) const
00313 {
00314     if (input.empty())
00315     {        
00316         RELLOG("nothing on input");
00317         addReport("nothing on input");
00318         return false;
00319     }
00320     
00321     QSharedPointer<IAutomaton> automaton = input[0];
00322 
00323     typedef QMap<QString, IState::TIStateNameSet> TEpsilonClosureMap;
00324     TEpsilonClosureMap closureMap;
00325     
00326     foreach(const QSharedPointer<IState> &state, automaton->getStates())
00327     {
00328         closureMap[state->getName()] = getEpsilonClosure(automaton, state);
00329         DBGLOG_ALGO("epsilonClosure(" << state->getName() << ")=" << closureMap[state->getName()]);
00330     }
00331 
00332     QSharedPointer<IAutomaton> newAutomaton = 
00333         m_creator->createAutomaton(automaton->getAlphabet(), automaton->getAlphabetSymbol(),
00334                                    automaton->getEpsilonSymbol());
00335 
00336     // TODO: should be really all original states included in the resulting automaton
00337     // copy states
00338     foreach(const QSharedPointer<IState> &currentState, automaton->getStates())
00339     {    
00340         newAutomaton->createState(currentState->getName(), currentState->getLabel(),
00341                                   currentState->isInitial(), currentState->isFinal());
00342     }
00343 
00344     bool ok = true;
00345     foreach(const QSharedPointer<IState> &currentState, newAutomaton->getStates())
00346     {
00347         bool isFinal = false;
00348 
00349         foreach(const QString &character, automaton->getAlphabet())
00350         {
00351             IState::TIStateNameSet destinations;
00352 
00353             ITransition::TCharSet charset;
00354             charset << character;
00355 
00356             foreach(const QString &stateName, closureMap[currentState->getName()])
00357             {
00358                 const QSharedPointer<IState> &state= automaton->getState(stateName);
00359                 isFinal = isFinal || state->isFinal();
00360                 
00361                 destinations |= state->getStatesOn(character);
00362             }
00363 
00364             foreach(const QString &stateName, destinations)
00365             {
00366                 newAutomaton->createTransition(currentState->getName(), stateName, charset);
00367             }
00368         }
00369         
00370         currentState->setFinal(isFinal);
00371     }
00372 
00373     if (ok)
00374     {
00375         result = newAutomaton;
00376         return true;
00377     }
00378 
00379     return false;
00380 }
00381 
00382 //--------------------------------------------------------------- RemoveEpsilonAlgorithm -->
00383 
00384 
00385 
00386 //<-- RemoveInaccessibleAlgorithm ----------------------------------------------------------
00387 
00388 RemoveInaccessibleAlgorithm::~RemoveInaccessibleAlgorithm()
00389 {
00390     DBGLOG_ALGO("deleted");
00391 }
00392 
00393 QString RemoveInaccessibleAlgorithm::getName() const
00394 {
00395     return "Remove inaccessible states";
00396 }
00397 
00398 bool RemoveInaccessibleAlgorithm::runInternal(const IAutomaton::TAutomataList &input,
00399                                               QSharedPointer<IAutomaton> &result) const
00400 {
00401     if (input.empty())
00402     {
00403         RELLOG("nothing on input");
00404         addReport("nothing on input");
00405         return false;
00406     }
00407     
00408     QSharedPointer<IAutomaton> automaton = input[0];
00409     
00410     QSharedPointer<IAutomaton> newAutomaton =
00411         m_creator->createAutomaton(automaton->getAlphabet(), automaton->getAlphabetSymbol(),
00412                                    automaton->getEpsilonSymbol());
00413 
00414     // 1) Q_0 = I; i = 1; // I .. initial states
00415     IState::TIStateNameSet  accessibleSet;
00416     IState::TIStateList     accessibleList;
00417     foreach(const QSharedPointer<IState> &state, automaton->getInitialStates())
00418     {
00419         accessibleSet << state->getName();
00420         accessibleList << state;        
00421         
00422         newAutomaton->createState(state->getName(), state->getLabel(), state->isInitial(), state->isFinal());        
00423     }
00424 
00425     IState::TIStateList newListQi;
00426     IState::TIStateList listQi = accessibleList;
00427     QSharedPointer<IState> newState;
00428     QSharedPointer<IState> currentState;
00429    
00430     bool ok = true;
00431     // small modification .. in next steps only newStates are needed in loop
00432     // 2) Q_i = {q: q isfrom d(p, a), p isfrom lastAddedStates, a isfrom T} U Q_i-1
00433     do
00434     {
00435         foreach(const QSharedPointer<IState> &state, listQi)
00436         {
00437             foreach(const QSharedPointer<ITransition> &tr, state->getTransitions())
00438             {
00439                 QString workState = tr->getDestinationState();
00440                 if (accessibleSet.contains(workState)) continue;
00441                 
00442                 accessibleSet << workState;
00443                 
00444                 currentState = automaton->getState(workState);
00445                 accessibleList << currentState;
00446                 newListQi << currentState;
00447                 
00448                 ok = ok && (newAutomaton->createState(currentState->getName(),
00449                                                       currentState->getLabel(),
00450                                                       currentState->isInitial(),
00451                                                       currentState->isFinal()) != NULL);
00452             }
00453         }
00454         
00455         listQi = newListQi;
00456         newListQi.clear();
00457     }
00458     while(!listQi.empty());
00459     
00460     if (!ok) return false;
00461     
00462     foreach(const QSharedPointer<IState> &state, accessibleList)
00463     {
00464         foreach(const QSharedPointer<ITransition> &tr, state->getTransitions())
00465         {
00466             if (!accessibleSet.contains(tr->getDestinationState())) continue;
00467             
00468             ok = ok && 
00469                 (newAutomaton->createTransition(tr->getSourceState(),
00470                                                 tr->getDestinationState(),
00471                                                 tr->getCharacters()) != NULL);
00472         }
00473     }
00474     
00475     if (ok)
00476     {
00477         result = newAutomaton;
00478         return true;
00479     }
00480     
00481     return false;
00482 }
00483 
00484 //---------------------------------------------------------- RemoveInaccessibleAlgorithm -->
00485 
00486 
00487 
00488 //<-- RemoveUselessAlgorithm --------------------------------------------------------------
00489 
00490 RemoveUselessAlgorithm::~RemoveUselessAlgorithm()
00491 {
00492     DBGLOG_ALGO("deleted");
00493 }
00494 
00495 QString RemoveUselessAlgorithm::getName() const
00496 {
00497     return "Remove useless states";
00498 }
00499 
00500 bool RemoveUselessAlgorithm::runInternal(const IAutomaton::TAutomataList &input,
00501                                           QSharedPointer<IAutomaton> &result) const
00502 {
00503     if (input.empty())
00504     {
00505         RELLOG("nothing on input");
00506         addReport("nothing on input");
00507         return false;
00508     }
00509     
00510     QSharedPointer<IAutomaton> automaton = input[0];
00511     
00512     QSharedPointer<IAutomaton> newAutomaton =
00513         m_creator->createAutomaton(automaton->getAlphabet(), automaton->getAlphabetSymbol(),
00514                                    automaton->getEpsilonSymbol());
00515 
00516     // 1) Q_0 = F; i = 1; // F .. final states
00517     IState::TIStateNameSet  usefulSet;
00518     IState::TIStateList     usefulList;
00519     foreach(const QSharedPointer<IState> &state, automaton->getFinalStates())
00520     {
00521         usefulSet << state->getName();
00522         usefulList << state;
00523         newAutomaton->createState(state->getName(),
00524                                   state->getLabel(),
00525                                   state->isInitial(),
00526                                   state->isFinal());
00527     }
00528 
00529     IState::TIStateList newListQi;
00530     IState::TIStateList listQi = usefulList;
00531     QSharedPointer<IState> newState;
00532     QSharedPointer<IState> currentState;
00533 
00534     // 2) Q_i = {q : p isfrom d(q, a), p isfrom Q_i-1} U Q_i-1    
00535     do
00536     {
00537         foreach(const QSharedPointer<IState> &state, listQi)
00538         {
00539             foreach(const QSharedPointer<ITransition> &tr, state->getTransitionsTo())
00540             {
00541                 QString workState = tr->getSourceState();
00542                 if (usefulSet.contains(workState)) continue;
00543                 
00544                 usefulSet << workState;
00545                 
00546                 currentState = automaton->getState(workState);
00547                 usefulList << currentState;
00548                 newListQi << currentState;
00549                 
00550                 newAutomaton->createState(currentState->getName(),
00551                                           currentState->getLabel(),
00552                                           currentState->isInitial(),
00553                                           currentState->isFinal());
00554             }
00555         }
00556         
00557         listQi = newListQi;
00558         newListQi.clear();
00559     }
00560     while (!listQi.empty());
00561 
00562     bool ok = true;
00563     foreach(const QSharedPointer<IState> &state, usefulList)
00564     {
00565         foreach(const QSharedPointer<ITransition> &tr, state->getTransitionsTo())
00566         {
00567             if (!usefulSet.contains(tr->getSourceState())) continue;
00568             
00569             ok = ok && (newAutomaton->createTransition(tr->getSourceState(),
00570                                                        tr->getDestinationState(),
00571                                                        tr->getCharacters()) != NULL);
00572         }
00573     }
00574     
00575     if (ok)
00576     {
00577         result = newAutomaton;
00578         return true;
00579     }
00580     
00581     return false;
00582 }
00583 
00584 //-------------------------------------------------------------- RemoveUselessAlgorithm -->
00585 
00586 
00587 
00588 //<-- RemoveMultipleInitialsAlgorithm ------------------------------------------------------
00589 
00590 RemoveMultipleInitialsAlgorithm::~RemoveMultipleInitialsAlgorithm()
00591 {
00592     DBGLOG_ALGO("deleted");
00593 }
00594 
00595 QString RemoveMultipleInitialsAlgorithm::getName() const
00596 {
00597     return "Remove multiple inital states";
00598 }
00599 
00600 bool RemoveMultipleInitialsAlgorithm::runInternal(const IAutomaton::TAutomataList &input,
00601                                                   QSharedPointer<IAutomaton> &result) const
00602 {
00603     if (input.empty())
00604     {
00605         RELLOG("nothing on input");
00606         addReport("nothing on input");
00607         return false;
00608     }
00609     
00610     QSharedPointer<IAutomaton> automaton = input[0];
00611 
00612     // 1) q0 = I // I ... initial states    
00613     IState::TIStateList initialStates = automaton->getInitialStates();
00614     
00615     if (initialStates.empty())
00616         return false; // no inital states!
00617     
00618     if (initialStates.count() == 1)
00619     {
00620         result = automaton;
00621         return true;
00622     }
00623     
00624     QStringList q0NameList, q0LabelList;
00625     bool q0final = false;    
00626     foreach(const QSharedPointer<IState> &state, initialStates)
00627     {
00628         q0NameList << state->getName();
00629         q0LabelList << state->getLabel();
00630         state->setInitial(false);
00631         q0final = q0final || state->isFinal();
00632     }
00633     
00634     QString q0Name = "["+q0NameList.join(",")+"]";
00635     makeSureNameUnique(automaton, q0Name);
00636     
00637     // 3) Q' = Q U {q0}
00638     automaton->createState(q0Name,
00639                            q0LabelList.join(""),
00640                            true,
00641                            // 4,5) if some q in I is final, q0 is final too
00642                            q0final);
00643                             
00644     // 2) d'(q0,a) = U d(q, a), q isfrom I, a isfrom T                          
00645     foreach(const QSharedPointer<IState> &state, initialStates)
00646     {
00647         foreach(const QSharedPointer<ITransition> &tr, state->getTransitions())
00648         {
00649             automaton->createTransition(q0Name, tr->getDestinationState(), tr->getCharacters());
00650         }
00651     }
00652     
00653     // here could arise some inacessible states (from originally initial states), so remove them
00654     // (if state was originally intial and no transition from q0 (new initial) leads to it, is now inaccessible)
00655     foreach(const QSharedPointer<IState> &state, initialStates)
00656     {
00657         bool accessible = false;
00658         foreach(const QSharedPointer<ITransition> &tr, state->getTransitionsTo())
00659         {
00660             accessible |= (tr->getSourceState() == q0Name);
00661         }
00662         
00663         if (!accessible)
00664             automaton->removeState(state);
00665     }
00666     
00667     result = automaton;
00668     return true;
00669 }
00670 
00671 //------------------------------------------------------ RemoveMultipleInitialsAlgorithm -->
00672 
00673 
00674 
00675 //<-- DeterminizeAlgorithm -----------------------------------------------------------------
00676 
00677 DeterminizeAlgorithm::DeterminizeAlgorithm()
00678 :   BasicAlgorithmWithSettings(false, true)
00679 {}
00680 
00681 DeterminizeAlgorithm::~DeterminizeAlgorithm()
00682 {
00683     DBGLOG_ALGO("deleted");
00684 }
00685 
00686 QString DeterminizeAlgorithm::getName() const
00687 {
00688     return "Determinize automaton";
00689 }
00690 
00691 bool DeterminizeAlgorithm::runInternal(const IAutomaton::TAutomataList &input,
00692                                        QSharedPointer<IAutomaton> &result) const
00693 {
00694     if (input.empty())
00695     {
00696         RELLOG("nothing on input");
00697         addReport("nothing on input");
00698         return false;
00699     }
00700     
00701     QSharedPointer<IAutomaton> automaton = input[0];
00702     if (automaton->hasEpsilonTransitions())
00703     {
00704         if (!removeEpsilonTransitions(automaton))
00705             return false;
00706     }
00707     
00708     if (automaton->hasMultipleInitials())
00709     {
00710         if (!removeMultipleInitials(automaton))
00711             return false;
00712     }
00713     
00714     // now automaton is prepared
00715     Q_ASSERT(automaton->getInitialStates().count() == 1);
00716     
00717     QSharedPointer<IAutomaton> automatonDFA(m_creator->createAutomaton(automaton->getAlphabet(),
00718                                                                        automaton->getAlphabetSymbol(),
00719                                                                        automaton->getEpsilonSymbol()));
00720     
00721     int stateNum = 0;
00722     
00723     // 4) q0' = q0
00724     QSharedPointer<IState> newState = (automaton->getInitialStates())[0];
00725     QStringList newStateNameList(newState->getName());
00726     
00727     QString newStateName = chooseStateName(automatonDFA, newStateNameList, stateNum);
00728     QString newStateLabel = chooseStateLabel(QStringList(newState->getLabel()), stateNum);
00729     newState = automatonDFA->createState(newStateName, newStateLabel, true, newState->isFinal());
00730     stateNum++;
00731     
00732     // 1) Q' = {{q0}}, q0 .. no marked
00733     QQueue<QSharedPointer<IState> > openedStates;
00734     openedStates.enqueue(newState);
00735         
00736     QMap<QString, QStringList> nameToNameListMap;
00737     nameToNameListMap[newStateName] = newStateNameList;    
00738     
00739     // 2) all states in Q' marked, goto 4)
00740     while (!openedStates.empty())
00741     {
00742         QSharedPointer<IState> currentState = openedStates.dequeue();
00743         
00744         // 3a) d'(q',a) = U_(p isform q') d(p, a), foreach a isform T
00745         ITransition::TCharSet alphabet = automaton->getAlphabet();
00746         foreach(const QString &character, alphabet)
00747         {
00748             IState::TIStateNameSet newStateNameSet;            
00749             
00750             Q_ASSERT(nameToNameListMap.contains(currentState->getName()));
00751             QStringList origNameList = nameToNameListMap[currentState->getName()];
00752             foreach(const QString &stateName, origNameList)
00753             {
00754                 QSharedPointer<IState> state = automaton->getState(stateName); // get original automaton's state
00755                 newStateNameSet |= state->getStatesOn(character);                
00756             }
00757             
00758             if (newStateNameSet.empty()) continue; // no next state
00759             
00760             newStateNameList = newStateNameSet.toList();
00761             qSort(newStateNameList); // required since QSet's elements is in undefined order
00762             
00763             QStringList newStateLabelList;
00764             bool newStateIsFinal = false;
00765             // 5) F' = { q' : q' isform Q', q' intersect F not empty }
00766             foreach(const QString &partName, newStateNameSet)
00767             {
00768                 QSharedPointer<IState> state = automaton->getState(partName);
00769                 newStateIsFinal = newStateIsFinal || state->isFinal();
00770                 newStateLabelList << state->getLabel();
00771             }
00772             
00773             if (nameToNameListMap.values().contains(newStateNameList))
00774             {                
00775                 newState = automatonDFA->getState(nameToNameListMap.key(newStateNameList));
00776                 
00777                 //DBGLOG("Adding tr: " << currentState->getName() << "," << newState->getName() << " on char " << character);
00778                 automatonDFA->createTransition(currentState->getName(), newState->getName(),
00779                                                (ITransition::TCharSet() << character));
00780                 
00781                 continue; // not add state more than once
00782             }
00783             
00784             newStateName = chooseStateName(automatonDFA, newStateNameList, stateNum);            
00785             newStateLabel = chooseStateLabel(newStateLabelList, stateNum);
00786             
00787             // now we have to create new state which belongs to DFA
00788             newState = automatonDFA->createState(newStateName, newStateLabel, false, newStateIsFinal);
00789             stateNum++;
00790             
00791             openedStates.enqueue(newState);
00792             nameToNameListMap[newStateName] = newStateNameList;
00793             
00794             //DBGLOG("Adding tr: " << currentState->getName() << "," << newStateName << " on char " << character);
00795             automatonDFA->createTransition(currentState->getName(), newStateName,
00796                                            (ITransition::TCharSet() << character));
00797         }
00798     }
00799     
00800     result = automatonDFA;
00801     
00802     return true;
00803 }
00804 
00805 //----------------------------------------------------------------- DeterminizeAlgorithm -->
00806 
00807 
00808 
00809 //<-- MinimalizeAlgorithm ------------------------------------------------------------------
00810 
00811 class GroupItem
00812 {
00813 public:
00814     typedef QStringList  TTrList;
00815 
00816     explicit GroupItem(const QString &state, const TTrList &trList = TTrList(), bool initial = false)
00817     :   m_state(state), m_trList(trList), m_initial(initial)
00818     {}
00819     
00820     QString getState() const { return m_state; }
00821     TTrList getTrList() const { return m_trList; }
00822     bool isInitial() const { return m_initial; }
00823     
00824 private:
00825     QString             m_state;
00826     TTrList             m_trList;
00827     bool                m_initial;
00828 };
00829 
00830 inline bool operator==(const GroupItem &lhs, const GroupItem &rhs)
00831 {
00832     return lhs.getState() == rhs.getState();
00833 }
00834 
00835 inline uint qHash(const GroupItem &key)
00836 {
00837     return qHash(key.getState());
00838 }
00839 
00840 class Group
00841 {
00842 public:
00843     typedef QVector<QSharedPointer<Group> >     TGroupList;
00844     typedef QSet<GroupItem>                     TItemSet;
00845     
00846     Group(int id)
00847     : m_id(id)
00848     {}
00849     
00850     int id() const { return m_id; }
00851     
00852     int count() const { return m_states.count(); }
00853     
00854     bool contains(const QString &state) const { return m_states.contains(GroupItem(state)); }
00855     
00856     TItemSet items() const { return m_states; }
00857     
00858     void insert(const GroupItem &state) { m_states << state; }
00859     
00860     bool initial() const
00861     {        
00862         foreach(const GroupItem &state, m_states)
00863         {
00864             if (state.isInitial()) return true;
00865         }
00866         return false;
00867     }
00868     
00869     //! number of groups can be increased, return true if is splitted
00870     //! only current group can be changed due tu splitting (new group is than added)
00871     TGroupList computeAndSplit(const TGroupList &groups)
00872     {
00873         QList<QVector<int> > trGroupLists;
00874         TGroupList newGroups;
00875         
00876         TItemSet::Iterator stateIt = m_states.begin();
00877         while(stateIt != m_states.end())
00878         {   
00879             QVector<int> trGroupList = computeTransitionGroupList(groups, stateIt->getTrList());            
00880             
00881             int idx = -1;
00882             if ((idx = trGroupLists.indexOf(trGroupList)) != -1) // just existing group
00883             {
00884                 Q_ASSERT(newGroups.count() > idx && trGroupLists.count() > idx);
00885                 newGroups[idx]->insert(*stateIt); // add to right group
00886             }
00887             else // create new group
00888             {
00889                 trGroupLists << trGroupList;
00890                 newGroups << QSharedPointer<Group>(new Group(newGroups.count())); // create new group with original id
00891                 newGroups.last()->insert(*stateIt);                               // and add state to it
00892             }
00893             
00894             ++stateIt;
00895         }
00896         
00897         return newGroups;
00898     }
00899     
00900 protected:
00901     typedef QVector<int>    TTrGroupList;
00902     TTrGroupList computeTransitionGroupList(const TGroupList &groups, 
00903                                             const GroupItem::TTrList &trList)
00904     {
00905         TTrGroupList trGroupList;
00906         trGroupList.reserve(trList.count());        
00907         for (GroupItem::TTrList::ConstIterator trIt = trList.begin();
00908              trIt != trList.end();
00909              ++trIt)
00910         {
00911             if (*trIt == "")
00912             {
00913                 trGroupList << -1;
00914                 continue;
00915             }
00916             
00917             for (TGroupList::ConstIterator groupIt = groups.begin();
00918                  groupIt != groups.end();
00919                  ++groupIt)
00920             {
00921                 if ((*groupIt)->contains(*trIt))
00922                 {
00923                     trGroupList << (*groupIt)->id();
00924                     break;
00925                 }
00926             }
00927         }
00928         
00929         Q_ASSERT(trGroupList.count() == trList.count());
00930         return trGroupList;
00931     }
00932     
00933 private:
00934     TItemSet        m_states;
00935     int             m_id;
00936 };
00937 
00938 #ifndef QT_NO_DEBUG_OUTPUT
00939 
00940 QDebug operator<<(QDebug dbg, const Group &g)
00941 {
00942     dbg.nospace() << "Group "<< g.id() << ": (";
00943     Group::TItemSet items = g.items();
00944     for (Group::TItemSet::ConstIterator itemIt = items.begin();
00945          itemIt != items.end();
00946          ++itemIt)
00947     {
00948         if (itemIt != items.begin())
00949             dbg.nospace() << ",";
00950         dbg.nospace() << itemIt->getState();
00951     }
00952     dbg.nospace() << ")";
00953     return dbg.nospace();
00954 }
00955 
00956 #endif
00957 
00958 MinimalizeAlgorithm::~MinimalizeAlgorithm()
00959 {
00960     DBGLOG_ALGO("deleted");
00961 }
00962 
00963 QString MinimalizeAlgorithm::getName() const
00964 {
00965     return "Minimalize automaton";
00966 }
00967 
00968 bool MinimalizeAlgorithm::runInternal(const IAutomaton::TAutomataList &input,
00969                                       QSharedPointer<IAutomaton> &result) const
00970 {
00971     if (input.empty())
00972     {
00973         RELLOG("nothing on input");
00974         addReport("nothing on input");
00975         return false;
00976     }
00977     
00978     QSharedPointer<IAutomaton> automaton = input[0];
00979     
00980     if (!automaton->isDeterministic())
00981     {
00982         if (!determinize(automaton))
00983             return false;
00984     }
00985     
00986     // now automaton is prepared
00987     Q_ASSERT(automaton->getInitialStates().count() == 1);
00988     
00989     QStringList alphabet = automaton->getAlphabet().toList();
00990     qSort(alphabet);
00991     
00992     Group::TGroupList groups;
00993     // create two groups, one for final states and second for other
00994     groups << QSharedPointer<Group>(new Group(groups.count())); // final states
00995     groups << QSharedPointer<Group>(new Group(groups.count())); // other
00996     foreach(const QSharedPointer<IState> &state, automaton->getStates())
00997     {
00998         GroupItem::TTrList trList;
00999         foreach(const QString &character, alphabet)
01000         {
01001             IState::TIStateNameSet statesOn = state->getStatesOn(character);
01002             Q_ASSERT(statesOn.count() < 2); // it's deterministic automaton
01003             if (statesOn.isEmpty())
01004                 trList << "";
01005             else
01006                 trList << *statesOn.begin();
01007         }
01008         
01009         if (state->isFinal())   groups[0]->insert(GroupItem(state->getName(), trList, state->isInitial()));
01010         else                    groups[1]->insert(GroupItem(state->getName(), trList, state->isInitial()));
01011     }
01012 
01013     // if no final state exists, remove final group
01014     if (groups[0]->count() == 0) // TODO: should this be reduced as no automaton (all states are useless)
01015     {
01016         groups.remove(0);
01017     }
01018     
01019     while (true)
01020     {
01021         Group::TGroupList newGroups;
01022         for (Group::TGroupList::ConstIterator groupIt = groups.begin();
01023              groupIt != groups.end();
01024              ++groupIt)
01025         {
01026             newGroups << (*groupIt)->computeAndSplit(groups);
01027         }
01028         
01029         if (newGroups.count() == groups.count())
01030             break;
01031         
01032         groups = newGroups;
01033     }
01034     
01035 #ifndef QT_NO_DEBUG_OUTPUT
01036     for (Group::TGroupList::ConstIterator groupIt = groups.begin();
01037          groupIt != groups.end();
01038          ++groupIt)
01039     {
01040         DBGLOG_ALGO(**groupIt);
01041     }
01042 #endif
01043     
01044     IState::TIStateNameSet removedStates;
01045     // remove equivalent states and reconnect all transitions which lead to them
01046     for (Group::TGroupList::ConstIterator groupIt = groups.begin();
01047          groupIt != groups.end();
01048          ++groupIt)
01049     {
01050         Q_ASSERT((*groupIt)->count() != 0 && "shouldn't be empty!");
01051         
01052         Group::TItemSet items = (*groupIt)->items();
01053         
01054         Group::TItemSet::ConstIterator itemIt = items.begin();
01055         QString firstStateName = itemIt->getState();
01056         
01057         if ((*groupIt)->initial()) // set state inital if some state in group is
01058         {
01059             QSharedPointer<IState> state = automaton->getState(firstStateName);
01060             state->setInitial(true);
01061         }
01062         
01063         ++itemIt;        
01064         while (itemIt != items.end())
01065         {
01066             QSharedPointer<IState> state = automaton->getState(itemIt->getState());
01067             ITransition::TITransitionList transitionsTo = state->getTransitionsTo();
01068             foreach(const QSharedPointer<ITransition> &tr, transitionsTo)
01069             {
01070                 if (removedStates.contains(tr->getSourceState())) // don't reconnect loops from removed states
01071                     continue;
01072                 if (tr->getSourceState() == tr->getDestinationState()) // don't reconnect loops
01073                     continue;
01074                 automaton->createTransition(tr->getSourceState(), firstStateName, tr->getCharacters());
01075             }
01076             
01077             automaton->removeState(state);
01078             removedStates << state->getName();
01079             ++itemIt;
01080         }
01081     }
01082     
01083     result = automaton;
01084     
01085     return true;
01086 }
01087 
01088 //------------------------------------------------------------------ MinimalizeAlgorithm -->
01089 
01090 
01091 
01092 //<-- UniteParallelAlgorithm ---------------------------------------------------------------
01093 
01094 UniteParallelAlgorithm::UniteParallelAlgorithm()
01095 :   BasicAlgorithmWithSettings(false, true)
01096 {}
01097 
01098 UniteParallelAlgorithm::~UniteParallelAlgorithm()
01099 {
01100     DBGLOG_ALGO("deleted");
01101 }
01102 
01103 QString UniteParallelAlgorithm::getName() const
01104 {
01105     return "Unite automata - parallel running";
01106 }
01107 
01108 bool UniteParallelAlgorithm::runInternal(const IAutomaton::TAutomataList &input,
01109                                  QSharedPointer<IAutomaton> &result) const
01110 {
01111     if (input.count() < 2)
01112     {
01113         RELLOG("not enough automata on input");
01114         addReport("not enough automata on input, required 2");
01115         return false;
01116     }
01117     
01118     QSharedPointer<IAutomaton> automaton1 = input[0];
01119     QSharedPointer<IAutomaton> automaton2 = input[1];
01120     
01121     ITransition::TCharSet alphabet = automaton1->getAlphabet();
01122     if (automaton1->getAlphabet() != automaton2->getAlphabet())
01123     {
01124         if (!tryMergeAlphabet(automaton1->getAlphabet(), automaton2->getAlphabet(), alphabet))
01125         {
01126             addReport("inconsistent alphabets on input, alphabets have to be same or one has to be a subset of the other!\n"
01127                       "try to set alphabet manually ...");
01128             RELLOG("not same alphabets");
01129             return false;
01130         }
01131     }
01132     
01133     if (automaton1->getAlphabetSymbol() != automaton2->getAlphabetSymbol() ||
01134         automaton1->getEpsilonSymbol() != automaton2->getEpsilonSymbol())
01135     {
01136         addReport("not same automata symbols settings, use same epsilon and alphabet symbol!");
01137         RELLOG("not same automata symbols settings");
01138         return false;
01139     }
01140     
01141     // prepare input
01142     if (automaton1->hasEpsilonTransitions())
01143         if (!removeEpsilonTransitions(automaton1))
01144             return false;
01145     if (automaton2->hasEpsilonTransitions())
01146         if (!removeEpsilonTransitions(automaton2))
01147             return false;
01148     
01149     if (automaton1->hasMultipleInitials())
01150         if (!removeMultipleInitials(automaton1))
01151             return false;
01152     if (automaton2->hasMultipleInitials())
01153         if (!removeMultipleInitials(automaton2))
01154             return false;
01155     
01156     QSharedPointer<IAutomaton> automatonUnited(m_creator->createAutomaton(alphabet,
01157                                                                           automaton1->getAlphabetSymbol(),
01158                                                                           automaton1->getEpsilonSymbol()));
01159     
01160     makeSureNamesUnique(automaton1, automaton2);
01161 
01162     Q_ASSERT(automaton1->getInitialStates().count() == 1);
01163     Q_ASSERT(automaton2->getInitialStates().count() == 1);
01164     // simulate parlalel running
01165     QSharedPointer<IState> state1 = automaton1->getInitialStates()[0];
01166     QSharedPointer<IState> state2 = automaton2->getInitialStates()[0];
01167     
01168     int stateNum = 0;
01169     
01170     QStringList newStateNameList = QStringList() << state1->getName() << state2->getName();
01171     QString newStateName = chooseStateName(automatonUnited, newStateNameList, stateNum);
01172     QString newStateLabel = chooseStateLabel((QStringList() << state1->getLabel() << state2->getLabel()), stateNum);
01173     QSharedPointer<IState> newState = 
01174         automatonUnited->createState(newStateName, newStateLabel, true, state1->isFinal() || state2->isFinal());    
01175     stateNum++;
01176     
01177     QQueue<QSharedPointer<IState> > openedStates;    
01178     openedStates.enqueue(newState);
01179     
01180     QMap<QString, QStringList> nameToNameListMap;        
01181     nameToNameListMap[newState->getName()] = newStateNameList;
01182     
01183     while (!openedStates.empty())
01184     {
01185         QSharedPointer<IState> currentState = openedStates.dequeue();
01186         
01187         foreach(const QString &character, automatonUnited->getAlphabet())
01188         {
01189             IState::TIStateNameSet newStateNameSet;            
01190             
01191             Q_ASSERT(nameToNameListMap.contains(currentState->getName()));
01192             QStringList origNameList = nameToNameListMap[currentState->getName()];
01193             foreach(const QString &stateName, origNameList)
01194             {
01195                 Q_ASSERT(automaton1->hasState(stateName) || automaton2->hasState(stateName));
01196                 // get original automaton's state
01197                 QSharedPointer<IState> state =
01198                     automaton1->hasState(stateName) ? automaton1->getState(stateName)
01199                                                     : automaton2->getState(stateName);
01200                 
01201                 newStateNameSet |= state->getStatesOn(character);
01202             }
01203             
01204             if (newStateNameSet.empty()) continue; // no next state
01205             
01206             newStateNameList = newStateNameSet.toList();
01207             qSort(newStateNameList); // required since QSet's elements is in undefined order
01208             
01209             bool newStateIsFinal = false;
01210             QStringList newStateLabelList;
01211             foreach(const QString &partName, newStateNameList)
01212             {
01213                 Q_ASSERT(automaton1->hasState(partName) || automaton2->hasState(partName));
01214                 const QSharedPointer<IState> state = 
01215                     automaton1->hasState(partName) ? automaton1->getState(partName)
01216                                                    : automaton2->getState(partName);
01217 
01218                  newStateIsFinal = newStateIsFinal || state->isFinal();
01219                  newStateLabelList << state->getLabel();
01220             }
01221             
01222             if (nameToNameListMap.values().contains(newStateNameList))
01223             {
01224                 newState = automatonUnited->getState(nameToNameListMap.key(newStateNameList));
01225                 
01226                 automatonUnited->createTransition(currentState->getName(), newState->getName(),
01227                                                  (ITransition::TCharSet() << character));
01228                 
01229                 continue; // not add state more than once
01230             }
01231             
01232             newStateName = chooseStateName(automatonUnited, newStateNameList, stateNum);
01233             newStateLabel = chooseStateLabel(newStateLabelList, stateNum);
01234             // now we have to create new state which belongs to united automaton
01235             newState = automatonUnited->createState(newStateName, newStateLabel, false, newStateIsFinal);
01236             stateNum++;
01237             
01238             openedStates.enqueue(newState);            
01239             nameToNameListMap[newStateName] = newStateNameList;
01240             
01241             automatonUnited->createTransition(currentState->getName(), newStateName,
01242                                               (ITransition::TCharSet() << character));
01243         }
01244     }
01245     
01246     result = automatonUnited;
01247     
01248     addReport("Automata united sucessfully\n");
01249     
01250     return true;
01251 }
01252 
01253 //--------------------------------------------------------------- UniteParallelAlgorithm -->
01254 
01255 
01256 
01257 //<-- IntersectionParallelAlgorithm --------------------------------------------------------
01258 
01259 IntersectionParallelAlgorithm::IntersectionParallelAlgorithm()
01260 :   BasicAlgorithmWithSettings(false, true)
01261 {}
01262 
01263 IntersectionParallelAlgorithm::~IntersectionParallelAlgorithm()
01264 {
01265     DBGLOG_ALGO("deleted");
01266 }
01267 
01268 QString IntersectionParallelAlgorithm::getName() const
01269 {
01270     return "Intersect automata - parallel running";
01271 }
01272 
01273 bool IntersectionParallelAlgorithm::runInternal(const IAutomaton::TAutomataList &input,
01274                                                QSharedPointer<IAutomaton> &result) const
01275 {
01276     if (input.count() < 2)
01277     {
01278         RELLOG("not enough automata on input");
01279         addReport("not enough automata on input - required 2");
01280         return false;
01281     }
01282     
01283     QSharedPointer<IAutomaton> automaton1 = input[0];
01284     QSharedPointer<IAutomaton> automaton2 = input[1];
01285     
01286     ITransition::TCharSet alphabet = automaton1->getAlphabet();
01287     if (automaton1->getAlphabet() != automaton2->getAlphabet())
01288     {
01289         if (!tryMergeAlphabet(automaton1->getAlphabet(), automaton2->getAlphabet(), alphabet))
01290         {
01291             addReport("inconsistent alphabets on input, alphabets have to be same or one has to be a subset of the other!");
01292             RELLOG("not same alphabets");
01293             return false;
01294         }
01295     }
01296     
01297     if (automaton1->getAlphabetSymbol() != automaton2->getAlphabetSymbol() ||
01298         automaton1->getEpsilonSymbol() != automaton2->getEpsilonSymbol())
01299     {
01300         addReport("not same automata symbols settings, use same epsilon and alphabet symbol!");
01301         RELLOG("not same automata symbols settings");
01302         return false;
01303     }
01304 
01305     // prepare input
01306     if (automaton1->hasEpsilonTransitions())
01307         if (!removeEpsilonTransitions(automaton1))
01308             return false;
01309     if (automaton2->hasEpsilonTransitions())
01310         if (!removeEpsilonTransitions(automaton2))
01311             return false;
01312     
01313     if (automaton1->hasMultipleInitials())
01314         if (!removeMultipleInitials(automaton1))
01315             return false;
01316     if (automaton2->hasMultipleInitials())
01317         if (!removeMultipleInitials(automaton2))
01318             return false;
01319     
01320     QSharedPointer<IAutomaton> automatonIntersect(m_creator->createAutomaton(alphabet,
01321                                                                              automaton1->getAlphabetSymbol(),
01322                                                                              automaton1->getEpsilonSymbol()));
01323                                                                           
01324     Q_ASSERT(automaton1->getInitialStates().count() == 1);
01325     Q_ASSERT(automaton2->getInitialStates().count() == 1);
01326     
01327     makeSureNamesUnique(automaton1, automaton2);
01328     
01329     // simulate parlalel running
01330     QSharedPointer<IState> state1 = automaton1->getInitialStates()[0];
01331     QSharedPointer<IState> state2 = automaton2->getInitialStates()[0];
01332     
01333     int stateNum = 0;
01334     
01335     QStringList newStateNameList = QStringList() << state1->getName() << state2->getName();
01336     QString newStateName = chooseStateName(automatonIntersect, newStateNameList, stateNum);
01337     QString newStateLabel = chooseStateLabel((QStringList() << state1->getLabel() << state2->getLabel()), stateNum);
01338     QSharedPointer<IState> newState = 
01339         automatonIntersect->createState(newStateName, newStateLabel, true, state1->isFinal() && state2->isFinal());
01340     stateNum++;
01341     
01342     QQueue<QSharedPointer<IState> > openedStates;    
01343     openedStates.enqueue(newState);
01344         
01345     QMap<QString, QStringList> nameToNameListMap;
01346     nameToNameListMap[newState->getName()] = newStateNameList;   
01347     
01348     while (!openedStates.empty())
01349     {
01350         QSharedPointer<IState> currentState = openedStates.dequeue();
01351         
01352         foreach(const QString &character, automatonIntersect->getAlphabet())
01353         {
01354             IState::TIStateNameSet newStateNameSet;
01355             QStringList origNameList = nameToNameListMap[currentState->getName()];
01356             foreach(const QString &stateName, origNameList)
01357             {
01358                 Q_ASSERT(automaton1->hasState(stateName) || automaton2->hasState(stateName));
01359                 QSharedPointer<IState> state = 
01360                     automaton1->hasState(stateName) ? automaton1->getState(stateName)
01361                                                     : automaton2->getState(stateName);
01362                 
01363                 newStateNameSet |= state->getStatesOn(character);
01364             }
01365             
01366             if (newStateNameSet.empty()) continue; // no next state
01367             
01368             newStateNameList = newStateNameSet.toList();
01369             qSort(newStateNameList); // required since QSet's elements is in undefined order
01370             
01371             unsigned char belongsTo = 0;
01372             bool newStateIsFinal = true;
01373             QStringList newStateLabelList;
01374             foreach(const QString &partName, newStateNameList)
01375             {
01376                 Q_ASSERT(automaton1->hasState(partName) || automaton2->hasState(partName));
01377                 QSharedPointer<IState> state;
01378                 if (automaton1->hasState(partName))
01379                 {
01380                     state = automaton1->getState(partName);
01381                     belongsTo |= 1; // 0001b
01382                 }
01383                 else
01384                 {
01385                     state = automaton2->getState(partName);
01386                     belongsTo |= 2; // 0010b
01387                 }
01388                 
01389                 newStateIsFinal = newStateIsFinal && state->isFinal();
01390                 newStateLabelList << state->getLabel();
01391             }
01392             
01393             newStateIsFinal &= belongsTo == 3; // 0011b // has to belong to both automaton
01394             
01395             if (nameToNameListMap.values().contains(newStateNameList))
01396             {
01397                 newState = automatonIntersect->getState(nameToNameListMap.key(newStateNameList));
01398                 
01399                 automatonIntersect->createTransition(currentState->getName(), newState->getName(),
01400                                                      (ITransition::TCharSet() << character));
01401                 
01402                 continue; // not add state more than once
01403             }
01404             
01405             newStateName = chooseStateName(automatonIntersect, newStateNameList, stateNum);
01406             newStateLabel = chooseStateLabel(newStateLabelList, stateNum);
01407             
01408             // now we have to create new state which belongs to united automaton
01409             newState = automatonIntersect->createState(newStateName, newStateLabel, false, newStateIsFinal);
01410             stateNum++;
01411                         
01412             openedStates.enqueue(newState);
01413             nameToNameListMap[newStateName] = newStateNameList;
01414             
01415             automatonIntersect->createTransition(currentState->getName(), newStateName,
01416                                                  (ITransition::TCharSet() << character));
01417         }
01418     }
01419     
01420     result = automatonIntersect;
01421     
01422     addReport("Automata intersected sucessfully\n");
01423     
01424     return true;
01425 }
01426 
01427 //-------------------------------------------------------- IntersectionParallelAlgorithm -->
01428 
01429 
01430 
01431 /*------------------------------------------------------|
01432  * AlgorithmHolder -> exported from library             |
01433  *------------------------------------------------------V*/
01434 
01435 AlgorithmHolder::AlgorithmHolder()
01436 {}
01437 
01438 IAlgorithm::TAlgorithmList AlgorithmHolder::getAlgorithms() const
01439 {
01440     IAlgorithm::TAlgorithmList algorithmList;
01441 
01442 // one automaton algorithms
01443     algorithmList << QSharedPointer<IAlgorithm>(new RemoveEpsilonAlgorithm());
01444     algorithmList << QSharedPointer<IAlgorithm>(new RemoveInaccessibleAlgorithm());
01445     algorithmList << QSharedPointer<IAlgorithm>(new RemoveUselessAlgorithm());
01446     algorithmList << QSharedPointer<IAlgorithm>(new RemoveMultipleInitialsAlgorithm());
01447 
01448     algorithmList << QSharedPointer<IAlgorithm>(new DeterminizeAlgorithm());    
01449     algorithmList << QSharedPointer<IAlgorithm>(new MinimalizeAlgorithm());
01450    
01451 // two automata algorithms    
01452     algorithmList << QSharedPointer<IAlgorithm>(new UniteParallelAlgorithm());
01453     algorithmList << QSharedPointer<IAlgorithm>(new IntersectionParallelAlgorithm());
01454     
01455     return algorithmList;
01456 }
01457 
01458 AlgorithmHolder::~AlgorithmHolder()
01459 {
01460     DBGLOG_ALGO("deleted");
01461 }
01462 
01463 Q_EXPORT_PLUGIN2(algorithms, AlgorithmHolder)

Generated on Tue Jan 4 2011 03:03:21 for Autoamata editor by  doxygen 1.7.0