cfl_regular.cpp

Go to the documentation of this file.
00001 /** @file cfl_regular.cpp
00002 
00003 Operations on regular languages.
00004 See [Cassandras and Lafortune. Introduction to Discrete Event Systems] for an
00005 introduction to regular language operations.
00006 Operations are always performed on language(s) marked by the passed generator(s),
00007 resulting in the language(s) marked by the resulting generator(s).
00008 Only if mentioned extra, the same is done for the involved generated (prefix-closed)
00009 languages.
00010 
00011 */
00012 
00013 /* FAU Discrete Event Systems Library (libfaudes)
00014 
00015 Copyright (C) 2006  Bernd Opitz
00016 Exclusive copyright is granted to Klaus Schmidt
00017 
00018 This library is free software; you can redistribute it and/or
00019 modify it under the terms of the GNU Lesser General Public
00020 License as published by the Free Software Foundation; either
00021 version 2.1 of the License, or (at your option) any later version.
00022 
00023 This library is distributed in the hope that it will be useful,
00024 but WITHOUT ANY WARRANTY; without even the implied warranty of
00025 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026 Lesser General Public License for more details.
00027 
00028 You should have received a copy of the GNU Lesser General Public
00029 License along with this library; if not, write to the Free Software
00030 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00031 
00032   
00033 #include "cfl_regular.h"
00034 #include "cfl_determin.h"
00035 
00036 
00037 namespace faudes {
00038 
00039 // LanguageUnionNonDet(rGen1, rGen2, rResGen)
00040 void LanguageUnionNonDet(const Generator& rGen1, const Generator& rGen2,
00041        Generator& rResGen) {
00042             
00043   FD_DF("LanguageUnionNonDet("<< rGen1.Name() 
00044   << "," << rGen2.Name() << ")");
00045     
00046   // are state names enabled?
00047   bool stateNamesEnabled=rResGen.StateNamesEnabled();
00048     
00049   // use pointer pResGen to result rResGen; if rResGen is identical to
00050   // one of the parameters, allocate temporary object and copy back later
00051   Generator* pResGen = &rResGen;
00052   if(&rResGen== &rGen1 || &rResGen== &rGen2) {
00053     pResGen= rResGen.New();
00054   }
00055 
00056   // prepare result
00057   pResGen->Clear();
00058 
00059   // union of alphabets
00060   pResGen->InjectAlphabet(rGen1.Alphabet()+rGen2.Alphabet());
00061     
00062   // Maps from states of rGen1 and rGen2 to states of ResGen
00063   std::map<Idx,Idx> Gen1StatesMap;
00064   std::map<Idx,Idx> Gen2StatesMap;
00065     
00066   // "union" of states: insert states representing the states of rGen1 and rGen2
00067   StateSet::Iterator sit;
00068   for (sit = rGen1.StatesBegin(); sit != rGen1.StatesEnd(); ++sit) {
00069     if (stateNamesEnabled) {
00070       Gen1StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen1.StateName(*sit)+"(1)"));
00071     }
00072     else {
00073       Gen1StatesMap[*sit] = pResGen->InsState();
00074     }
00075   }
00076   for (sit = rGen2.StatesBegin(); sit != rGen2.StatesEnd(); ++sit) {
00077     if (stateNamesEnabled) {
00078       Gen2StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen2.StateName(*sit)+"(2)"));
00079     }
00080     else {
00081       Gen2StatesMap[*sit] = pResGen->InsState();
00082     }
00083   }
00084     
00085   // "union" of transition relations
00086   TransSet::Iterator tit;
00087   for (tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit) {
00088     pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen1StatesMap[tit->X2]);
00089   }
00090   for (tit = rGen2.TransRelBegin(); tit != rGen2.TransRelEnd(); ++tit) {
00091     pResGen->SetTransition(Gen2StatesMap[tit->X1], tit->Ev, Gen2StatesMap[tit->X2]);
00092   }
00093     
00094   // "union" of init states
00095   for (sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit) {
00096     pResGen->SetInitState(Gen1StatesMap[*sit]);
00097   }
00098   for (sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit) {
00099     pResGen->SetInitState(Gen2StatesMap[*sit]);
00100   }
00101     
00102   // "union" of marked states
00103   for (sit = rGen1.MarkedStatesBegin(); sit != rGen1.MarkedStatesEnd(); ++sit) {
00104     pResGen->SetMarkedState(Gen1StatesMap[*sit]);
00105   }
00106   for (sit = rGen2.MarkedStatesBegin(); sit != rGen2.MarkedStatesEnd(); ++sit) {
00107     pResGen->SetMarkedState(Gen2StatesMap[*sit]);
00108   }
00109     
00110   // set name of result
00111   pResGen->Name(CollapsString("UnionNonDet("+rGen1.Name()+","+rGen2.Name()+")"));
00112     
00113   // if necessary, move pResGen to rResGen
00114   if(pResGen != &rResGen) {
00115     pResGen->Move(rResGen);
00116     delete pResGen;
00117   }
00118     
00119 }
00120 
00121 // LanguageUnion(rGen1, rGen2, rResGen)
00122 void LanguageUnion(const Generator& rGen1, const Generator& rGen2, 
00123        Generator& rResGen) {
00124 
00125   FD_DF("LanguageUnion("<< rGen1.Name() 
00126   << "," << rGen2.Name() << ")");
00127    
00128   // fix name
00129   std::string name1 = rGen1.Name();
00130   std::string name2 = rGen2.Name();
00131 
00132   // avoid copy
00133   Generator* pTempGen = rResGen.New();
00134     
00135   // perform nondeterministic language union
00136   LanguageUnionNonDet(rGen1, rGen2, *pTempGen);
00137     
00138   // make deterministic
00139   Deterministic(*pTempGen, rResGen);
00140 
00141   // dispose temp
00142   delete pTempGen;
00143 
00144   // set name of result
00145   rResGen.Name(CollapsString("Union("+name1+","+name2+")"));
00146 
00147 }
00148 
00149 // LanguageUnion(rGenVec, rResGen)
00150 void LanguageUnion(const GeneratorVector& rGenVec, Generator& rResGen) {
00151 
00152   // ignore empty
00153   if(rGenVec.Size()==0) {
00154     return;
00155   }
00156 
00157   // copy one
00158   if(rGenVec.Size()==1) {
00159     rResGen=rGenVec.At(0);
00160     return;
00161   }
00162 
00163   // avoid final copy
00164   Generator* pTempGen = rResGen.New();
00165 
00166   // run union on others
00167   LanguageUnionNonDet(rGenVec.At(0),rGenVec.At(1),*pTempGen);
00168   for(GeneratorVector::Position i=2; i<rGenVec.Size(); i++) 
00169     LanguageUnionNonDet(rGenVec.At(i),*pTempGen,*pTempGen);
00170 
00171   // make deterministic
00172   Deterministic(*pTempGen, rResGen);
00173 
00174   // dispose temp
00175   delete pTempGen;
00176 
00177   // set name of result
00178   rResGen.Name(CollapsString("Union(...)"));
00179 }
00180 
00181 
00182 // LanguageIntersection(rGen1, rGen2, rResGen)
00183 void LanguageIntersection(const Generator& rGen1, const Generator& rGen2, 
00184         Generator& rResGen) {
00185   FD_DF("LanguageIntersection("<< rGen1.Name() 
00186   << "," << rGen2.Name() << ")");
00187     
00188   // fix name
00189   std::string name1 = rGen1.Name();
00190   std::string name2 = rGen2.Name();
00191 
00192   // the product of rGen1 and rGen2 implements the language intersection
00193   Product(rGen1, rGen2, rResGen);
00194   rResGen.Name(CollapsString("Intersection("+name1+","+name2+")"));
00195     
00196 }
00197 
00198 
00199 // LanguageIntersection(rGenVec, rResGen)
00200 void LanguageIntersection(const GeneratorVector& rGenVec, Generator& rResGen) 
00201 {
00202 
00203   // ignore empty
00204   if(rGenVec.Size()==0) {
00205     return;
00206   }
00207 
00208   // copy one
00209   if(rGenVec.Size()==1) {
00210     rResGen=rGenVec.At(0);
00211     return;
00212   }
00213 
00214   // run product on others
00215   LanguageIntersection(rGenVec.At(0),rGenVec.At(1),rResGen);
00216   for(GeneratorVector::Position i=2; i<rGenVec.Size(); i++) 
00217     LanguageIntersection(rGenVec.At(i),rResGen,rResGen);
00218 }
00219 
00220 
00221 // EmptyLanguageIntersection(rGen1, rGen2)
00222 bool EmptyLanguageIntersection(const Generator& rGen1, const Generator& rGen2) {
00223   FD_DF("EmptyLanguageIntersection("<< rGen1.Name() 
00224   << "," << rGen2.Name() << ")");
00225 
00226   // not tested for non-det automata
00227   bool g1_det = rGen1.IsDeterministic();
00228   bool g2_det = rGen2.IsDeterministic();
00229   if( (!g1_det) || (!g2_det)) {
00230     std::stringstream errstr;
00231     errstr << "EmptyLanguageIntersection has not been tested for nondeterministic generators";
00232     throw Exception("Product", errstr.str(), 201);
00233   }
00234 
00235   // Perform product and break when a marking is reached simultaneously)
00236 
00237   // todo stack
00238   std::stack< std::pair<Idx,Idx> > todo;
00239   std::set< std::pair<Idx,Idx> > done;
00240   // iterate variables
00241   std::pair<Idx,Idx> currentstates, newstates;
00242   StateSet::Iterator lit1, lit2;
00243   TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
00244   // convenience
00245   const StateSet& mark1 = rGen1.MarkedStates();
00246   const StateSet& mark2 = rGen2.MarkedStates();
00247   // restrict search to coaccessible states
00248   StateSet coac1 = rGen1.CoaccessibleSet();
00249   StateSet coac2 = rGen2.CoaccessibleSet();
00250 
00251   // push all combinations of coaccessible initial states on todo stack
00252   FD_DF("EmptyLanguageIntersection: push all combinations of initial states to todo:");
00253   StateSet init1 = coac1 * rGen1.InitStates();
00254   StateSet init2 = coac2 * rGen2.InitStates();
00255   for (lit1 = init1.Begin(); lit1 != init1.End(); ++lit1) {
00256     for (lit2 = init2.Begin(); lit2 != init2.End(); ++lit2) {
00257       currentstates = std::make_pair(*lit1, *lit2);
00258       todo.push(currentstates);
00259     }
00260   }
00261 
00262   // process todo stack
00263   bool empty = true;
00264   FD_DF("EmptyLanguageIntersection: processing reachable states:");
00265   while (!todo.empty()) {
00266     // allow for user interrupt
00267     // LoopCallback();
00268     // allow for user interrupt, incl progress report
00269     FD_WPC(done.size(),done.size()+todo.size(),"Product(): processing"); 
00270     // get next reachable state from todo stack
00271     currentstates = todo.top();
00272     todo.pop();
00273     done.insert(currentstates);
00274     FD_DF("EmptyLanguageIntersection: processing " << currentstates.first << "|" << currentstates.second);
00275     // test for sync acceptance (do this here to include initial states)
00276     if(mark1.Exists(currentstates.first) && mark2.Exists(currentstates.second)) {
00277        empty=false; 
00278        break;
00279     }
00280     // iterate over all rGen1/rGen2 transitions
00281     tit1 = rGen1.TransRelBegin(currentstates.first);
00282     tit1_end = rGen1.TransRelEnd(currentstates.first);
00283     tit2 = rGen2.TransRelBegin(currentstates.second);
00284     tit2_end = rGen2.TransRelEnd(currentstates.second);
00285     while((tit1 != tit1_end) && (tit2 != tit2_end)) {
00286       // shared event
00287       if(tit1->Ev == tit2->Ev) {
00288         // push new state
00289         newstates = std::make_pair(tit1->X2, tit2->X2);
00290         if(done.find(newstates)==done.end()) 
00291     if(coac1.Exists(newstates.first))
00292         if(coac2.Exists(newstates.second))
00293               todo.push(newstates);
00294         // increment transition
00295         ++tit1;
00296         ++tit2;
00297       }
00298       // try resync tit1
00299       else if (tit1->Ev < tit2->Ev) {
00300         ++tit1;
00301       }
00302       // try resync tit2
00303       else if (tit1->Ev > tit2->Ev) {
00304         ++tit2;
00305       }
00306     }
00307   }
00308 
00309 #ifdef FAUDES_CODE
00310   // Alternative test for validation
00311   Generator ProductGen;
00312   ProductGen.StateNamesEnabled(false);
00313   Product(rGen1, rGen2, ProductGen);
00314   bool altempty = IsEmptyLanguage(ProductGen);
00315   if(empty != altempty) {
00316     rGen1.Write();
00317     rGen2.Write();
00318     FD_ERR("EmptyLanguageIntersection(): ERROR  -- ref result: " << altempty);
00319   }
00320 #endif 
00321 
00322   // done
00323   return empty;
00324 }
00325 
00326 // LanguageDisjoint(rGen1, rGen2)
00327 bool LanguageDisjoint(const Generator& rGen1, const Generator& rGen2) {
00328   FD_DF("LanguageDisjoint("<< rGen1.Name() 
00329   << "," << rGen2.Name() << ")");
00330   return EmptyLanguageIntersection(rGen1,rGen2);
00331 }
00332 
00333 // Automaton(rGen)
00334 void Automaton(Generator& rGen, const EventSet& rAlphabet) {
00335   FD_DF("Automaton("<< rGen.Name() << "," << rAlphabet.Name() << ")");
00336     
00337   // for correct result, rGen has to be deterministic!
00338 #ifdef FAUDES_CHECKED
00339   if ( !(rGen.IsDeterministic()) ) {
00340     FD_WARN("Automaton(): nondeterministic parameter " << rGen.Name() <<".");
00341   }
00342 #endif 
00343 
00344   // prepare result
00345   rGen.Name(CollapsString("Automaton(" + rGen.Name() + "," + rAlphabet.Name() + ")"));
00346     
00347   // extend rGen.Alphabet() by rAlphabet
00348   rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
00349     
00350   // remove states that do not represent prefixes of marked strings
00351   rGen.Coaccessible();
00352     
00353   // introduce a dump state (unmarked)
00354   Idx dump;
00355   bool dumpReached=false; // record, whether dump state is indeed used
00356   if (rGen.StateNamesEnabled()) {
00357     std::string dumpstr=rGen.UniqueStateName("dump");
00358     dump = rGen.InsState(dumpstr);
00359   } else {
00360     dump = rGen.InsState();
00361   }
00362   
00363   // if there is no initial state, the dump state becomes the initial state
00364   // (required for automaton from empty language argument)
00365   if(rGen.InitStates().Empty()){
00366     rGen.SetInitState(dump);
00367     dumpReached=true;
00368   }
00369     
00370   // introduce transitions to dumpstate
00371   StateSet::Iterator sit;
00372   EventSet::Iterator eit;
00373   for (sit = rGen.StatesBegin(); sit != rGen.StatesEnd(); ++sit) {        
00374     for (eit = rGen.Alphabet().Begin(); eit != rGen.Alphabet().End(); ++eit) {
00375       // If no transition is defined for this state and event, insert respective
00376       // transition to dump state (note that dump state itself is also treated here
00377       // and thus provided with selfloops)
00378       if (rGen.TransRelBegin(*sit, *eit) == rGen.TransRelEnd(*sit, *eit)) {
00379   rGen.SetTransition(*sit, *eit, dump);
00380   // indicate that dumstate was reached
00381   if(*sit!=dump) dumpReached=true;
00382       }
00383     }        
00384   }
00385     
00386   // if no transition was introduced (except for selfloops), remove dump state
00387   if(!dumpReached) 
00388     rGen.DelState(dump);
00389 }
00390 
00391 // Automaton(rGen)
00392 void Automaton(Generator& rGen) {
00393   FD_DF("Automaton("<< rGen.Name() << ")");
00394   std::string name=rGen.Name();
00395   Automaton(rGen,rGen.Alphabet());    
00396   rGen.Name(CollapsString("Automaton(" + name + ")"));
00397 }
00398 
00399 // LanguageComplement(rGen,rAlphabet)
00400 void LanguageComplement(Generator& rGen, const EventSet& rAlphabet) {
00401   FD_DF("LanguageComplement("<< rGen.Name() << "," << rAlphabet.Name() << ")");
00402 
00403   // fix name
00404   std::string name = rGen.Name();  
00405   
00406   // convert to automaton (avoiding statename "dump")
00407   bool stateNamesEnabled=rGen.StateNamesEnabled(); 
00408   rGen.StateNamesEnabled(false); 
00409   Automaton(rGen,rAlphabet);
00410   rGen.StateNamesEnabled(stateNamesEnabled); 
00411     
00412   // invert marking
00413   rGen.InjectMarkedStates(rGen.States() - rGen.MarkedStates());
00414 
00415   // set name    
00416   rGen.Name(CollapsString("Complement(" + name + "," + rAlphabet.Name() + ")"));
00417 }
00418 
00419 // LanguageComplement(rGen)
00420 void LanguageComplement(Generator& rGen) {
00421   FD_DF("LanguageComplement("<< rGen.Name() << ")");
00422   std::string name=rGen.Name();
00423   LanguageComplement(rGen,rGen.Alphabet());
00424   rGen.Name(CollapsString("Complement(" + name + ")"));
00425   return;    
00426 }
00427 
00428 // language complement, uniform api
00429 void LanguageComplement(const Generator& rGen, Generator& rRes) {
00430   rRes=rGen;
00431   LanguageComplement(rRes);
00432 }
00433 
00434 
00435 // language complement, uniform api
00436 void LanguageComplement(const Generator& rGen, const EventSet& rSigma, Generator& rRes) {
00437   rRes=rGen;
00438   LanguageComplement(rRes,rSigma);
00439 }
00440 
00441 
00442 
00443 
00444 //LanguageDifference(rGen1, rGen2, rResGen)
00445 void LanguageDifference(
00446    const Generator& rGen1, 
00447    const Generator& rGen2,
00448    Generator& rResGen) {
00449          
00450      FD_DF("LanguageDifference("<< rGen1.Name() << "," << rGen2.Name() << ")");
00451 
00452     // incl. all-empty case
00453     if(IsEmptyLanguage(rGen2)) {
00454       rResGen.Assign(rGen1);
00455       rResGen.Name(CollapsString("LanguageDifference(" + rGen1.Name() + "," + rGen2.Name() + ")"));
00456       return;
00457     }
00458      
00459     // use pointer pResGen to result rResGen
00460     Generator* pResGen = &rResGen;
00461     if(&rResGen == &rGen1 || &rResGen== &rGen2) {
00462       pResGen = rResGen.New();
00463     }    
00464     
00465     // due to the use of LanguageComplement(), rGen2 has to be deterministic
00466     #ifdef FAUDES_CHECKED
00467     if(!(rGen2.IsDeterministic())){
00468       std::stringstream errstr;
00469       errstr << "Nondeterministic parameter " << rGen2.Name() << ".";
00470       throw Exception("LanguageDifference()", errstr.str(), 101);
00471     }
00472     #endif
00473           
00474     // prepare result
00475     pResGen->Clear();
00476      
00477     // calculate "Lm1-Lm2" by building the intersection of Lm1 with the complement of Lm2
00478     // for correct result, complement has to be computed wrt the alphabet of Lm1 (!)
00479         
00480     *pResGen=rGen2;
00481     LanguageComplement(*pResGen,rGen1.Alphabet());
00482     LanguageIntersection(rGen1, *pResGen, *pResGen);
00483         
00484   
00485     // if necessary, move pResGen to rResGen
00486     if(pResGen != &rResGen) {
00487       pResGen->Move(rResGen);
00488       delete pResGen;
00489     } 
00490     
00491     return;
00492 }
00493 
00494 // LanguageConcatenateNonDet(rGen1, rGen2, rResGen)
00495 void LanguageConcatenateNonDet(const Generator& rGen1, const Generator& rGen2, 
00496              Generator& rResGen) {
00497   FD_DF("LanguageConcatenateNonDet(" << rGen1.Name() << "," << rGen2.Name() << ")");
00498             
00499   // are state names enabled in result?
00500   bool stateNamesEnabled=rResGen.StateNamesEnabled();
00501     
00502   // use pointer pResGen to result rResGen
00503   Generator* pResGen = &rResGen;
00504   if(&rResGen== &rGen1 || &rResGen== &rGen2) {
00505     pResGen= rResGen.New();
00506   }
00507 
00508   // prepare result
00509   pResGen->Clear();
00510     
00511   // union of alphabets
00512   pResGen->InjectAlphabet(rGen1.Alphabet() + rGen2.Alphabet());
00513 
00514   // Maps from states of rGen1 and rGen2 to states of ResGen
00515   std::map<Idx,Idx> Gen1StatesMap;
00516   std::map<Idx,Idx> Gen2StatesMap;
00517 
00518   // helpers
00519   StateSet::Iterator sit;
00520   TransSet::Iterator tit;
00521     
00522   // "union" of states: insert states representing the states of rGen1 and rGen2
00523   for (sit = rGen1.StatesBegin(); sit != rGen1.StatesEnd(); ++sit) {
00524     if (stateNamesEnabled) {
00525       Gen1StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen1.StateName(*sit)+"(1)"));
00526     } else {
00527       Gen1StatesMap[*sit] = pResGen->InsState();
00528     }
00529   }
00530   for (sit = rGen2.StatesBegin(); sit != rGen2.StatesEnd(); ++sit) {
00531     if (stateNamesEnabled) {
00532       Gen2StatesMap[*sit] = pResGen->InsState(pResGen->UniqueStateName(rGen2.StateName(*sit)+"(2)"));
00533     } else {
00534       Gen2StatesMap[*sit] = pResGen->InsState();
00535     }
00536   }
00537 
00538   // "union" transitions: insert all rGen1 transitions
00539   for (tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit) 
00540     pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen1StatesMap[tit->X2]);
00541     
00542   // "union" transitions: insert all rGen2 transitions
00543   for (tit = rGen2.TransRelBegin(); tit != rGen2.TransRelEnd(); ++tit) 
00544     pResGen->SetTransition(Gen2StatesMap[tit->X1], tit->Ev, Gen2StatesMap[tit->X2]);
00545     
00546 
00547   // initial state bug (detected by Tomas Masopust, fix by Klaus Schmidt)
00548   // 1) copy all transitions to the result, clear initial/marked status
00549   // 2) all initial states of G1 become initial states in the result
00550   // 3) if L1 contains the empty string, also all initial states of G2 become initial states
00551   //    in the result
00552   // 4) transition leading to a marked state in G1 also become transitions to all
00553   //    initial states of G2
00554   // 5) marked states of G2 become marked in the result
00555 
00556 
00557   // test whether L1 includes the empty string
00558   bool concatenateEpsilon1=false;
00559   for(sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit) {
00560     if(rGen1.ExistsMarkedState(*sit)) {
00561       concatenateEpsilon1=true;
00562       break;
00563     }
00564   }
00565 
00566   // initial states of G1 become initial states in the result
00567   for (sit = rGen1.InitStatesBegin(); sit != rGen1.InitStatesEnd(); ++sit) 
00568     pResGen->SetInitState(Gen1StatesMap[*sit]);
00569     
00570   // if L1 contains the emtystring, G2 initial states become initial states in the result
00571   if(concatenateEpsilon1)
00572     for (sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit) 
00573       pResGen->SetInitState(Gen2StatesMap[*sit]);
00574     
00575   // any G1 transition to a marked state must also lead to all initial states of G2
00576   for(tit = rGen1.TransRelBegin(); tit != rGen1.TransRelEnd(); ++tit) 
00577     if(rGen1.ExistsMarkedState(tit->X2)) 
00578       for(sit = rGen2.InitStatesBegin(); sit != rGen2.InitStatesEnd(); ++sit) 
00579         pResGen->SetTransition(Gen1StatesMap[tit->X1], tit->Ev, Gen2StatesMap[*sit]);
00580 
00581   // set pResGen marked states corresponding to rGen2 marked states using Gen2StatesMap
00582   for(sit = rGen2.MarkedStatesBegin(); sit != rGen2.MarkedStatesEnd(); ++sit) {
00583     pResGen->SetMarkedState(Gen2StatesMap[*sit]);
00584   }
00585 
00586   // remove blocking states as they provide no useful meaning.
00587   pResGen->Trim();
00588   pResGen->Name("ConcatenateNonDet("+rGen1.Name()+","+rGen2.Name()+")");
00589     
00590   // if necessary, move pResGen to rResGen
00591   if(pResGen != &rResGen) {
00592     pResGen->Move(rResGen);
00593     delete pResGen;
00594   }
00595     
00596 }
00597 
00598 // LanguageConcatenate(rGen1, rGen2, rResGen)
00599 void LanguageConcatenate(const Generator& rGen1, const Generator& rGen2, 
00600        Generator& rResGen) {
00601 
00602   FD_DF("LanguageConcatenate("<< rGen1.Name() 
00603   << "," << rGen2.Name() << ")");
00604     
00605   // perform nondeterministic language concatenation
00606   LanguageConcatenateNonDet(rGen1, rGen2, rResGen);
00607     
00608   // make deterministic if necessary
00609   if(!(rResGen.IsDeterministic())){
00610     Deterministic(rResGen, rResGen);
00611   }
00612 
00613   // set name of result
00614   rResGen.Name("Concatenate("+rGen1.Name()+","+rGen2.Name()+")");
00615     
00616   return;    
00617 }
00618 
00619 // FullLanguage(rAlphabet, rResGen)
00620 void FullLanguage(const EventSet& rAlphabet, Generator& rResGen) {
00621   FD_DF("FullLanguage("<< rAlphabet.Name() 
00622   << "," << rResGen.Name() << ")");
00623   
00624   // prepare result
00625   rResGen.Clear();
00626   
00627   // helpers
00628   Idx state;
00629   EventSet::Iterator evit;
00630   
00631   // alphabet
00632   rResGen.InjectAlphabet(rAlphabet);
00633   
00634   // insert marked initial state
00635   if(rResGen.StateNamesEnabled()){
00636     state = rResGen.InsInitState("1");
00637   } else{
00638     state = rResGen.InsInitState();
00639   }
00640   rResGen.SetMarkedState(state);
00641   
00642   // create selfloop for each event
00643   for (evit = rAlphabet.Begin(); evit != rAlphabet.End(); ++evit) {
00644     rResGen.SetTransition(state, *evit, state);
00645   }
00646   
00647   // set name of result
00648   rResGen.Name("FullLanguage("+rAlphabet.Name()+")");
00649     
00650   return;
00651 }
00652 
00653 // AlphabetLanguage(rAlphabet, rResGen)
00654 void AlphabetLanguage(const EventSet& rAlphabet, Generator& rResGen) {
00655   FD_DF("AlphabetLanguage("<< rAlphabet.Name() 
00656   << "," << rResGen.Name() << ")");
00657   
00658   // prepare result
00659   rResGen.Clear();
00660       
00661   // set name of result
00662   rResGen.Name("AlphabetLanguage("+rAlphabet.Name()+")");
00663     
00664   // if alphabet is empty, leave generator empty
00665   if(rAlphabet.Empty()){
00666     FD_WARN("AlphabetLanguage: empty alphabet.");
00667     return;
00668   }
00669     
00670   // helpers
00671   Idx istate, mstate;
00672   EventSet::Iterator evit;
00673   
00674   // alphabet
00675   rResGen.InjectAlphabet(rAlphabet);
00676   
00677   // insert one initial state and one marked state
00678   if(rResGen.StateNamesEnabled()){
00679     istate = rResGen.InsInitState("1");
00680     mstate = rResGen.InsMarkedState("2");
00681   }
00682   else{
00683     istate = rResGen.InsInitState();
00684     mstate = rResGen.InsMarkedState();
00685   }
00686   
00687   // for each event from rAlphabet, inserted transition leading from init state to marked state
00688   for (evit = rAlphabet.Begin(); evit != rAlphabet.End(); ++evit) {
00689     rResGen.SetTransition(istate, *evit, mstate);
00690   }
00691     
00692   return;
00693 }
00694 
00695 // EmptyStringLanguage(rAlphabet, rResGen)
00696 void EmptyStringLanguage(const EventSet& rAlphabet, Generator& rResGen) {
00697   FD_DF("EmptyStringLanguage("<< rAlphabet.Name() 
00698   << "," << rResGen.Name() << ")");
00699   
00700   // prepare result
00701   rResGen.Clear();
00702   
00703   // helpers
00704   Idx state;
00705   
00706   // alphabet
00707   rResGen.InjectAlphabet(rAlphabet);
00708   
00709   // insert marked initial state
00710   if(rResGen.StateNamesEnabled()){
00711     state = rResGen.InsInitState("1");
00712   }
00713   else{
00714     state = rResGen.InsInitState();
00715   }
00716   rResGen.SetMarkedState(state);
00717   
00718   // set name of result
00719   rResGen.Name("EmptyStringLanguage("+rAlphabet.Name()+")");
00720     
00721   return;
00722 }
00723 
00724 // EmptyLanguage(rAlphabet, rResGen)
00725 void EmptyLanguage(const EventSet& rAlphabet, Generator& rResGen) {
00726   FD_DF("EmptyStringLanguage("<< rAlphabet.Name() 
00727   << "," << rResGen.Name() << ")");
00728   
00729   // prepare result
00730   rResGen.Clear();
00731   
00732   // set alphabet
00733   rResGen.InjectAlphabet(rAlphabet);
00734 
00735   // set name of result
00736   rResGen.Name("EmptyLanguage("+rAlphabet.Name()+")");
00737     
00738   return;
00739 }
00740 
00741 // EmptyLanguage(rGen)
00742 bool IsEmptyLanguage(const Generator& rGen) {
00743   // case a) check if set of marked or initial states is empty
00744   if(rGen.MarkedStatesSize()==0) return true;
00745   if(rGen.InitStatesSize()==0) return true;
00746   // case b) check if no marked state is accessible (reachable)
00747   return (rGen.AccessibleSet()*rGen.MarkedStates()).Empty();
00748 }
00749 
00750 // LanguageInclusion(rGen1, rGen2)
00751 bool LanguageInclusion(const Generator& rGen1, const Generator& rGen2) {
00752     
00753   FD_DF("LanguageInclusion("<< rGen1.Name() << "," << rGen2.Name() << ")"); 
00754     
00755   // check if there is no string in Lm1 that is not in Lm2, which means Lm1<=Lm2
00756   Generator NotrGen2=rGen2;
00757   NotrGen2.StateNamesEnabled(false);
00758   // note: complement w.r.t. union of alphabets to ensure that elementwise 
00759   // inclusion of Lm1 in Lm2 is tested
00760   LanguageComplement(NotrGen2 , rGen1.Alphabet()+rGen2.Alphabet());
00761   return EmptyLanguageIntersection(rGen1,NotrGen2);        
00762 }
00763 
00764 // LanguageEquality(rGen1, rGen2)
00765 bool LanguageEquality(const Generator& rGen1, const Generator& rGen2) {
00766     
00767   FD_DF("LanguageEquality("<< rGen1.Name() << "," << rGen2.Name() << ")");
00768 
00769   // Check for equality by testing mutual inclusion
00770   return LanguageInclusion(rGen1,rGen2) && LanguageInclusion(rGen2,rGen1);
00771 }
00772 
00773 // KleeneClosure(rGen)
00774 void KleeneClosure(Generator& rGen) {
00775    
00776   FD_DF("KleeneClosure("<< rGen.Name() << ")");
00777 
00778   // fix name 
00779   std::string name=CollapsString("KleeneClosure(" + rGen.Name() + ")");
00780 
00781   // The Kleene Closure of the empty set is the empty set
00782   if(IsEmptyLanguage(rGen)){
00783     rGen.Clear();
00784     rGen.Name(name);
00785     return;
00786   }
00787 
00788   // run nondet version    
00789   KleeneClosureNonDet(rGen);
00790   Deterministic(rGen, rGen);
00791 
00792   // set name
00793   rGen.Name(name);
00794 }
00795 
00796 // KleeneClosure(rGen, rResGen)
00797 void KleeneClosure(const Generator& rGen, Generator& rResGen) {
00798    
00799   FD_DF("KleeneClosure("<< rGen.Name() << ", ... )");
00800 
00801   // if arg and result match, call respective version
00802   if(&rGen==&rResGen) {
00803     KleeneClosure(rResGen);
00804     return;
00805   }
00806 
00807   // fix name 
00808   std::string name=CollapsString("KleeneClosure(" + rGen.Name() + ")");
00809 
00810   // The Kleene Closure of the empty set is the empty set
00811   if(IsEmptyLanguage(rGen)){
00812     rResGen.Clear();
00813     rResGen.Name(name);
00814     return;
00815   }
00816 
00817   // run nondet version with intermediate result
00818   Generator* pgen=rGen.Copy();   
00819   KleeneClosureNonDet(*pgen);
00820   Deterministic(*pgen, rResGen);
00821   delete pgen;
00822 
00823   // set name
00824   rResGen.Name(name);
00825 }
00826 
00827 // KleeneClosureNonDet(rGen)
00828 void KleeneClosureNonDet(Generator& rGen) {
00829     
00830   FD_DF("KleeneClosureNonDet("<< rGen.Name()  << ")");
00831     
00832   // set name 
00833   rGen.Name(CollapsString("KleeneClosureNonDet("+ rGen.Name() + ")"));
00834     
00835   // The Kleene Closure of the empty set is the empty set
00836   if(IsEmptyLanguage(rGen)) {
00837     rGen.Clear();
00838     return;
00839   }
00840     
00841   // helpers
00842   TransSet::Iterator tit;
00843   TransSet TransToInsert;
00844 
00845   // initial state bug (detected by Tomas Masopust, fix proposed by Klaus Schmidt)
00846   // 1. prepare the generator to have a unique initial state
00847   // 2. if the initial state fails to be marked, introduce a fake marked initial state.
00848   // 3. equip the fake markded initial state with the same transitions as the original initial state
00849   UniqueInit(rGen);
00850   Idx istate = *rGen.InitStatesBegin();
00851   Idx imstate = istate;
00852   if(!rGen.ExistsMarkedState(imstate)) {
00853     imstate=rGen.InsInitState();
00854     rGen.SetMarkedState(imstate);
00855     for(tit = rGen.TransRelBegin(istate); tit != rGen.TransRelEnd(istate); ++tit) { 
00856       TransToInsert.Insert(imstate, tit->Ev, tit->X2);
00857     }
00858   }
00859       
00860   // for all transitions leading from a state x1 to a marked state: insert a transition
00861   // with the same event that leads to the initial state(s). 
00862   for(tit = rGen.TransRelBegin(); tit != rGen.TransRelEnd(); ++tit) { 
00863     if(rGen.ExistsMarkedState(tit->X2)) {
00864       if(!(rGen.ExistsTransition(tit->X1, tit->Ev, imstate)) ){
00865   TransToInsert.Insert(tit->X1, tit->Ev, imstate);
00866       }
00867     }        
00868   }
00869   for (tit = TransToInsert.Begin(); tit != TransToInsert.End(); ++tit) {
00870     rGen.SetTransition(*tit);
00871   }
00872     
00873 }
00874 
00875 // PrefixClosure(rGen)
00876 void PrefixClosure(Generator& rGen) {
00877     
00878   FD_DF("PrefixClosure("<< rGen.Name() << ")");
00879 
00880   // fix name
00881   std::string name=CollapsString("PrefixClosure("+ rGen.Name() + ")");
00882     
00883   // remove all states that do net represent prefixes of marked strings
00884   rGen.Coaccessible();
00885     
00886   // mark all remaining states
00887   rGen.InjectMarkedStates(rGen.States());
00888    
00889   // set name 
00890   rGen.Name(name);
00891     
00892 }
00893 
00894 // IsPrefixClosed
00895 bool IsPrefixClosed(const Generator& rGen) {
00896   
00897   // figure relevant states
00898   StateSet relevant = rGen.AccessibleSet() * rGen.CoaccessibleSet();
00899 
00900   // test
00901   return relevant <= rGen.MarkedStates();
00902 
00903 }
00904 
00905 // IsNonblocking
00906 bool IsNonblocking(const Generator& rGen) {
00907   
00908   // test
00909   return rGen.AccessibleSet() <= rGen.CoaccessibleSet();
00910 
00911 }
00912 
00913 // IsNonblocking 
00914 bool IsNonblocking(const Generator& rGen1, const Generator& rGen2) {
00915   
00916   // build composition
00917   Generator parallel;
00918   parallel.StateNamesEnabled(false);
00919   Parallel(rGen1,rGen2,parallel);
00920 
00921   // test (parallel returns an accessible generator).
00922   return parallel.States() <= parallel.CoaccessibleSet();
00923 
00924 }
00925 
00926 
00927 
00928 // SelfLoop(rGen,rAlphabet)
00929 void SelfLoop(Generator& rGen,const EventSet& rAlphabet) {
00930     
00931   FD_DF("SelfLoop(" << rGen.Name() << "," << rAlphabet.Name() << ")");
00932 
00933   // fix name
00934   std::string name = CollapsString("SelfLoop(" + rGen.Name() + "," + rAlphabet.Name() + ")");
00935   // extend alphabet of rGen
00936   rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
00937     
00938   //helpers
00939   EventSet::Iterator evit,evbegin,evend;
00940   evbegin = rAlphabet.Begin();
00941   evend = rAlphabet.End();  
00942   StateSet::Iterator sit;
00943     
00944   // iterate over all states and insert selfloop for each event of rAlphabet
00945   for (sit = rGen.StatesBegin(); sit != rGen.StatesEnd(); ++sit) {
00946     for(evit = evbegin; evit != evend; ++evit){
00947       rGen.SetTransition(*sit, *evit, *sit);
00948     }
00949   }
00950     
00951   // set name
00952   rGen.Name(name);
00953 }
00954 
00955 // SelfLoopMarkedStates(rGen,rAlphabet)
00956 void SelfLoopMarkedStates(Generator& rGen,const EventSet& rAlphabet) {
00957     
00958   FD_DF("SelfLoopMarkedStates(" << rGen.Name() << "," << rAlphabet.Name() << ")");
00959 
00960   // fix name
00961   std::string name = CollapsString("SelfLoopMarkedStates(" + rGen.Name() 
00962      + "," + rAlphabet.Name() + ")");
00963 
00964   // extend alphabet of rGen
00965   rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
00966     
00967   //helpers
00968   EventSet::Iterator evit,evbegin,evend;
00969   evbegin = rAlphabet.Begin();
00970   evend = rAlphabet.End();  
00971   StateSet::Iterator sit;
00972     
00973   // iterate over all marked states and insert selfloop for each event of rAlphabet
00974   for (sit = rGen.MarkedStatesBegin(); sit != rGen.MarkedStatesEnd(); ++sit) {
00975     for(evit = evbegin; evit != evend; ++evit){
00976       rGen.SetTransition(*sit, *evit, *sit);
00977     }
00978   }
00979     
00980   // set name
00981   rGen.Name(name);
00982 }
00983 
00984 // SelfLoop(rGen,rAlphabet,rStates)
00985 void SelfLoop(Generator& rGen,const EventSet& rAlphabet,const StateSet& rStates) {
00986     
00987   FD_DF("SelfLoop(" << rGen.Name() << "," << rAlphabet.Name() << "," << rStates.Name() << ")");
00988 
00989   // fix name
00990   std::string name = CollapsString("SelfLoop(" + rGen.Name() 
00991      + "," + rAlphabet.Name() + "," + rStates.Name() + ")");
00992 
00993   // exception: rStates must be states of rGen
00994 #ifdef FAUDES_CHECKED
00995   if( !(rStates <= rGen.States()) ){
00996     std::stringstream errstr;
00997     errstr << "State set " << rStates.Name() << 
00998       " has to be included in state set of "<< rGen.Name() << ".";
00999     throw Exception("SelfLoop()", errstr.str(), 100);
01000   }
01001 #endif
01002     
01003   // extend alphabet of rGen
01004   rGen.InjectAlphabet(rGen.Alphabet()+rAlphabet);
01005     
01006   //helpers
01007   EventSet::Iterator evit,evbegin,evend;
01008   evbegin = rAlphabet.Begin();
01009   evend = rAlphabet.End();    
01010   StateSet::Iterator sit;
01011     
01012   // iterate over all marked states and insert selfloop for each event of rAlphabet
01013   for (sit = rStates.Begin(); sit != rStates.End(); ++sit) {
01014     for(evit = evbegin; evit != evend; ++evit){
01015       rGen.SetTransition(*sit, *evit, *sit);
01016     }
01017   }
01018     
01019   // set name
01020   rGen.Name(name);
01021 }
01022 
01023 
01024 } // namespace faudes
01025 
01026 #undef Product //see define above for comment

libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen