|
libFAUDES
Sections
Index
|
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 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.16b --- 2010-9-8 --- c++ source docu by doxygen 1.6.3