libFAUDES

Sections

Index

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

libFAUDES 2.22s --- 2013.10.07 --- c++ source docu by doxygen