cfl_omega.cpp

Go to the documentation of this file.
00001 /** @file cfl_omega.cpp
00002 
00003 Operations regarding omega languages.
00004 
00005 */
00006 
00007 /* FAU Discrete Event Systems Library (libfaudes)
00008 
00009 Copyright (C) 2010 Thomas Moor
00010 
00011 This library is free software; you can redistribute it and/or
00012 modify it under the terms of the GNU Lesser General Public
00013 License as published by the Free Software Foundation; either
00014 version 2.1 of the License, or (at your option) any later version.
00015 
00016 This library is distributed in the hope that it will be useful,
00017 but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019 Lesser General Public License for more details.
00020 
00021 You should have received a copy of the GNU Lesser General Public
00022 License along with this library; if not, write to the Free Software
00023 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00024 
00025   
00026 
00027 #include "cfl_omega.h"
00028 
00029 #include "cfl_parallel.h"
00030 #include "cfl_project.h" 
00031 #include "cfl_graphfncts.h" 
00032 
00033 
00034 namespace faudes {
00035 
00036 
00037 // helper class for omega compositions
00038 class OPState {
00039 public:
00040   // minimal interface
00041   OPState() {};
00042   OPState(const Idx& rq1, const Idx& rq2, const bool& rf) :
00043     q1(rq1), q2(rq2), m1required(rf), mresolved(false) {};
00044   std::string Str(void) { return ToStringInteger(q1)+"|"+
00045       ToStringInteger(q2)+"|"+ToStringInteger(m1required); };
00046   // order
00047   bool operator < (const OPState& other) const {
00048     if (q1 < other.q1) return(true);
00049     if (q1 > other.q1) return(false);
00050     if (q2 < other.q2) return(true);
00051     if (q2 > other.q2) return(false);
00052     if (!m1required && other.m1required)  return(true);
00053     if (m1required &&  !other.m1required) return(false);
00054     if (!mresolved &&  other.mresolved)  return(true);
00055     return(false);
00056   }
00057   // member variables
00058   Idx q1;
00059   Idx q2;
00060   bool m1required;
00061   bool mresolved;
00062 };
00063 
00064 
00065 
00066 // OmegaProduct for Generators, transparent for event attributes.
00067 void aOmegaProduct(
00068   const Generator& rGen1,
00069   const Generator& rGen2,
00070   Generator& rResGen) 
00071 {
00072 
00073   // inputs have to agree on attributes of shared events:
00074   bool careattr=rGen1.Alphabet().EqualAttributes(rGen2.Alphabet());
00075 
00076   // prepare result
00077   Generator* pResGen = &rResGen;
00078   if(&rResGen== &rGen1 || &rResGen== &rGen2) {
00079     pResGen= rResGen.New();
00080   }
00081 
00082   // make product composition of inputs
00083   OmegaProduct(rGen1,rGen2,*pResGen);
00084 
00085   // copy all attributes of input alphabets
00086   if(careattr) {
00087     pResGen->EventAttributes(rGen1.Alphabet());
00088     pResGen->EventAttributes(rGen2.Alphabet());
00089   }
00090 
00091   // copy result
00092   if(pResGen != &rResGen) {
00093     pResGen->Move(rResGen);
00094     delete pResGen;
00095   }
00096 
00097 }
00098 
00099 
00100 
00101 // OmegaProduct(rGen1, rGen2, res)
00102 void OmegaProduct(
00103   const Generator& rGen1, const Generator& rGen2, 
00104   Generator& rResGen)
00105 {
00106   FD_DF("OmegaProduct(" << &rGen1 << "," << &rGen2 << ")");
00107 
00108   // prepare result
00109   Generator* pResGen = &rResGen;
00110   if(&rResGen== &rGen1 || &rResGen== &rGen2) {
00111     pResGen= rResGen.New();
00112   }
00113   pResGen->Clear();
00114   pResGen->Name(CollapsString(rGen1.Name()+".x."+rGen2.Name()));
00115 
00116   // create res alphabet
00117   pResGen->InsEvents(rGen1.Alphabet());
00118   pResGen->InsEvents(rGen2.Alphabet());
00119 
00120   // reverse composition map
00121   std::map< OPState, Idx> reverseCompositionMap;
00122   // todo stack
00123   std::stack< OPState > todo;
00124   // current pair, new pair
00125   OPState currentstates, newstates;
00126   // state
00127   Idx tmpstate;  
00128   StateSet::Iterator lit1, lit2;
00129   TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
00130   std::map< OPState, Idx>::iterator rcit;
00131   // push all combinations of initial states on todo stack
00132   FD_DF("OmegaProduct: adding all combinations of initial states to todo:");
00133   for (lit1 = rGen1.InitStatesBegin(); lit1 != rGen1.InitStatesEnd(); ++lit1) {
00134     for (lit2 = rGen2.InitStatesBegin(); lit2 != rGen2.InitStatesEnd(); ++lit2) {
00135       currentstates = OPState(*lit1, *lit2, true);
00136       todo.push(currentstates);
00137       reverseCompositionMap[currentstates] = pResGen->InsInitState();
00138       FD_DF("OmegaProduct:   " << currentstates.Str() << " -> " << reverseCompositionMap[currentstates]);
00139     }
00140   }
00141 
00142   // start algorithm
00143   FD_DF("OmegaProduct: processing reachable states:");
00144   while (! todo.empty()) {
00145     // allow for user interrupt
00146     LoopCallback();
00147     // get next reachable state from todo stack
00148     currentstates = todo.top();
00149     todo.pop();
00150     FD_DF("OmegaProduct: processing (" << currentstates.Str() << " -> " << reverseCompositionMap[currentstates]);
00151     // iterate over all rGen1 transitions  
00152     tit1 = rGen1.TransRelBegin(currentstates.q1);
00153     tit1_end = rGen1.TransRelEnd(currentstates.q1);
00154     for(; tit1 != tit1_end; ++tit1) {
00155       // find transition in rGen2
00156       tit2 = rGen2.TransRelBegin(currentstates.q2, tit1->Ev);
00157       tit2_end = rGen2.TransRelEnd(currentstates.q2, tit1->Ev);
00158       for (; tit2 != tit2_end; ++tit2) {
00159         newstates = OPState(tit1->X2, tit2->X2,currentstates.m1required);
00160         // figure whether marking was resolved
00161         if(currentstates.m1required) {
00162       if(rGen1.ExistsMarkedState(currentstates.q1))
00163       newstates.m1required=false;
00164         } else {
00165       if(rGen2.ExistsMarkedState(currentstates.q2))
00166       newstates.m1required=true;
00167         }
00168         // add to todo list if composition state is new
00169         rcit = reverseCompositionMap.find(newstates);
00170         if(rcit == reverseCompositionMap.end()) {
00171           todo.push(newstates);
00172           tmpstate = pResGen->InsState();
00173           if(!newstates.m1required)
00174       if(rGen2.ExistsMarkedState(newstates.q2))
00175               pResGen->SetMarkedState(tmpstate);
00176           reverseCompositionMap[newstates] = tmpstate;
00177           FD_DF("OmegaProduct:   todo push: (" << newstates.Str() << ") -> " << reverseCompositionMap[newstates]);
00178         }
00179         else {
00180           tmpstate = rcit->second;
00181         }
00182         pResGen->SetTransition(reverseCompositionMap[currentstates], 
00183             tit1->Ev, tmpstate);
00184         FD_DF("OmegaProduct:  add transition to new generator: " << 
00185         pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit1->Ev, tmpstate)));
00186       }
00187     }
00188   }
00189 
00190   FD_DF("OmegaProduct: marked states: "  << pResGen->MarkedStatesToString());
00191 
00192 
00193   // fix statenames ...
00194   if(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled()) 
00195   for(rcit=reverseCompositionMap.begin(); rcit!=reverseCompositionMap.end(); rcit++) {
00196     Idx x1=rcit->first.q1;
00197     Idx x2=rcit->first.q2;
00198     bool m1requ=rcit->first.m1required;
00199     Idx x12=rcit->second;
00200     if(!pResGen->ExistsState(x12)) continue;
00201     std::string name1= rGen1.StateName(x1);
00202     if(name1=="") name1=ToStringInteger(x1);
00203     std::string name2= rGen2.StateName(x2);
00204     if(name2=="") name1=ToStringInteger(x2);
00205     std::string name12 = name1 + "|" + name2;
00206     if(m1requ) name12 += "|r1m";
00207     else name12 +="|r2m";
00208     name12=pResGen->UniqueStateName(name12);
00209     pResGen->StateName(x12,name12);
00210   }
00211 
00212   // .. or clear them (?)
00213   if(!(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled())) 
00214     pResGen->StateNamesEnabled(false);
00215 
00216   // copy result
00217   if(pResGen != &rResGen) {
00218     pResGen->Move(rResGen);
00219     delete pResGen;
00220   }
00221 }
00222 
00223 
00224 
00225 // OmegaParallel for Generators, transparent for event attributes.
00226 void aOmegaParallel(
00227   const Generator& rGen1,
00228   const Generator& rGen2,
00229   Generator& rResGen) 
00230 {
00231 
00232   // inputs have to agree on attributes of shared events:
00233   bool careattr=rGen1.Alphabet().EqualAttributes(rGen2.Alphabet());
00234 
00235   // prepare result
00236   Generator* pResGen = &rResGen;
00237   if(&rResGen== &rGen1 || &rResGen== &rGen2) {
00238     pResGen= rResGen.New();
00239   }
00240 
00241   // make product composition of inputs
00242   OmegaParallel(rGen1,rGen2,*pResGen);
00243 
00244   // copy all attributes of input alphabets
00245   if(careattr) {
00246     pResGen->EventAttributes(rGen1.Alphabet());
00247     pResGen->EventAttributes(rGen2.Alphabet());
00248   }
00249 
00250   // copy result
00251   if(pResGen != &rResGen) {
00252     pResGen->Move(rResGen);
00253     delete pResGen;
00254   }
00255 
00256 }
00257 
00258 
00259 
00260 // OmegaParallel(rGen1, rGen2, res)
00261 void OmegaParallel(
00262   const Generator& rGen1, const Generator& rGen2, 
00263   Generator& rResGen)
00264 {
00265   FD_DF("OmegaParallel(" << &rGen1 << "," << &rGen2 << ")");
00266   // prepare result
00267   Generator* pResGen = &rResGen;
00268   if(&rResGen== &rGen1 || &rResGen== &rGen2) {
00269     pResGen= rResGen.New();
00270   }
00271   pResGen->Clear();
00272   pResGen->Name(CollapsString(rGen1.Name()+"|||"+rGen2.Name()));
00273   // create res alphabet
00274   pResGen->InsEvents(rGen1.Alphabet());
00275   pResGen->InsEvents(rGen2.Alphabet());
00276   // shared events
00277   EventSet sharedalphabet = rGen1.Alphabet() * rGen2.Alphabet();
00278   FD_DF("OmegaParallel: g1 events: " << rGen1.Alphabet().ToString());
00279   FD_DF("OmegaParallel: g2 events: " << rGen2.Alphabet().ToString());
00280   FD_DF("OmegaParallel: shared events: " << sharedalphabet.ToString());
00281 
00282   // reverse composition map
00283   std::map< OPState, Idx> reverseCompositionMap;
00284   // todo stack
00285   std::stack< OPState > todo;
00286   // current pair, new pair
00287   OPState currentstates, newstates;
00288   // state
00289   Idx tmpstate;  
00290   StateSet::Iterator lit1, lit2;
00291   TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
00292   std::map< OPState, Idx>::iterator rcit;
00293   // push all combinations of initial states on todo stack
00294   FD_DF("OmegaParallel: adding all combinations of initial states to todo:");
00295   for (lit1 = rGen1.InitStatesBegin(); lit1 != rGen1.InitStatesEnd(); ++lit1) {
00296     for (lit2 = rGen2.InitStatesBegin(); lit2 != rGen2.InitStatesEnd(); ++lit2) {
00297       currentstates = OPState(*lit1, *lit2, true);
00298       tmpstate=pResGen->InsInitState();
00299       if(rGen2.ExistsMarkedState(*lit2)) { 
00300         currentstates.mresolved=true;
00301         pResGen->SetMarkedState(tmpstate);
00302       }
00303       todo.push(currentstates);
00304       reverseCompositionMap[currentstates] = tmpstate;
00305       FD_DF("OmegaParallel:   " << currentstates.Str() << " -> " << tmpstate);
00306     }
00307   }
00308 
00309   // start algorithm
00310   FD_DF("OmegaParallel: processing reachable states:");
00311   while (! todo.empty()) {
00312     // allow for user interrupt
00313     LoopCallback();
00314     // get next reachable state from todo stack
00315     currentstates = todo.top();
00316     todo.pop();
00317     FD_DF("OmegaParallel: processing (" << currentstates.Str() << " -> " 
00318         << reverseCompositionMap[currentstates]);
00319     // iterate over all rGen1 transitions 
00320     // (includes execution of shared events)
00321     tit1 = rGen1.TransRelBegin(currentstates.q1);
00322     tit1_end = rGen1.TransRelEnd(currentstates.q1);
00323     for(; tit1 != tit1_end; ++tit1) {
00324       // if event not shared
00325       if(! sharedalphabet.Exists(tit1->Ev)) {
00326         FD_DF("OmegaParallel:   exists only in rGen1");
00327         newstates = OPState(tit1->X2, currentstates.q2, currentstates.m1required);
00328         // figure whether marking is resolved 
00329         // (tmoor 201208: only m1required can be resolved, since only G1 proceeds)
00330         if(currentstates.m1required) {
00331           if(rGen1.ExistsMarkedState(newstates.q1)) {
00332             newstates.m1required=false;
00333       //newstates.mresolved=true; // optional
00334     }
00335   }
00336         // add to todo list if composition state is new
00337         rcit = reverseCompositionMap.find(newstates);
00338         if (rcit == reverseCompositionMap.end()) {
00339           todo.push(newstates);
00340           tmpstate = pResGen->InsState();
00341           if(newstates.mresolved) pResGen->SetMarkedState(tmpstate);                   
00342           reverseCompositionMap[newstates] = tmpstate;
00343           FD_DF("OmegaParallel:   todo push: " << newstates.Str() << "|" 
00344               << reverseCompositionMap[newstates]);
00345         }
00346         else {
00347           tmpstate = rcit->second;
00348         }
00349   // insert transition to result 
00350         pResGen->SetTransition(reverseCompositionMap[currentstates], tit1->Ev, 
00351             tmpstate);
00352         FD_DF("OmegaParallel:  add transition to new generator: " << 
00353         pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit1->Ev, tmpstate)));
00354       }
00355       // if shared event
00356       else {
00357         FD_DF("OmegaParallel:   common event");
00358         // find shared transitions
00359         tit2 = rGen2.TransRelBegin(currentstates.q2, tit1->Ev);
00360         tit2_end = rGen2.TransRelEnd(currentstates.q2, tit1->Ev);
00361         for (; tit2 != tit2_end; ++tit2) {
00362           newstates = OPState(tit1->X2,tit2->X2,currentstates.m1required);
00363           // figure whether marking was resolved
00364           // (tmoor 201208: both markings can be resolved, since both G1 and G2 proceed)
00365           if(currentstates.m1required) {
00366         if(rGen1.ExistsMarkedState(newstates.q1)) {
00367         newstates.m1required=false;
00368         //newstates.mresolved=true; // optional
00369       }
00370           } else {
00371         if(rGen2.ExistsMarkedState(newstates.q2)) {
00372         newstates.m1required=true;
00373               newstates.mresolved=true;
00374       }
00375           }
00376           // add to todo list if composition state is new
00377           rcit = reverseCompositionMap.find(newstates);
00378           if (rcit == reverseCompositionMap.end()) {
00379             todo.push(newstates);
00380             tmpstate = pResGen->InsState();
00381             if(newstates.mresolved) pResGen->SetMarkedState(tmpstate);                   
00382             reverseCompositionMap[newstates] = tmpstate;
00383             FD_DF("OmegaParallel:   todo push: (" << newstates.Str() << ") -> " 
00384                 << reverseCompositionMap[newstates]);
00385           }
00386           else {
00387             tmpstate = rcit->second;
00388           }
00389           pResGen->SetTransition(reverseCompositionMap[currentstates], 
00390               tit1->Ev, tmpstate);
00391           FD_DF("OmegaParallel:  add transition to new generator: " << 
00392     pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit1->Ev, tmpstate)));
00393         }
00394       }
00395     }
00396     // iterate over all remaining rGen2 transitions 
00397     // (without execution of shared events)
00398     tit2 = rGen2.TransRelBegin(currentstates.q2);
00399     tit2_end = rGen2.TransRelEnd(currentstates.q2);
00400     for (; tit2 != tit2_end; ++tit2) {
00401       if (! sharedalphabet.Exists(tit2->Ev)) {
00402         FD_DF("OmegaParallel:   exists only in rGen2: " << sharedalphabet.Str(tit2->Ev));
00403         newstates = OPState(currentstates.q1, tit2->X2, currentstates.m1required);
00404         // figure whether marking was resolved
00405         // (tmoor 201208: only m2required=!m1required can be resolved, since only G2 proceeds)
00406         if(!currentstates.m1required) {
00407           if(rGen2.ExistsMarkedState(newstates.q2)) {
00408             newstates.m1required=true;
00409             newstates.mresolved=true;
00410     }
00411         }
00412         FD_DF("OmegaParallel: set trans: " << currentstates.Str() << " " << newstates.Str()); 
00413         // add to todo list if composition state is new
00414         rcit = reverseCompositionMap.find(newstates);
00415         if (rcit == reverseCompositionMap.end()) {
00416           todo.push(newstates);
00417           tmpstate = pResGen->InsState();
00418           if(newstates.mresolved) pResGen->SetMarkedState(tmpstate);                   
00419           reverseCompositionMap[newstates] = tmpstate;
00420           FD_DF("OmegaParallel:   todo push: " << newstates.Str() << " -> " 
00421               << reverseCompositionMap[newstates]);
00422         }
00423         else {
00424           tmpstate = rcit->second;
00425         }
00426         pResGen->SetTransition(reverseCompositionMap[currentstates], 
00427             tit2->Ev, tmpstate);
00428         FD_DF("OmegaParallel:  add transition to new generator: " << 
00429         pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit2->Ev, tmpstate)));
00430       }
00431     }
00432   }
00433 
00434   FD_DF("OmegaParallel: marked states: " << pResGen->MarkedStatesToString());
00435 
00436   // fix statenames ...
00437   if(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled()) 
00438   for(rcit=reverseCompositionMap.begin(); rcit!=reverseCompositionMap.end(); rcit++) {
00439     Idx x1=rcit->first.q1;
00440     Idx x2=rcit->first.q2;
00441     bool m1requ=rcit->first.m1required;
00442     bool mres=rcit->first.mresolved;
00443     Idx x12=rcit->second;
00444     if(!pResGen->ExistsState(x12)) continue;
00445     std::string name1= rGen1.StateName(x1);
00446     if(name1=="") name1=ToStringInteger(x1);
00447     std::string name2= rGen2.StateName(x2);
00448     if(name2=="") name1=ToStringInteger(x2);
00449     std::string name12 = name1 + "|" + name2 ;
00450     if(m1requ) name12 += "|r1m";
00451     else name12 +="|r2m";
00452     if(mres) name12 += "*";
00453     name12=pResGen->UniqueStateName(name12);
00454     pResGen->StateName(x12,name12);
00455   }
00456 
00457   // .. or clear them (?)
00458   if(!(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled())) 
00459     pResGen->StateNamesEnabled(false);
00460 
00461   // copy result
00462   if(pResGen != &rResGen) {
00463     pResGen->Move(rResGen);
00464     delete pResGen;
00465   }
00466 }
00467 
00468 
00469 // OmegaClosure(rGen)
00470 void OmegaClosure(Generator& rGen) {
00471   FD_DF("OmegaClosure("<< rGen.Name() << ")");
00472 
00473   // fix name
00474   std::string name=CollapsString("OmegaClosure("+ rGen.Name() + ")");
00475     
00476   // remove all states that do net represent prefixes of marked strings
00477   rGen.OmegaTrim();
00478     
00479   // mark all remaining states
00480   rGen.InjectMarkedStates(rGen.States());
00481    
00482   // set name 
00483   rGen.Name(name);
00484 }
00485 
00486 
00487 // IsOmegaClosed
00488 bool IsOmegaClosed(const Generator& rGen) {
00489   
00490   FD_DF("IsOmegaClosed("<< rGen.Name() << ")");
00491 
00492   // figure irrelevant states: not coaccessible / accessible
00493   StateSet irrelevant = rGen.States();
00494   irrelevant.EraseSet(rGen.AccessibleSet()* rGen.CoaccessibleSet());
00495   
00496   // figure irrelevant states: terminal
00497   irrelevant.InsertSet(rGen.TerminalStates());
00498 
00499   // iterative search on indirect terminal states ...
00500   bool done;
00501   do {
00502     // ... over all states
00503     StateSet::Iterator sit = rGen.States().Begin();
00504     StateSet::Iterator sit_end = rGen.States().End();
00505     done=true;
00506     for(; sit!=sit_end; ++sit) {
00507       if(irrelevant.Exists(*sit)) continue;
00508       TransSet::Iterator tit = rGen.TransRelBegin(*sit);
00509       TransSet::Iterator tit_end = rGen.TransRelEnd(*sit);
00510       for (; tit != tit_end; ++tit) {
00511         if(!irrelevant.Exists(tit->X2)) break;
00512       }
00513       if(tit==tit_end) {
00514         irrelevant.Insert(*sit);
00515   done=false;
00516       }
00517     }
00518   } while(!done);
00519 
00520   // marked states are irrelevant here
00521   irrelevant.InsertSet(rGen.MarkedStates());
00522 
00523   // report
00524 #ifdef FAUDES_DEBUG_FUNCTION
00525   FD_DF("IsOmegaClosed(..): irrelevant states "<< irrelevant.ToString());
00526 #endif
00527 
00528   // locate unmarked SCCs
00529   // find all relevant SCCs
00530   SccFilter umfilter(SccFilter::FmIgnoreTrivial | SccFilter::FmStatesAvoid, irrelevant);
00531   std::list<StateSet> umsccs;
00532   StateSet umroots;
00533   ComputeScc(rGen,umfilter,umsccs,umroots); 
00534 
00535   // report
00536 #ifdef FAUDES_DEBUG_FUNCTION
00537   std::list<StateSet>::iterator ssit=umsccs.begin();
00538   for(;ssit!=umsccs.end(); ++ssit) {
00539     FD_DF("IsOmegaClosed(): GPlant-marked scc without GCand-mark: " << ssit->ToString());
00540   }  
00541 #endif
00542 
00543   // done
00544   return umsccs.empty();
00545 
00546 }
00547 
00548 
00549 
00550 } // namespace faudes
00551 

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