libFAUDES

Sections

Index

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     return(false);
00054   }
00055   // member variables
00056   Idx q1;
00057   Idx q2;
00058   bool m1required;
00059   bool mresolved;
00060 };
00061 
00062 
00063 
00064 // OmegaParallel for vGenerators, transparent for event attributes.
00065 void aOmegaParallel(
00066   const vGenerator& rGen1,
00067   const vGenerator& rGen2,
00068   vGenerator& rResGen) 
00069 {
00070 
00071   // inputs have to agree on attributes of shared events:
00072   bool careattr=rGen1.Alphabet().EqualAttributes(rGen2.Alphabet());
00073 
00074   // prepare result
00075   vGenerator* pResGen = &rResGen;
00076   if(&rResGen== &rGen1 || &rResGen== &rGen2) {
00077     pResGen= rResGen.New();
00078   }
00079 
00080   // make product composition of inputs
00081   OmegaParallel(rGen1,rGen2,*pResGen);
00082 
00083   // copy all attributes of input alphabets
00084   if(careattr) {
00085     pResGen->EventAttributes(rGen1.Alphabet());
00086     pResGen->EventAttributes(rGen2.Alphabet());
00087   }
00088 
00089   // copy result
00090   if(pResGen != &rResGen) {
00091     pResGen->Move(rResGen);
00092     delete pResGen;
00093   }
00094 
00095 }
00096 
00097 
00098 
00099 // OmegaParallel(rGen1, rGen2, res)
00100 void OmegaParallel(
00101   const vGenerator& rGen1, const vGenerator& rGen2, 
00102   vGenerator& rResGen)
00103 {
00104   FD_DF("OmegaParallel(" << &rGen1 << "," << &rGen2 << ")");
00105   // prepare result
00106   vGenerator* pResGen = &rResGen;
00107   if(&rResGen== &rGen1 || &rResGen== &rGen2) {
00108     pResGen= rResGen.New();
00109   }
00110   pResGen->Clear();
00111   pResGen->Name(CollapsString(rGen1.Name()+"|||"+rGen2.Name()));
00112   // rGen1.events() \ rGen2.events()
00113   EventSet sharedalphabet = rGen1.Alphabet() * rGen2.Alphabet();
00114   FD_DF("OmegaParallel: shared events: " << sharedalphabet.ToString());
00115 
00116   // create res alphabet
00117   EventSet::Iterator eit;
00118   for (eit = rGen1.AlphabetBegin(); eit != rGen1.AlphabetEnd(); ++eit) {
00119     pResGen->InsEvent(*eit);
00120   }
00121   for (eit = rGen2.AlphabetBegin(); eit != rGen2.AlphabetEnd(); ++eit) {
00122     pResGen->InsEvent(*eit);
00123   }
00124   FD_DF("OmegaParallel: inserted indices in rResGen.alphabet( "
00125       << pResGen->AlphabetToString() << ")");
00126 
00127   // reverse composition map
00128   std::map< OPState, Idx> reverseCompositionMap;
00129   // todo stack
00130   std::stack< OPState > todo;
00131   // current pair, new pair
00132   OPState currentstates, newstates;
00133   // state
00134   Idx tmpstate;  
00135   StateSet::Iterator lit1, lit2;
00136   TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
00137   std::map< OPState, Idx>::iterator rcit;
00138   // push all combinations of initial states on todo stack
00139   FD_DF("OmegaParallel: adding all combinations of initial states to todo:");
00140   for (lit1 = rGen1.InitStatesBegin(); lit1 != rGen1.InitStatesEnd(); ++lit1) {
00141     for (lit2 = rGen2.InitStatesBegin(); lit2 != rGen2.InitStatesEnd(); ++lit2) {
00142       currentstates = OPState(*lit1, *lit2, true);
00143       todo.push(currentstates);
00144       reverseCompositionMap[currentstates] = pResGen->InsInitState();
00145       FD_DF("OmegaParallel:   " << currentstates.Str() << " -> " 
00146           << reverseCompositionMap[currentstates]);
00147     }
00148   }
00149 
00150   // start algorithm
00151   FD_DF("OmegaParallel: processing reachable states:");
00152   while (! todo.empty()) {
00153     // allow for user interrupt
00154     LoopCallback();
00155     // get next reachable state from todo stack
00156     currentstates = todo.top();
00157     todo.pop();
00158     FD_DF("OmegaParallel: processing (" << currentstates.Str() << " -> " 
00159         << reverseCompositionMap[currentstates]);
00160     // iterate over all rGen1 transitions 
00161     // (includes execution of shared events)
00162     tit1 = rGen1.TransRelBegin(currentstates.q1);
00163     tit1_end = rGen1.TransRelEnd(currentstates.q1);
00164     for (; tit1 != tit1_end; ++tit1) {
00165       // if event not shared
00166       if (! sharedalphabet.Exists(tit1->Ev)) {
00167         FD_DF("OmegaParallel:   exists only in rGen1");
00168         newstates = OPState(tit1->X2, currentstates.q2, currentstates.m1required);
00169         // figure whether marking was resolved
00170         if(currentstates.m1required) {
00171           if(rGen1.ExistsMarkedState(currentstates.q1))
00172             newstates.m1required=false;
00173         } else {
00174           if(rGen2.ExistsMarkedState(currentstates.q2))
00175             newstates.m1required=true;
00176         }
00177         // add to todo list if composition state is new
00178         rcit = reverseCompositionMap.find(newstates);
00179         if (rcit == reverseCompositionMap.end()) {
00180           todo.push(newstates);
00181           tmpstate = pResGen->InsState();
00182           if(!newstates.m1required)
00183     if(rGen2.ExistsMarkedState(newstates.q2))
00184             pResGen->SetMarkedState(tmpstate);                   
00185           reverseCompositionMap[newstates] = tmpstate;
00186           FD_DF("OmegaParallel:   todo push: " << newstates.Str() << "|" 
00187               << reverseCompositionMap[newstates]);
00188         }
00189         else {
00190           tmpstate = rcit->second;
00191         }
00192   // insert transition to result 
00193         pResGen->SetTransition(reverseCompositionMap[currentstates], tit1->Ev, 
00194             tmpstate);
00195         FD_DF("OmegaParallel:  add transition to new generator: " << 
00196         pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit1->Ev, tmpstate)));
00197       }
00198       // if shared event
00199       else {
00200         FD_DF("OmegaParallel:   common event");
00201         // find shared transitions
00202         tit2 = rGen2.TransRelBegin(currentstates.q2, tit1->Ev);
00203         tit2_end = rGen2.TransRelEnd(currentstates.q2, tit1->Ev);
00204         for (; tit2 != tit2_end; ++tit2) {
00205           newstates = OPState(tit1->X2, tit2->X2,currentstates.m1required);
00206           // figure whether marking was resolved
00207           if(currentstates.m1required) {
00208         if(rGen1.ExistsMarkedState(currentstates.q1))
00209         newstates.m1required=false;
00210           } else {
00211         if(rGen2.ExistsMarkedState(currentstates.q2))
00212         newstates.m1required=true;
00213           }
00214           // add to todo list if composition state is new
00215           rcit = reverseCompositionMap.find(newstates);
00216           if (rcit == reverseCompositionMap.end()) {
00217             todo.push(newstates);
00218             tmpstate = pResGen->InsState();
00219             if(!newstates.m1required)
00220         if(rGen2.ExistsMarkedState(newstates.q2))
00221               pResGen->SetMarkedState(tmpstate);                   
00222             reverseCompositionMap[newstates] = tmpstate;
00223             FD_DF("OmegaParallel:   todo push: (" << newstates.Str() << ") -> " 
00224                 << reverseCompositionMap[newstates]);
00225           }
00226           else {
00227             tmpstate = rcit->second;
00228           }
00229           pResGen->SetTransition(reverseCompositionMap[currentstates], 
00230               tit1->Ev, tmpstate);
00231           FD_DF("OmegaParallel:  add transition to new generator: " << 
00232     pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit1->Ev, tmpstate)));
00233         }
00234       }
00235     }
00236     // iterate over all remaining rGen2 transitions 
00237     // (without execution of shared events)
00238     tit2 = rGen2.TransRelBegin(currentstates.q2);
00239     tit2_end = rGen2.TransRelEnd(currentstates.q2);
00240     for (; tit2 != tit2_end; ++tit2) {
00241       if (! sharedalphabet.Exists(tit2->Ev)) {
00242         FD_DF("OmegaParallel:   exists only in rGen2");
00243         newstates = OPState(currentstates.q1, tit2->X2, currentstates.m1required);
00244         // figure whether marking was resolved
00245         if(currentstates.m1required) {
00246           if(rGen1.ExistsMarkedState(currentstates.q1))
00247             newstates.m1required=false;
00248         } else {
00249           if(rGen2.ExistsMarkedState(currentstates.q2))
00250             newstates.m1required=true;
00251         }
00252         // add to todo list if composition state is new
00253         rcit = reverseCompositionMap.find(newstates);
00254         if (rcit == reverseCompositionMap.end()) {
00255           todo.push(newstates);
00256           tmpstate = pResGen->InsState();
00257           if(!newstates.m1required)
00258     if(rGen2.ExistsMarkedState(newstates.q2))
00259             pResGen->SetMarkedState(tmpstate);                   
00260           reverseCompositionMap[newstates] = tmpstate;
00261           FD_DF("OmegaParallel:   todo push: " << newstates.Str() << " -> " 
00262               << reverseCompositionMap[newstates]);
00263         }
00264         else {
00265           tmpstate = rcit->second;
00266         }
00267         pResGen->SetTransition(reverseCompositionMap[currentstates], 
00268             tit2->Ev, tmpstate);
00269         FD_DF("OmegaParallel:  add transition to new generator: " << 
00270         pResGen->TStr(Transition(reverseCompositionMap[currentstates], tit2->Ev, tmpstate)));
00271       }
00272     }
00273   }
00274 
00275   FD_DF("OmegaParallel: marked states: " 
00276       << pResGen->MarkedStatesToString());
00277 
00278 
00279   // fix statenames ...
00280   if(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled()) 
00281   for(rcit=reverseCompositionMap.begin(); rcit!=reverseCompositionMap.end(); rcit++) {
00282     Idx x1=rcit->first.q1;
00283     Idx x2=rcit->first.q2;
00284     bool m1requ=rcit->first.m1required;
00285     Idx x12=rcit->second;
00286     if(!pResGen->ExistsState(x12)) continue;
00287     std::string name1= rGen1.StateName(x1);
00288     if(name1=="") name1=ToStringInteger(x1);
00289     std::string name2= rGen2.StateName(x2);
00290     if(name2=="") name1=ToStringInteger(x2);
00291     std::string name12;
00292     if(m1requ) name12= name1 + "|" + name2 + "|r1m";
00293     else name12= name1 + "|" + name2 + "|r2m";
00294     name12=pResGen->UniqueStateName(name12);
00295     pResGen->StateName(x12,name12);
00296   }
00297 
00298   // .. or clear them (?)
00299   if(!(rGen1.StateNamesEnabled() && rGen2.StateNamesEnabled() && rResGen.StateNamesEnabled())) 
00300     pResGen->ClearStateNames();
00301 
00302   // copy result
00303   if(pResGen != &rResGen) {
00304     pResGen->Move(rResGen);
00305     delete pResGen;
00306   }
00307 }
00308 
00309 
00310 // OmegaClosure(rGen)
00311 void OmegaClosure(vGenerator& rGen) {
00312     
00313   FD_DF("OmegaClosure("<< rGen.Name() << ")");
00314 
00315   // fix name
00316   std::string name=CollapsString("OmegaClosure("+ rGen.Name() + ")");
00317     
00318   // remove all states that do net represent prefixes of marked strings
00319   rGen.OmegaTrim();
00320     
00321   // mark all remaining states
00322   rGen.InjectMarkedStates(rGen.States());
00323    
00324   // set name 
00325   rGen.Name(name);
00326     
00327 }
00328 
00329 // IsOmegaClosed
00330 bool IsOmegaClosed(const vGenerator& rGen) {
00331   
00332   FD_DF("IsOmegaClosed("<< rGen.Name() << ")");
00333 
00334   // figure irrelevant states: not coaccessible / accessible
00335   StateSet irrelevant = rGen.States();
00336   irrelevant.EraseSet(rGen.AccessibleSet()* rGen.CoaccessibleSet());
00337   
00338   // figure irrelevant states: terminal
00339   irrelevant.InsertSet(rGen.TerminalStates());
00340 
00341   // iterative search on indirect terminal states ...
00342   bool done;
00343   do {
00344     // ... over all states
00345     StateSet::Iterator sit = rGen.States().Begin();
00346     StateSet::Iterator sit_end = rGen.States().End();
00347     done=true;
00348     for(; sit!=sit_end; ++sit) {
00349       if(irrelevant.Exists(*sit)) continue;
00350       TransSet::Iterator tit = rGen.TransRelBegin(*sit);
00351       TransSet::Iterator tit_end = rGen.TransRelEnd(*sit);
00352       for (; tit != tit_end; ++tit) {
00353         if(!irrelevant.Exists(tit->X2)) break;
00354       }
00355       if(tit==tit_end) {
00356         irrelevant.Insert(*sit);
00357   done=false;
00358       }
00359     }
00360   } while(!done);
00361 
00362   // marked states are irrelevant here
00363   irrelevant.InsertSet(rGen.MarkedStates());
00364 
00365   // report
00366 #ifdef FAUDES_DEBUG_FUNCTION
00367   FD_DF("IsOmegaClosed(..): irrelevant states "<< irrelevant.ToString());
00368 #endif
00369 
00370   // locate unmarked SCCs
00371   // find all relevant SCCs
00372   SccFilter umfilter(SccFilter::IgnoreTrivial | SccFilter::StatesAvoid, irrelevant);
00373   std::list<StateSet> umsccs;
00374   StateSet umroots;
00375   ComputeScc(rGen,umfilter,umsccs,umroots); 
00376 
00377   // report
00378 #ifdef FAUDES_DEBUG_FUNCTION
00379   std::list<StateSet>::iterator ssit=umsccs.begin();
00380   for(;ssit!=umsccs.end(); ++ssit) {
00381     FD_DF("IsOmegaClosed(): GPlant-marked scc without GCand-mark: " << ssit->ToString());
00382   }  
00383 #endif
00384 
00385   // done
00386   return umsccs.empty();
00387 
00388 }
00389 
00390 
00391 
00392 } // namespace faudes
00393 

libFAUDES 2.18b --- 2010-12-17 --- c++ source docu by doxygen 1.6.3