cfl_omega.cppGo 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 |