syn_wsupcon.cppGo to the documentation of this file.00001 /** @file syn_wsupcon.cpp Supremal controllable sublanguage for infinite time behaviours */ 00002 00003 /* FAU Discrete Event Systems Library (libfaudes) 00004 00005 Copyright (C) 2010 Thomas Moor 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public 00009 License as published by the Free Software Foundation; either 00010 version 2.1 of the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License along with this library; if not, write to the Free Software 00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ 00020 00021 00022 //#define FAUDES_DEBUG_FUNCTION 00023 00024 #include "syn_wsupcon.h" 00025 #include "syn_supcon.h" 00026 #include "syn_supnorm.h" 00027 #include "syn_functions.h" 00028 00029 00030 namespace faudes { 00031 00032 00033 /* 00034 *************************************************************************************** 00035 *************************************************************************************** 00036 Implementation IsOmegaControllabe 00037 *************************************************************************************** 00038 *************************************************************************************** 00039 */ 00040 00041 // IsOmegaControllable() 00042 bool IsOmegaControllable( 00043 const Generator& rGenPlant, 00044 const EventSet& rCAlph, 00045 const Generator& rGenCand) 00046 { 00047 FD_DF("IsOmegaControllable(\"" << rGenPlant.Name() << "\", \"" << rGenCand.Name() << "\")"); 00048 00049 // alphabets must match 00050 if ( rGenPlant.Alphabet() != rGenCand.Alphabet()) { 00051 std::stringstream errstr; 00052 errstr << "Alphabets of generators do not match."; 00053 throw Exception("IsOmegaControllable(..)", errstr.str(), 100); 00054 } 00055 00056 #ifdef FAUDES_CHECKED 00057 // generators are meant to be nonblocking 00058 if( !IsOmegaTrim(rGenCand) ) { 00059 std::stringstream errstr; 00060 errstr << "Argument \"" << rGenCand.Name() << "\" is not omega-trim."; 00061 throw Exception("IsOmegaControllable(..)", errstr.str(), 201); 00062 } 00063 if( !IsOmegaTrim(rGenPlant) ) { 00064 std::stringstream errstr; 00065 errstr << "Argument \"" << rGenPlant.Name() << "\" is not omega-trim."; 00066 throw Exception("IsOmegaControllable(..)", errstr.str(), 201); 00067 } 00068 #endif 00069 00070 // the trivial case: empty cand is fine 00071 // (we must treat this case because empty generators are not regarded deterministic) 00072 if(rGenCand.Empty()) { 00073 FD_DF("IsOmegaControllable(..): empty candidate, pass"); 00074 return true; 00075 } 00076 00077 // the trivial case: empty plant is fails 00078 // (we must treat this case because empty generators are not regarded deterministic) 00079 if(rGenPlant.Empty()) { 00080 FD_DF("IsOmegaControllable(..): empty plant, fail"); 00081 return false; 00082 } 00083 00084 #ifdef FAUDES_CHECKED 00085 // generators are meant to be deterministic 00086 if ( !IsDeterministic(rGenCand) || !IsDeterministic(rGenPlant)) { 00087 std::stringstream errstr; 00088 errstr << "Arguments are expected to be deterministic."; 00089 throw Exception("IsOmegaControllable", errstr.str(), 202); 00090 } 00091 #endif 00092 00093 // test controllability 00094 StateSet dummy; 00095 if(!IsControllableUnchecked(rGenPlant,rCAlph,rGenCand,dummy)) return false; 00096 00097 // test relative closedness 00098 if(!IsRelativelyOmegaClosedUnchecked(rGenPlant,rGenCand)) return false; 00099 00100 // pass 00101 FD_DF("IsOmegaControllable(...): passed"); 00102 return true; 00103 } 00104 00105 00106 // IsOmegaControllable() wrapper 00107 bool IsOmegaControllable( 00108 const System& rPlantGen, 00109 const Generator& rCandGen) 00110 { 00111 return IsOmegaControllable(rPlantGen,rPlantGen.ControllableEvents(),rCandGen); 00112 } 00113 00114 /* 00115 *************************************************************************************** 00116 *************************************************************************************** 00117 Implementation SupConCmplClosed 00118 *************************************************************************************** 00119 *************************************************************************************** 00120 */ 00121 00122 00123 // supcon complete 00124 void SupConCmplClosed( 00125 const Generator& rPlantGen, 00126 const EventSet& rCAlph, 00127 const Generator& rSpecGen, 00128 Generator& rResGen) 00129 { 00130 FD_DF("SupConCmplClosed(" << rPlantGen.Name() << "," << rSpecGen.Name()<< ")"); 00131 00132 // exceptions on invalid parameters, same as std synthesis 00133 ControlProblemConsistencyCheck(rPlantGen,rCAlph,rSpecGen); 00134 00135 // prepare result 00136 Generator* pResGen = &rResGen; 00137 if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) { 00138 pResGen= rResGen.New(); 00139 } 00140 pResGen->Clear(); 00141 pResGen->Name("SupConCmplClosed("+rPlantGen.Name()+", "+rSpecGen.Name()+")"); 00142 pResGen->InjectAlphabet(rPlantGen.Alphabet()); 00143 00144 //check for trivial result 00145 if(rSpecGen.InitStatesEmpty()){ 00146 FD_DF("SupConCmplClosed: empty language specification - empty result."); 00147 } 00148 00149 00150 // have a reverse composition map 00151 std::map< std::pair<Idx,Idx>, Idx> revmap; 00152 00153 // parallel composition (result is reachable) 00154 SupConProduct(rPlantGen, rCAlph, rSpecGen, revmap, *pResGen); 00155 00156 // make resulting generator complete and controllabel 00157 while(true) { 00158 Idx state_num = pResGen->Size(); 00159 if(pResGen->InitStates().Empty()) break; 00160 pResGen->Complete(); 00161 if(pResGen->InitStates().Empty()) break; 00162 SupConClosedUnchecked(rPlantGen, rCAlph, *pResGen); 00163 if(pResGen->Size() == state_num) break; 00164 } 00165 00166 // convenience state names 00167 if(rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && rResGen.StateNamesEnabled()) 00168 SetComposedStateNames(rPlantGen, rSpecGen, revmap, *pResGen); 00169 else 00170 pResGen->StateNamesEnabled(false); 00171 00172 // copy result 00173 if(pResGen != &rResGen) { 00174 pResGen->Move(rResGen); 00175 delete pResGen; 00176 } 00177 00178 } 00179 00180 00181 // user wrapper 00182 void SupConCmplClosed( 00183 const System& rPlantGen, 00184 const Generator& rSpecGen, 00185 Generator& rResGen) 00186 { 00187 00188 // execute 00189 SupConCmplClosed(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,rResGen); 00190 00191 // copy all attributes of input alphabet 00192 rResGen.EventAttributes(rPlantGen.Alphabet()); 00193 00194 } 00195 00196 00197 00198 00199 /* 00200 *************************************************************************************** 00201 *************************************************************************************** 00202 Implementation SupConCmplNB 00203 *************************************************************************************** 00204 *************************************************************************************** 00205 */ 00206 00207 00208 // supcon complete 00209 void SupConCmplNB( 00210 const Generator& rPlantGen, 00211 const EventSet& rCAlph, 00212 const Generator& rSpecGen, 00213 Generator& rResGen) 00214 { 00215 FD_DF("SupConCmplNB(" << rPlantGen.Name() << "," << rSpecGen.Name()<< ")"); 00216 00217 // exceptions on invalid parameters, same as std synthesis 00218 ControlProblemConsistencyCheck(rPlantGen,rCAlph,rSpecGen); 00219 00220 // prepare result 00221 Generator* pResGen = &rResGen; 00222 if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) { 00223 pResGen= rResGen.New(); 00224 } 00225 pResGen->Clear(); 00226 pResGen->Name("SupConCmplNB("+rPlantGen.Name()+", "+rSpecGen.Name()+")"); 00227 pResGen->InjectAlphabet(rPlantGen.Alphabet()); 00228 00229 //check for trivial result 00230 if(rSpecGen.InitStatesEmpty()){ 00231 FD_DF("SupConCmplNB: empty language specification - empty result."); 00232 } 00233 00234 00235 // have a reverse composition map 00236 std::map< std::pair<Idx,Idx>, Idx> revmap; 00237 00238 // parallel composition (result is reachable) 00239 SupConProduct(rPlantGen, rCAlph, rSpecGen, revmap, *pResGen); 00240 00241 // make resulting generator complete and controllabel and coaccessible 00242 while(true) { 00243 Idx state_num = pResGen->Size(); 00244 if(pResGen->InitStates().Empty()) break; 00245 pResGen->Coaccessible(); 00246 if(pResGen->InitStates().Empty()) break; 00247 pResGen->Complete(); 00248 if(pResGen->InitStates().Empty()) break; 00249 SupConClosedUnchecked(rPlantGen, rCAlph, *pResGen); 00250 if(pResGen->Size() == state_num) break; 00251 } 00252 00253 // convenience state names 00254 if(rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && rResGen.StateNamesEnabled()) 00255 SetComposedStateNames(rPlantGen, rSpecGen, revmap, *pResGen); 00256 else 00257 pResGen->StateNamesEnabled(false); 00258 00259 // copy result 00260 if(pResGen != &rResGen) { 00261 pResGen->Move(rResGen); 00262 delete pResGen; 00263 } 00264 00265 } 00266 00267 00268 // user wrapper 00269 void SupConCmplNB( 00270 const System& rPlantGen, 00271 const Generator& rSpecGen, 00272 Generator& rResGen) 00273 { 00274 00275 // execute 00276 SupConCmplNB(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,rResGen); 00277 00278 // copy all attributes of input alphabet 00279 rResGen.EventAttributes(rPlantGen.Alphabet()); 00280 00281 } 00282 00283 00284 00285 /* 00286 *************************************************************************************** 00287 *************************************************************************************** 00288 Implementation SupConNormCmplNB 00289 *************************************************************************************** 00290 *************************************************************************************** 00291 */ 00292 00293 00294 // SupConNormCmplNB(rL,rCAlph,rOAlph,rK,rResult) 00295 void SupConNormCmplNB( 00296 const Generator& rL, 00297 const EventSet& rCAlph, 00298 const EventSet& rOAlph, 00299 const Generator& rK, 00300 Generator& rResult) 00301 { 00302 FD_DF("SupConNormCmplNB(" << rL.Name() << "," << rK.Name() << ")"); 00303 // initialize: K0 00304 Generator K0; 00305 K0.StateNamesEnabled(false); 00306 Product(rL,rK,K0); 00307 K0.Coaccessible(); 00308 // initialize: closure(rL) 00309 Generator L=rL; 00310 L.StateNamesEnabled(false); 00311 L.Trim(); 00312 MarkAllStates(L); 00313 // loop 00314 Generator Ki=K0; 00315 Ki.StateNamesEnabled(false); 00316 while(1) { 00317 FD_DF("SupConNormCmplNB(" << rL.Name() << "," << rK.Name() << "): #" << Ki.Size() << " m#" << Ki.MarkedStatesSize()); 00318 // keep copy of recent 00319 rResult=Ki; 00320 // cheep closure (for coreachable generator) 00321 Ki.InjectMarkedStates(Ki.States()); 00322 // synthesise closed 00323 SupConNormClosed(L,rCAlph,rOAlph,Ki,Ki); 00324 Complete(Ki); 00325 // restrict 00326 Product(K0,Ki,Ki); 00327 Ki.Coaccessible(); 00328 // test (sequence is decreasing anyway) 00329 if(LanguageInclusion(rResult,Ki)) break; 00330 } 00331 FD_DF("SupConNormCmplNB(" << rL.Name() << "," << rK.Name() << "): done"); 00332 } 00333 00334 00335 /** rti wrapper */ 00336 void SupConNormCmplNB( 00337 const System& rPlantGen, 00338 const Generator& rSpecGen, 00339 Generator& rResGen) 00340 { 00341 FD_DF("SupConNormCmplNB(" << rPlantGen.Name() << "," << rSpecGen.Name() << "): rti wrapper"); 00342 // prepare result 00343 Generator* pResGen = &rResGen; 00344 if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) { 00345 pResGen= rResGen.New(); 00346 } 00347 // execute 00348 SupConNormCmplNB(rPlantGen,rPlantGen.ControllableEvents(),rPlantGen.ObservableEvents(),rSpecGen,*pResGen); 00349 // copy all attributes of input alphabet 00350 pResGen->EventAttributes(rPlantGen.Alphabet()); 00351 // copy result 00352 if(pResGen != &rResGen) { 00353 pResGen->Move(rResGen); 00354 delete pResGen; 00355 } 00356 } 00357 00358 00359 /* 00360 *************************************************************************************** 00361 *************************************************************************************** 00362 Computation of the controllable prefix / enforcing omega-controlled liveness 00363 *************************************************************************************** 00364 *************************************************************************************** 00365 */ 00366 00367 00368 00369 /* 00370 Initial libFAUDES implementation of omega-controlled liveness, tmoor 2011, last used 00371 for libFAUDES 2.22p. The function retsricts the candidate to states for which a 00372 prefix-closed controller exists such that in closed-loop configuration the acceptance condition 00373 is implied by the plant acceptance condition. This corresponds to the controllable prefix, 00374 originally proposed by J. Thistle et al. The actual implementation, however, is based on a sufficient 00375 but not necessary test. It therefore identifies a subset of the controllable prefix, which may 00376 turn out empty even when a prefix-closed controller exists. The below code is obsolete and will 00377 be removed eventually. 00378 */ 00379 00380 /* 00381 00382 // OmegaControlledLiveness(...) 00383 bool OmegaControlledLiveness( 00384 Generator& rSupCandGen, 00385 const EventSet& rCAlph, 00386 StateSet& rMarkedPlantStates, 00387 StateSet& rMarkedSpecStates) 00388 { 00389 FD_DF("OmegaControlledLiveness(...)"); 00390 00391 // set of critical states 00392 StateSet critical; 00393 00394 // return true if parallelcomp contains no initial states 00395 if(rSupCandGen.InitStatesEmpty()) { 00396 return true; 00397 } 00398 00399 #ifdef FAUDES_DEBUG_FUNCTION 00400 FD_DF("OmegaControlledLiveness(): marked states: "); 00401 StateSet ssd= rMarkedPlantStates + rMarkedSpecStates; 00402 ssd.Write(); 00403 #endif 00404 00405 // find un-marked sccs 00406 StateSet astates = rMarkedPlantStates + rMarkedSpecStates; 00407 SccFilter umfilter(SccFilter::FmIgnoreTrivial | SccFilter::FmStatesAvoid, astates); 00408 std::list<StateSet> umsccs; 00409 StateSet umroots; 00410 ComputeScc(rSupCandGen,umfilter,umsccs,umroots); 00411 00412 // report 00413 std::list<StateSet>::iterator ssit=umsccs.begin(); 00414 for(;ssit!=umsccs.end(); ++ssit) { 00415 FD_DF("OmegaControlledLiveness(): unmarked scc: " << ssit->ToString()); 00416 } 00417 00418 // good-states iteration 00419 StateSet goodstates = rMarkedSpecStates; 00420 00421 // drive states to good states 00422 while(true) { 00423 // LoopCallback(); 00424 // allow for user interrupt, incl progress report 00425 FD_WPC(1,2,"OmegaControlledLiveness(): iterating states"); 00426 // test individual states 00427 FD_DF("OmegaControlledLiveness(): iterate over states (#" << rSupCandGen.Size() << ")"); 00428 bool found=false; 00429 00430 StateSet::Iterator sit = rSupCandGen.StatesBegin(); 00431 StateSet::Iterator sit_end = rSupCandGen.StatesEnd(); 00432 for(; sit!=sit_end; ++sit) { 00433 bool fail = false; // cbaier 20121011 00434 bool positive=false; // cbaier 20121011 00435 // goodstate anyway 00436 if(goodstates.Exists(*sit)) continue; 00437 // test transitions 00438 TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit); 00439 TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit); 00440 // no transitions at all 00441 if(tit==tit_end) continue; 00442 // loop over successors 00443 for(; tit!=tit_end; ++tit) { 00444 if(goodstates.Exists(tit->X2)) 00445 {positive=true; // cbaier 20121011: added 00446 continue;} 00447 if(rCAlph.Exists(tit->Ev)) continue; 00448 00449 // good states survive the loop // cbaier 20121011: added 00450 if(tit!=tit_end) { 00451 fail=true; 00452 break; 00453 } 00454 } 00455 00456 // good states survive 00457 if(!fail && positive) { // cbaier 20121011: changed 00458 FD_DF("OmegaControlledLiveness(): good state " << rSupCandGen.SStr(*sit)); 00459 goodstates.Insert(*sit); 00460 found=true; 00461 } 00462 } 00463 00464 // test individual unmarked sccs 00465 FD_DF("OmegaControlledLiveness(): iterate over unmarked sccs (#" << umsccs.size() <<")"); 00466 std::list<StateSet>::iterator ssit=umsccs.begin(); 00467 while(ssit!=umsccs.end()) { 00468 bool fail=false; 00469 bool positive=false; 00470 sit=ssit->Begin(); 00471 sit_end=ssit->End(); 00472 for(; sit!=sit_end; ++sit) { 00473 // goodstate anyway 00474 if(goodstates.Exists(*sit)) continue; 00475 // test transitions 00476 TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit); 00477 TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit); 00478 // no transitions at all 00479 if(tit==tit_end) continue; 00480 // loop over successors 00481 for(; tit!=tit_end; ++tit) { 00482 if(goodstates.Exists(tit->X2)) { positive=true; continue;} 00483 if(rCAlph.Exists(tit->Ev)) continue; // tmoor 20110202: fixed typo 00484 if(ssit->Exists(tit->X2)) continue; 00485 break; 00486 } 00487 // good states survive the loop 00488 if(tit!=tit_end) { 00489 fail=true; 00490 break; 00491 } 00492 } 00493 00494 // prepare next scc iterator 00495 std::list<StateSet>::iterator ssitnext=ssit; 00496 ++ssitnext; 00497 bool lend= (ssitnext==umsccs.end()); 00498 // all states passed, then they are all good 00499 if(!fail && positive) { 00500 FD_DF("OmegaControlledLiveness(): good scc " << ssit->ToString()); 00501 goodstates.InsertSet(*ssit); 00502 umsccs.erase(ssit); 00503 found=true; 00504 } 00505 // break on end of list 00506 if(lend) break; 00507 // progress 00508 ssit=ssitnext; 00509 } 00510 00511 // exit 00512 if(!found) break; 00513 }; 00514 00515 // delete critical states 00516 FD_DF("OmegaControlledLiveness(): good states: " << goodstates.ToString()) 00517 StateSet::Iterator sit = rSupCandGen.StatesBegin(); 00518 StateSet::Iterator sit_end = rSupCandGen.StatesEnd(); 00519 for(; sit!=sit_end; ++sit) { 00520 if(!goodstates.Exists(*sit)) 00521 rSupCandGen.DelState(*sit); 00522 } 00523 00524 // return true 00525 FD_DF("OmegaControlledLiveness(): done"); 00526 return true; 00527 } 00528 00529 */ 00530 00531 00532 /* 00533 This implementation is a direct transscript of the mu-calculus formulas stated in "Control of 00534 w-Automata, Church's Problem, and the Emptiness Problem for Tree w-Automata", by J. Thistle and 00535 W.M. Wonham, 1992, adapted for the special case of deterministic Buchi-automata. Referring to the 00536 referenced literature, the corresponding iteration is "essentially optimal" in terms of performance. 00537 In the below implementation, we unwind each individual mu/nu quantifiation literally and resist 00538 to apply strategic substitutions in order to obtain a reference implementation. This is suspected 00539 to introduce (linear) penalty for avoidable boolean operations on sets of states. In a recent study, 00540 Christian Wamser proposes fine-tuned alternative implementation which will be integrated in 00541 libFAUDES in due course. 00542 */ 00543 00544 bool OmegaControlledLiveness( 00545 Generator& rSupCandGen, 00546 const EventSet& rCAlph, 00547 const StateSet& rPlantMarking) 00548 { 00549 00550 FD_DF("OmegaControlledLiveness()"); 00551 00552 // declare iterate sets 00553 StateSet resolved, initialK, targetLstar; 00554 StateSet initialL, targetL; 00555 StateSet domainL, target1; 00556 StateSet target, domain, theta; 00557 00558 // convenience 00559 const StateSet& full = rSupCandGen.States(); 00560 Idx fsz=full.Size(); 00561 00562 // evaluate mu(resolved).nu(initialK)[ p(initialK * markedK + resolved )) ]; 00563 // here, p(T) denotes the set of states that can be driven to enter T under liveness assumption inf-markL; 00564 // use std. mu-nu-iteration 00565 resolved.Clear(); 00566 while(true) { 00567 Idx rsz = resolved.Size(); 00568 initialK = full; 00569 while(true) { 00570 Idx iKsz = initialK.Size(); 00571 00572 // prepare target for P(): targetLstar = initialK * markedK + resolved 00573 targetLstar = (initialK * rSupCandGen.MarkedStates()) + resolved; 00574 FD_DF("OmegaControlledLiveness(): [STD] iterate resolved/targetLstar #" << xsz << "/" << targetLstar.Size()); 00575 00576 // evaluate p(targetLstar) = mu(initialL).[ thetaTilde(targetLstar+initialL) ] 00577 // here, thetaTilde(T) denotes the set of states that can be controlled such that T is persistently 00578 // reachable and markL is not passed before T is entered; 00579 // start with initialL:=0 and iterate initialL += thetaTilde(targetLstar+initialL); 00580 initialL.Clear(); 00581 while(true) { 00582 Idx iLsz = initialL.Size(); 00583 00584 // prepare targetL=targetLstar+initialL 00585 targetL=targetLstar+initialL; 00586 FD_DF("OmegaControlledLiveness(): [STD] ---- iterate targetL #" << targetL.Size()); 00587 00588 // evaluate thetaTilde(targetL)=nu(domainL).mu(target1)[ theta(targetL+(target1-markL), domainL-markL) ]; 00589 // here, theta(T,D) is the set of states that, by one transition, can enter T and can be controlled not to exit D+T; 00590 // start with domainL:=full and iterate domainL -= mu(target1)[theta(targetL+(target1-markL), domainL-markL)]; 00591 domainL=full; 00592 targetL = targetLstar + initialL; 00593 while(true) { 00594 Idx dLsz = domainL.Size(); 00595 FD_DF("OmegaControlledLiveness(): [STD] --- iterate domainL #" << domainL.Size()); 00596 00597 // user interrupt/ progress 00598 FD_WPC(1,2,"OmegaControlledLiveness(): [STD] iterating reverse dynamics"); 00599 00600 // prepare domain = domainL - marL 00601 domain=domainL-rPlantMarking; 00602 00603 // evaluate mu(target1)[ theta(targetL+(target1-markL), domain) ]; 00604 // start with target1:=0 and iterate target+=theta(targetL+(target1-markL), domainL-markL) ]; 00605 target1.Clear(); 00606 while(true) { 00607 Idx t1sz = target1.Size(); 00608 00609 // prepare target= targetL+(target1-markL) 00610 target = targetL + (target1-rPlantMarking); 00611 00612 // evaluate theta(target,domain) 00613 FD_DF("OmegaControlledLiveness(): [STD] -- evaluate theta for target/domain # " 00614 << target.Size() << "/" << domain.Size()); 00615 theta.Clear(); 00616 StateSet::Iterator sit = full.Begin(); 00617 StateSet::Iterator sit_end = full.End(); 00618 for(;sit!=sit_end;++sit) { 00619 bool pass = false; 00620 bool fail = false; 00621 TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit); 00622 TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit); 00623 for(;tit!=tit_end; ++tit) { 00624 if(target.Exists(tit->X2)) {pass = true; continue;} 00625 if(domain.Exists(tit->X2)) {continue;} 00626 if(!rCAlph.Exists(tit->Ev)){ fail = true; break;} 00627 } 00628 if(pass && !fail) { 00629 theta.Insert(*sit); 00630 FD_DF("OmegaControlledLiveness(): [STD] theta found state " << rSupCandGen.SStr(*sit)); 00631 } 00632 } // end: theta 00633 00634 // mu-loop on target1 00635 target1.InsertSet(theta); 00636 if(target1.Size()==t1sz) break; 00637 if(target1.Size()==fsz) break; 00638 } // end: mu 00639 00640 FD_DF("OmegaControlledLiveness(): [STD] -- mu-target1 # " << target1.Size()); 00641 00642 // nu-loop on domainL 00643 domainL.RestrictSet(target1); 00644 if(domainL.Size()==dLsz) break; 00645 if(domainL.Size()==0) break; 00646 } // end: nu 00647 00648 FD_DF("OmegaControlledLiveness(): [STD] --- nu-domainL-mu-target1 # " << domainL.Size()); 00649 00650 // mu-loop on initialL 00651 initialL.InsertSet(domainL); 00652 if(initialL.Size()==iLsz) break; 00653 if(initialL.Size()==fsz) break; 00654 } // end: mu 00655 00656 // nu-loop on initialK 00657 initialK.RestrictSet(initialL); 00658 if(initialK.Size()==iKsz) break; 00659 if(initialK.Size()==0) break; 00660 } // end: nu 00661 00662 // mu-loop on resolved 00663 resolved.InsertSet(initialK); 00664 if(resolved.Size()==rsz) break; 00665 if(resolved.Size()==fsz) break; 00666 } // end: mu 00667 00668 // restrict candidate to resolved states 00669 rSupCandGen.DelStates(full - resolved); 00670 00671 // done 00672 return true; 00673 } 00674 00675 00676 /* 00677 Variant of the controllable prefix to extract a particular feedback map. Again, this is 00678 very close to the relevant literature and meant as a reference. A more efficient 00679 implementation proposed by Christian Wamser will be integrated in due course. 00680 */ 00681 00682 bool OmegaControlledLiveness( 00683 Generator& rSupCandGen, 00684 const EventSet& rCAlph, 00685 const StateSet& rPlantMarking, 00686 std::map< Idx , EventSet>& rFeedbackMap) 00687 { 00688 00689 FD_WARN("OmegaControlledLiveness()"); 00690 00691 // declare iterate sets 00692 StateSet resolved, initialK, targetLstar; 00693 StateSet initialL, targetL; 00694 StateSet domainL, target1; 00695 StateSet target, domain, theta; 00696 00697 // record controls per state 00698 EventSet disable; 00699 std::map< Idx , EventSet> controls1; 00700 std::map< Idx , EventSet> controls1L; 00701 std::map< Idx , EventSet> controls1X; 00702 00703 // convenience 00704 const StateSet& full = rSupCandGen.States(); 00705 Idx fsz=full.Size(); 00706 00707 // evaluate mu(resolved).nu(initialK)[ p(initialK * markedK + resolved )) ]; 00708 resolved.Clear(); 00709 while(true) { 00710 Idx xsz = resolved.Size(); 00711 initialK = full; 00712 while(true) { 00713 Idx rsz = initialK.Size(); 00714 targetLstar = (initialK * rSupCandGen.MarkedStates()) + resolved; 00715 FD_WARN("OmegaControlledLiveness(): [FBM] iterate resolved/targetLstar #" << xsz << "/" << targetLstar.Size()); 00716 00717 // reset controls 00718 controls1L.clear(); 00719 00720 // evaluate p(targetLstar) = mu(initialL).[ thetaTilde(targetLstar+initialL) ] 00721 initialL.Clear(); 00722 while(true) { 00723 Idx t1Lsz = initialL.Size(); 00724 targetL = targetLstar + initialL; 00725 FD_WARN("OmegaControlledLiveness(): [FBM] ---- iterate targetL #" << targetL.Size()); 00726 00727 // evaluate thetaTilde(targetL)=nu(domainL).mu(target1)[ theta(targetL+(target1-markL), domainL-markL) ]; 00728 domainL=full; 00729 while(true) { 00730 Idx dsz = domainL.Size(); 00731 domain=domainL-rPlantMarking; 00732 FD_WARN("OmegaControlledLiveness(): [FBM] --- iterate domain #" << domain.Size()); 00733 00734 // reset controls 00735 controls1.clear(); 00736 00737 // user interrupt/ progress 00738 FD_WPC(1,2,"OmegaControlledLiveness(): [FBM] iterating reverse dynamics"); 00739 00740 // evaluate mu(target1)[ theta(targetL+(target1-markL), domain) ]; 00741 target1.Clear(); 00742 while(true) { 00743 Idx t1sz = target1.Size(); 00744 target = targetL + (target1-rPlantMarking); 00745 00746 // evaluate theta(target,domain) 00747 FD_WARN("OmegaControlledLiveness(): [FBM] -- evaluate theta for target/domain # " 00748 << target.Size() << "/" << domain.Size()); 00749 theta.Clear(); 00750 StateSet::Iterator sit = full.Begin(); 00751 StateSet::Iterator sit_end = full.End(); 00752 for(;sit!=sit_end;++sit) { 00753 bool pass = false; 00754 bool fail = false; 00755 disable.Clear(); 00756 TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit); 00757 TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit); 00758 for(;tit!=tit_end; ++tit) { 00759 if(target.Exists(tit->X2)) { pass = true; continue; } 00760 if(domain.Exists(tit->X2)) { continue; } 00761 if(!rCAlph.Exists(tit->Ev)){ fail = true; break; } 00762 disable.Insert(tit->Ev); 00763 } 00764 if(pass && !fail) { 00765 theta.Insert(*sit); 00766 if(controls1.find(*sit)==controls1.end()) controls1[*sit]=disable; 00767 FD_WARN("OmegaControlledLiveness(): [FBM] theta found state " << rSupCandGen.SStr(*sit)); 00768 if(!disable.Empty())disable.Write(); 00769 } 00770 } // end: theta 00771 00772 // mu-loop on target1 00773 target1.InsertSet(theta); 00774 if(target1.Size()==t1sz) break; 00775 if(target1.Size()==fsz) break; 00776 } // end: mu 00777 00778 FD_WARN("OmegaControlledLiveness(): [FBM] -- mu-target1 # " << target1.Size()); 00779 00780 // nu-loop on domainL 00781 domainL.RestrictSet(target1); 00782 if(domainL.Size()==dsz) break; 00783 if(domainL.Size()==0) break; 00784 } // end: nu 00785 00786 FD_WARN("OmegaControlledLiveness(): [FBM] --- nu-domainL-mu-target1 # " << domainL.Size()); 00787 00788 // merge controls 00789 std::map< Idx , EventSet>::iterator cit=controls1.begin(); 00790 std::map< Idx , EventSet>::iterator cit_end=controls1.end(); 00791 for(;cit!=cit_end;++cit) { 00792 if(controls1L.find(cit->first)!=controls1L.end()) continue; 00793 controls1L[cit->first]=cit->second; 00794 } 00795 00796 // mu-loop on initialL 00797 initialL.InsertSet(domainL); 00798 if(initialL.Size()==t1Lsz) break; 00799 if(initialL.Size()==fsz) break; 00800 } // end: mu 00801 00802 // nu-loop on initialK 00803 initialK.RestrictSet(initialL); 00804 if(initialK.Size()==rsz) break; 00805 if(initialK.Size()==0) break; 00806 } // end: nu 00807 00808 // merge controls 00809 std::map< Idx , EventSet>::iterator cit=controls1L.begin(); 00810 std::map< Idx , EventSet>::iterator cit_end=controls1L.end(); 00811 for(;cit!=cit_end;++cit) { 00812 if(controls1X.find(cit->first)!=controls1X.end()) continue; 00813 controls1X[cit->first]=cit->second; 00814 } 00815 00816 // mu-loop on resolved 00817 resolved.InsertSet(initialK); 00818 if(resolved.Size()==xsz) break; 00819 if(resolved.Size()==fsz) break; 00820 } // end: mu 00821 00822 // restrict candidate to valid restrict 00823 rSupCandGen.DelStates(full - resolved); 00824 00825 // re-write controls as feedback map 00826 EventSet ucalph = rSupCandGen.Alphabet() - rCAlph; 00827 StateSet::Iterator sit = resolved.Begin(); 00828 StateSet::Iterator sit_end = resolved.End(); 00829 for(;sit!=sit_end;++sit) { 00830 FD_WARN("OmegaControlledLiveness(): [FBM] controls " << rSupCandGen.SStr(*sit) << " " << controls1X[*sit].ToString()); 00831 rFeedbackMap[*sit]= (rSupCandGen.ActiveEventSet(*sit) + ucalph) - controls1X[*sit]; 00832 } 00833 00834 // done 00835 return true; 00836 } 00837 00838 00839 00840 00841 // helper class: mergable control pattern 00842 class MCtrlPattern { 00843 public: 00844 // merge with other 00845 void merge(const MCtrlPattern& other) { 00846 disable_all.InsertSet(other.disable_all); 00847 enable_one.insert(other.enable_one.begin(),other.enable_one.end()); 00848 } 00849 // test conflict 00850 bool conflict() { 00851 std::set< EventSet >::iterator eit =enable_one.begin(); 00852 std::set< EventSet >::iterator eit_end =enable_one.end(); 00853 for(; eit!=eit_end ; ++eit) 00854 if( (*eit - disable_all).Empty() ) return true; 00855 return false; 00856 } 00857 // member variables 00858 EventSet disable_all; 00859 std::set< EventSet > enable_one; 00860 }; 00861 00862 00863 00864 /* 00865 Variant of a controllable prefix under partial observation. This is **experimantal**. 00866 Based on the situation of full observation, this variant records control patterns 00867 used to establish controlled liveness and only accepts a new state if the corresponding 00868 pattern complies all recorded patterns that correspond to the same observation. 00869 The result is a (possibly strict) subset of the controllable prefix for the purpose. 00870 Theoretical background will be provided in due course. 00871 */ 00872 00873 bool OmegaControlledLiveness( 00874 Generator& rSupCandGen, 00875 const EventSet& rCAlph, 00876 const StateSet& rPlantMarking, 00877 std::map< Idx , Idx>& rControllerStatesMap, 00878 std::map< Idx , EventSet>& rFeedbackMap) 00879 { 00880 00881 FD_WARN("OmegaControlledLiveness(): [POBS]: cand #" << rSupCandGen.Size()); 00882 00883 // debugging: interpret empty controllermap as identity 00884 StateSet::Iterator xit = rSupCandGen.StatesBegin(); 00885 StateSet::Iterator xit_end = rSupCandGen.StatesEnd(); 00886 for(;xit!=xit_end;++xit) { 00887 std::map< Idx , Idx >::const_iterator cxit=rControllerStatesMap.find(*xit); 00888 if(cxit==rControllerStatesMap.end()) rControllerStatesMap[*xit]=*xit; 00889 } 00890 00891 // informative 00892 std::map< Idx , Idx>::const_iterator oit = rControllerStatesMap.begin(); 00893 std::set< Idx > ostates; 00894 for(; oit != rControllerStatesMap.end(); ++oit) 00895 ostates.insert(oit->second); 00896 FD_WARN("OmegaControlledLiveness(): [POBS]: " << "obs #" << ostates.size()); 00897 00898 // declare iterate sets 00899 StateSet resolved, initialK, targetLstar; 00900 StateSet initialL, targetL; 00901 StateSet domainL, target1; 00902 StateSet target, domain, theta; 00903 00904 // record controls per state 00905 EventSet disable; 00906 EventSet enable; 00907 std::map< Idx , MCtrlPattern> controlsT; 00908 std::map< Idx , MCtrlPattern> controls1; 00909 std::map< Idx , MCtrlPattern> controls1L; 00910 std::map< Idx , MCtrlPattern> controls1X; 00911 00912 // convenience 00913 const StateSet& full = rSupCandGen.States(); 00914 Idx fsz=full.Size(); 00915 00916 // evaluate mu(resolved).nu(initialK)[ p(initialK * markedK + resolved )) ]; 00917 resolved.Clear(); 00918 while(true) { 00919 Idx xsz = resolved.Size(); 00920 initialK = full; 00921 while(true) { 00922 Idx rsz = initialK.Size(); 00923 targetLstar = (initialK * rSupCandGen.MarkedStates()) + resolved; 00924 FD_WARN("OmegaControlledLiveness(): [POBS] iterate resolved/targetLstar #" << xsz << "/" << targetLstar.Size()); 00925 00926 // reset controls 00927 controls1L.clear(); 00928 00929 // evaluate p(targetLstar) = mu(initialL).[ thetaTilde(targetLstar+initialL) ] 00930 initialL.Clear(); 00931 while(true) { 00932 Idx t1Lsz = initialL.Size(); 00933 targetL = targetLstar + initialL; 00934 FD_WARN("OmegaControlledLiveness(): [POBS] ---- iterate targetL #" << targetL.Size()); 00935 00936 // evaluate thetaTilde(targetL)=nu(domainL).mu(target1)[ theta(targetL+(target1-markL), domainL-markL) ]; 00937 domainL=full; 00938 while(true) { 00939 Idx dsz = domainL.Size(); 00940 domain=domainL-rPlantMarking; 00941 FD_WARN("OmegaControlledLiveness(): [POBS] --- iterate domain #" << domain.Size()); 00942 00943 // reset controls 00944 controls1.clear(); 00945 00946 // user interrupt/ progress 00947 FD_WPC(1,2,"OmegaControlledLiveness(): [POBS] iterating reverse dynamics"); 00948 00949 // evaluate mu(target1)[ theta(targetL+(target1-markL), domain) ]; 00950 target1.Clear(); 00951 while(true) { 00952 Idx t1sz = target1.Size(); 00953 target = targetL + (target1-rPlantMarking); 00954 00955 // evaluate theta(target,domain) in three passes 00956 FD_WARN("OmegaControlledLiveness(): [POBS] -- evaluate theta for target/domain # " 00957 << target.Size() << "/" << domain.Size()); 00958 theta.Clear(); 00959 controlsT.clear(); 00960 00961 // pass 1: find new candidate states and acumulate required controls 00962 StateSet::Iterator sit = full.Begin(); 00963 StateSet::Iterator sit_end = full.End(); 00964 for(;sit!=sit_end;++sit) { 00965 Idx cx=rControllerStatesMap[*sit]; 00966 bool pass = false; 00967 bool fail = false; 00968 disable.Clear(); 00969 enable.Clear(); 00970 TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit); 00971 TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit); 00972 for(;tit!=tit_end; ++tit) { 00973 if(disable.Exists(tit->Ev)) continue; 00974 if(target.Exists(tit->X2)) {enable.Insert(tit->Ev); pass = true; continue;} 00975 if(domain.Exists(tit->X2)) {continue;} 00976 if(!rCAlph.Exists(tit->Ev)){ fail = true; break;} 00977 disable.Insert(tit->Ev); 00978 } 00979 if(pass && !fail) { 00980 // initialize control with existing patterns 00981 if(controlsT.find(cx)==controlsT.end()) { 00982 if(controls1.find(cx)!=controls1.end()) 00983 controlsT[cx].merge(controls1[cx]); 00984 if(controls1L.find(cx)!=controls1L.end()) 00985 controlsT[cx].merge(controls1L[cx]); 00986 if(controls1X.find(cx)!=controls1X.end()) 00987 controlsT[cx].merge(controls1X[cx]); 00988 } 00989 // apply additional pattern 00990 controlsT[cx].disable_all.InsertSet(disable); 00991 controlsT[cx].enable_one.insert(enable); 00992 } 00993 } // end: theta pass 1 00994 00995 // pass 2: merge new controls to controls1, reject conflicting 00996 std::map< Idx , MCtrlPattern >::iterator cpit=controlsT.begin(); 00997 std::map< Idx , MCtrlPattern >::iterator cpit_end=controlsT.end(); 00998 while(cpit!=cpit_end) { 00999 if(cpit->second.conflict()) {controlsT.erase(cpit++); continue;} 01000 controls1[cpit->first].merge(cpit->second); 01001 ++cpit; 01002 } 01003 01004 // pass 3: evaluate theta by accumulated controls control 01005 sit = rSupCandGen.StatesBegin(); 01006 sit_end = rSupCandGen.StatesEnd(); 01007 for(;sit!=sit_end;++sit) { 01008 bool pass = false; 01009 bool fail = false; 01010 Idx cx=rControllerStatesMap[*sit]; 01011 if(controls1.find(cx)==controls1.end()) continue; 01012 disable=controls1[cx].disable_all; 01013 TransSet::Iterator tit = rSupCandGen.TransRelBegin(*sit); 01014 TransSet::Iterator tit_end = rSupCandGen.TransRelEnd(*sit); 01015 for(;tit!=tit_end; ++tit) { 01016 if(disable.Exists(tit->Ev)) continue; 01017 if(target.Exists(tit->X2)) {pass = true; continue;} 01018 if(domain.Exists(tit->X2)) {continue;} 01019 fail = true; 01020 } 01021 if(pass && !fail) { 01022 theta.Insert(*sit); 01023 //FD_WARN("OmegaControlledLiveness(): [POBS] theta candidate verified " << rSupCandGen.SStr(*sit)); 01024 } 01025 } // end: theta pass 3 01026 01027 // mu-loop on target1 01028 target1.InsertSet(theta); 01029 if(target1.Size()==t1sz) break; 01030 if(target1.Size()==fsz) break; 01031 } // end: mu 01032 01033 FD_WARN("OmegaControlledLiveness(): [POBS] -- mu-target1 # " << target1.Size()); 01034 01035 // nu-loop on domainL 01036 domainL.RestrictSet(target1); 01037 if(domainL.Size()==dsz) break; 01038 if(domainL.Size()==0) break; 01039 } // end: nu 01040 01041 FD_WARN("OmegaControlledLiveness(): [POBS] --- nu-domainL-mu-target1 # " << domainL.Size()); 01042 01043 // merge controls 01044 std::map< Idx , MCtrlPattern>::iterator cit = controls1.begin(); 01045 std::map< Idx , MCtrlPattern>::iterator cit_end = controls1.end(); 01046 for(;cit!=cit_end;++cit) 01047 controls1L[cit->first].merge(cit->second); 01048 01049 // mu-loop on initialL 01050 initialL.InsertSet(domainL); 01051 if(initialL.Size()==t1Lsz) break; 01052 if(initialL.Size()==fsz) break; 01053 } // end: mu 01054 01055 // nu-loop on initialK 01056 initialK.RestrictSet(initialL); 01057 if(initialK.Size()==rsz) break; 01058 if(initialK.Size()==0) break; 01059 } // end: nu 01060 01061 // merge controls 01062 std::map< Idx , MCtrlPattern>::iterator cit = controls1L.begin(); 01063 std::map< Idx , MCtrlPattern>::iterator cit_end = controls1L.end(); 01064 for(;cit!=cit_end;++cit) 01065 controls1X[cit->first].merge(cit->second); 01066 01067 // mu-loop on resolved 01068 resolved.InsertSet(initialK); 01069 if(resolved.Size()==xsz) break; 01070 if(resolved.Size()==fsz) break; 01071 } // end: mu 01072 01073 // restrict candidate to valid restrict 01074 rSupCandGen.DelStates(full - resolved); 01075 01076 // debugging 01077 if(rSupCandGen.IsCoaccessible()) 01078 FD_WARN("OmegaControlledLiveness(): [POBS] ---- coaccessible ok"); 01079 if(rSupCandGen.IsComplete()) 01080 FD_WARN("OmegaControlledLiveness(): [POBS] ---- complete ok"); 01081 if(!rSupCandGen.InitStates().Empty()) 01082 FD_WARN("OmegaControlledLiveness(): [POBS] ---- init state ok"); 01083 01084 // re-write controls as feedback map (w.r.t. candidate states) 01085 StateSet::Iterator sit = resolved.Begin(); 01086 StateSet::Iterator sit_end = resolved.End(); 01087 for(;sit!=sit_end;++sit) { 01088 Idx cx=rControllerStatesMap[*sit]; 01089 //FD_WARN("OmegaControlledLiveness(): [POBS] controls at cx=" << cx << " for plant state " << rSupCandGen.SStr(*sit) << " " << controls1X[cx].disable_all.ToString()); 01090 rFeedbackMap[*sit]= rSupCandGen.Alphabet() - controls1X[cx].disable_all; 01091 } 01092 01093 // done 01094 return true; 01095 } 01096 01097 01098 /* 01099 *************************************************************************************** 01100 *************************************************************************************** 01101 Implementation of OmegaSupConNB and friends 01102 *************************************************************************************** 01103 *************************************************************************************** 01104 */ 01105 01106 // helper class: omega-product state 01107 class OPSState { 01108 public: 01109 // minimal interface 01110 OPSState() {}; 01111 OPSState(const Idx& rq1, const Idx& rq2, const bool& rf) : 01112 q1(rq1), q2(rq2), m1required(rf) {}; 01113 std::string Str(void) { return ToStringInteger(q1)+"|"+ 01114 ToStringInteger(q2)+"|"+ToStringInteger(m1required); }; 01115 // order 01116 bool operator < (const OPSState& other) const { 01117 if (q1 < other.q1) return(true); 01118 if (q1 > other.q1) return(false); 01119 if (q2 < other.q2) return(true); 01120 if (q2 > other.q2) return(false); 01121 if (m1required && !other.m1required) return(true); 01122 return(false); 01123 } 01124 // member variables 01125 Idx q1; 01126 Idx q2; 01127 bool m1required; 01128 }; 01129 01130 01131 // OmegaSupConProduct(rPlantGen, rCAlph, rSpecGen, rReverseCompositionMap, rResGen) 01132 void OmegaSupConProduct( 01133 const Generator& rPlantGen, 01134 const EventSet& rCAlph, 01135 const Generator& rSpecGen, 01136 std::map< OPSState , Idx>& rProductCompositionMap, 01137 Generator& rResGen) 01138 { 01139 FD_DF("OmegaSupConProduct(" << &rPlantGen << "," << &rSpecGen << ")"); 01140 01141 // prepare result 01142 rResGen.Clear(); 01143 rResGen.InjectAlphabet(rPlantGen.Alphabet()); 01144 01145 // trivial case 01146 if (rPlantGen.InitStatesEmpty()) { 01147 FD_DF("OmegaSupConProduct: plant got no initial states. " 01148 << "parallel composition contains empty language."); 01149 return; 01150 } 01151 if (rSpecGen.InitStatesEmpty()) { 01152 FD_DF("OmegaSupConProduct: spec got no initial states. " 01153 << "parallel composition contains empty language."); 01154 return; 01155 } 01156 01157 // todo stack 01158 std::stack< OPSState > todo; 01159 // current/next state as pair with flag 01160 OPSState currentp, nextp; 01161 // current/next state as target index 01162 Idx currentt, nextt; 01163 TransSet::Iterator ptit, ptit_end, stit, stit_end; 01164 std::map< OPSState, Idx>::iterator rcit; 01165 // critical states 01166 StateSet critical; 01167 // disabled events 01168 EventSet disable; 01169 01170 01171 // push initial state on todo stack 01172 currentp = OPSState(*rPlantGen.InitStatesBegin(), *rSpecGen.InitStatesBegin(), true); 01173 todo.push(currentp); 01174 currentt=rResGen.InsInitState(); 01175 rProductCompositionMap[currentp] = currentt; 01176 01177 // process/feed todo stack 01178 FD_DF("OmegaSupConProduct: processing reachable states:"); 01179 while(!todo.empty()) { 01180 // allow for user interrupt 01181 // LoopCallback(); 01182 // allow for user interrupt, incl progress report 01183 FD_WPC(rProductCompositionMap.size(),rProductCompositionMap.size()+todo.size(),"OmegaSupConProduct(): processing"); 01184 FD_DF("OmegaSupConProduct(): processing" << rProductCompositionMap.size() << " " << todo.size()); 01185 // get next reachable state from todo stack 01186 currentp = todo.top(); 01187 currentt = rProductCompositionMap[currentp]; 01188 todo.pop(); 01189 // skip critical (tmoor 201308) 01190 if(critical.Exists(currentt)) continue; 01191 // report 01192 FD_DF("OmegaSupConProduct: processing (" << currentp.Str() << " -> " << currentt <<")"); 01193 01194 // iterate over transitions, pass1: figure whether current state becomes critical (tmoor 201308) 01195 ptit = rPlantGen.TransRelBegin(currentp.q1); 01196 ptit_end = rPlantGen.TransRelEnd(currentp.q1); 01197 stit = rSpecGen.TransRelBegin(currentp.q2); 01198 stit_end = rSpecGen.TransRelEnd(currentp.q2); 01199 disable.Clear(); 01200 // process all transitions and increment iterators strategically 01201 while((ptit != ptit_end) && (stit != stit_end)) { 01202 FD_DF("OmegaSupConProduct: current plant-transition: " << rPlantGen.TStr(*ptit) ); 01203 FD_DF("OmegaSupConProduct: current spec-transition: " << rSpecGen.TStr(*stit)); 01204 // case A: execute common event 01205 if(ptit->Ev == stit->Ev) { 01206 nextp = OPSState(ptit->X2, stit->X2,currentp.m1required); 01207 if(currentp.m1required) { 01208 if(rPlantGen.ExistsMarkedState(currentp.q1)) nextp.m1required=false; 01209 } else { 01210 if(rSpecGen.ExistsMarkedState(currentp.q2)) nextp.m1required=true; 01211 } 01212 // figure whether successor state is known to be critical 01213 rcit = rProductCompositionMap.find(nextp); 01214 if(rcit != rProductCompositionMap.end()) { 01215 if(critical.Exists(rcit->second)) { 01216 FD_DF("OmegaSupconOmegaParallel: common event " << rSpecGen.EStr(stit->Ev) << " to a critical states"); 01217 // if event is uncontrollable, current state becomes critical 01218 if(!rCAlph.Exists(ptit->Ev)) { 01219 FD_DF("OmegaSupConProduct: critical insert" << currentt); 01220 critical.Insert(currentt); // tmoor 201308 01221 // exit all loops 01222 ptit = ptit_end; 01223 stit = stit_end; 01224 break; 01225 } 01226 // else, event is disabled 01227 disable.Insert(stit->Ev); 01228 } 01229 } 01230 // increment transition 01231 ++ptit; 01232 ++stit; 01233 } 01234 // case B: process plant event that is disabled by the specification 01235 else if (ptit->Ev < stit->Ev) { 01236 FD_DF("SupConProduct: " << rPlantGen.EStr(ptit->Ev) << " is enabled in the plant but disabled in the specification"); 01237 // if the event is uncontrollable, this makes the current state critical 01238 if (!rCAlph.Exists(ptit->Ev)) { 01239 FD_DF("OmegaSupConProduct: disabled event " << rPlantGen.EStr(ptit->Ev) << " is uncontrollable"); 01240 FD_DF("OmegaSupConProduct: critical insert" << currentt); 01241 critical.Insert(currentt); 01242 // exit all loops 01243 ptit = ptit_end; 01244 stit = stit_end; 01245 break; 01246 } 01247 FD_DF("OmegaSupConProduct: incrementing plant transrel"); 01248 ++ptit; 01249 } 01250 // increment titg and titg, case C: process h event that is not enabled for g 01251 else { 01252 FD_DF("OmegaSupConProduct: incrementing spec transrel"); 01253 ++stit; 01254 } 01255 } // end while incrementing 01256 // increment iterators case D: process leftover events of plant 01257 while (ptit != ptit_end) { 01258 FD_DF("OmegaSupConProduct: current g-transition: " << rPlantGen.TStr(*ptit)); 01259 FD_DF("OmegaSupConProduct: current h-transition: end"); 01260 // if uncontrollable event leaves candidate 01261 if (!rCAlph.Exists(ptit->Ev)) { 01262 FD_DF("OmegaSupConProduct: asynchron executed uncontrollable " 01263 << "event " << rPlantGen.EStr(ptit->Ev) << " leaves specification:"); 01264 FD_DF("SupConProduct: critical insert" << rPlantGen.SStr(currentt)); 01265 critical.Insert(currentt); 01266 // exit this loop 01267 break; 01268 } 01269 FD_DF("OmegaSupConProduct: incrementing g transrel"); 01270 ++ptit; 01271 } // end iterating pass1 01272 01273 // skip critical (tmoor 201308) 01274 if(critical.Exists(currentt)) continue; 01275 01276 // iterate over transitions, pass2: execute shared events (tmoor 201308) 01277 FD_DF("OmegaSupConProduct(): processing pass2"); 01278 ptit = rPlantGen.TransRelBegin(currentp.q1); 01279 ptit_end = rPlantGen.TransRelEnd(currentp.q1); 01280 stit = rSpecGen.TransRelBegin(currentp.q2); 01281 stit_end = rSpecGen.TransRelEnd(currentp.q2); 01282 // process all transitions and increment iterators strategically 01283 while((ptit != ptit_end) && (stit != stit_end)) { 01284 FD_DF("OmegaSupConProduct: current plant-transition: " << rPlantGen.TStr(*ptit) ); 01285 FD_DF("OmegaSupConProduct: current spec-transition: " << rSpecGen.TStr(*stit)); 01286 // case A: execute common event 01287 if(ptit->Ev == stit->Ev) { 01288 if(!disable.Exists(stit->Ev)) { 01289 FD_DF("OmegaSupConProduct: executing common event " << rPlantGen.EStr(ptit->Ev)); 01290 nextp = OPSState(ptit->X2, stit->X2,currentp.m1required); 01291 if(currentp.m1required) { 01292 if(rPlantGen.ExistsMarkedState(currentp.q1)) nextp.m1required=false; 01293 } else { 01294 if(rSpecGen.ExistsMarkedState(currentp.q2)) nextp.m1required=true; 01295 } 01296 // figure target index 01297 rcit = rProductCompositionMap.find(nextp); 01298 // if state is new: add to todo list and result 01299 if(rcit == rProductCompositionMap.end()) { 01300 todo.push(nextp); 01301 nextt = rResGen.InsState(); 01302 rProductCompositionMap[nextp] = nextt; 01303 if(!nextp.m1required) 01304 if(rSpecGen.ExistsMarkedState(nextp.q2)) 01305 rResGen.SetMarkedState(nextt); 01306 FD_DF("OmegaSupConProduct: todo push: (" << nextp.Str() << ") -> " << nextt); 01307 } else { 01308 nextt = rcit->second; 01309 } 01310 // set the transition and increment iterators 01311 FD_DF("OmegaSuperParallel: add transition to new generator: " << rResGen.TStr(Transition(currentt, ptit->Ev, nextt))); 01312 rResGen.SetTransition(currentt, ptit->Ev, nextt); 01313 } 01314 // increment transition 01315 ++ptit; 01316 ++stit; 01317 } // end: if processing common event 01318 // case B: process plant event that is disabled by the specification 01319 else if (ptit->Ev < stit->Ev) { 01320 ++ptit; 01321 } 01322 // increment titg and titg, case C: process h event that is not enabled for g 01323 else { 01324 ++stit; 01325 } 01326 } // end while incrementing for pass2 01327 01328 } // while todo 01329 01330 FD_DF("OmegaSupConProduct: deleting critical states: " << critical.ToString()); 01331 rResGen.DelStates(critical); 01332 01333 // restrict composition map 01334 std::map< OPSState , Idx>::iterator cit = rProductCompositionMap.begin(); 01335 while(cit != rProductCompositionMap.end()) 01336 if(!rResGen.ExistsState(cit->second)) rProductCompositionMap.erase(cit++); 01337 else cit++; 01338 01339 } 01340 01341 01342 01343 01344 // OmegaSupConNBUnchecked(rPlantGen, rCAlph, rSpecGen,rResGen) 01345 void OmegaSupConNBUnchecked( 01346 const Generator& rPlantGen, 01347 const EventSet& rCAlph, 01348 const Generator& rSpecGen, 01349 StateSet& rPlantMarking, 01350 Generator& rResGen) 01351 { 01352 FD_DF("OmegaSupConNBUnchecked(\"" << rPlantGen.Name() << "\", \"" << rSpecGen.Name() << "\")"); 01353 01354 // PREPARE RESULT: 01355 Generator* pResGen = &rResGen; 01356 if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) { 01357 pResGen= rResGen.New(); 01358 } 01359 pResGen->Clear(); 01360 pResGen->InjectAlphabet(rPlantGen.Alphabet()); 01361 01362 // controllable events 01363 FD_DF("OmegaSupConNB: controllable events: " << rCAlph.ToString()); 01364 01365 // perform product 01366 std::map< OPSState , Idx> cmap; 01367 OmegaSupConProduct(rPlantGen, rCAlph, rSpecGen, cmap, *pResGen); 01368 01369 // figure plant marking 01370 rPlantMarking.Clear(); 01371 std::map< OPSState, Idx>::iterator pcit; 01372 for(pcit=cmap.begin(); pcit!=cmap.end(); ++pcit) 01373 if(rPlantGen.ExistsMarkedState(pcit->first.q1)) 01374 rPlantMarking.Insert(pcit->second); 01375 01376 // fix statenames (debugging) 01377 #ifdef FAUDES_DEBUG_FUNCTION 01378 std::map< OPSState, Idx>::iterator dcit; 01379 for(dcit=cmap.begin(); dcit!=cmap.end(); ++dcit) { 01380 Idx x1=dcit->first.q1; 01381 Idx x2=dcit->first.q2; 01382 bool m1requ=dcit->first.m1required; 01383 Idx x12=dcit->second; 01384 if(!pResGen->ExistsState(x12)) continue; 01385 std::string name1= rPlantGen.StateName(x1); 01386 if(name1=="") name1=ToStringInteger(x1); 01387 std::string name2= rSpecGen.StateName(x2); 01388 if(name2=="") name1=ToStringInteger(x2); 01389 std::string name12; 01390 if(m1requ) name12= name1 + "|" + name2 + "|r1m"; 01391 else name12= name1 + "|" + name2 + "|r2m"; 01392 name12=pResGen->UniqueStateName(name12); 01393 pResGen->StateName(x12,name12); 01394 } 01395 #endif 01396 01397 #ifdef FAUDES_DEBUG_FUNCTION 01398 pResGen->DWrite(); 01399 pResGen->Write("tmp_syn_xxx_"+pResGen->Name()+".gen"); 01400 pResGen->WriteStateSet(rPlantMarking); 01401 #endif 01402 01403 // iterate for required properties 01404 while(true) { 01405 // catch trivial 01406 if(pResGen->Empty()) break; 01407 // fast inner loop: prefix controllability and omega-trim 01408 while(true) { 01409 Idx count1 = pResGen->Size(); 01410 FD_WARN("OmegaSupConNB: iterate: do prefix con on #" << pResGen->Size()); 01411 SupConClosedUnchecked(rPlantGen, rCAlph, *pResGen); 01412 FD_WARN("OmegaSupConNB: iterate: do coaccessible on #" << pResGen->Size()); 01413 pResGen->Coaccessible(); 01414 FD_WARN("OmegaSupConNB: iterate: do accessible on #" << pResGen->Size()); 01415 pResGen->Accessible(); 01416 FD_WARN("OmegaSupConNB: iterate: do complete on #" << pResGen->Size()); 01417 pResGen->Complete(); 01418 if(pResGen->Size() == count1) break; 01419 if(pResGen->Size() == 0) break; 01420 } 01421 // slow outer loop: controlled liveness aka restrict to controllable prefix 01422 Idx count2 = pResGen->Size(); 01423 FD_WARN("OmegaSupConNB: iterate: do controlled liveness on #" << pResGen->Size()); 01424 OmegaControlledLiveness(*pResGen,rCAlph,rPlantMarking); 01425 if(pResGen->Size() == count2) break; 01426 } 01427 01428 // fix statenames ... 01429 std::map< OPSState, Idx>::iterator rcit; 01430 if(rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && pResGen->StateNamesEnabled()) 01431 for(rcit=cmap.begin(); rcit!=cmap.end(); rcit++) { 01432 Idx x1=rcit->first.q1; 01433 Idx x2=rcit->first.q2; 01434 bool m1requ=rcit->first.m1required; 01435 Idx x12=rcit->second; 01436 if(!pResGen->ExistsState(x12)) continue; 01437 std::string name1= rPlantGen.StateName(x1); 01438 if(name1=="") name1=ToStringInteger(x1); 01439 std::string name2= rSpecGen.StateName(x2); 01440 if(name2=="") name1=ToStringInteger(x2); 01441 std::string name12; 01442 if(m1requ) name12= name1 + "|" + name2 + "|r1m"; 01443 else name12= name1 + "|" + name2 + "|r2m"; 01444 name12=pResGen->UniqueStateName(name12); 01445 pResGen->StateName(x12,name12); 01446 } 01447 01448 // .. or clear them (?) 01449 if(!(rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && pResGen->StateNamesEnabled())) 01450 pResGen->StateNamesEnabled(false); 01451 01452 // copy result 01453 if(pResGen != &rResGen) { 01454 pResGen->Move(rResGen); 01455 delete pResGen; 01456 } 01457 01458 FD_WARN("OmegaSupConNB: return #" << rResGen.Size()); 01459 } 01460 01461 01462 // OmegaSupConNormNBUnchecked(rPlantGen, rCAlph, rOAlph, rSpecGen, rFeedbackMap, rResGen) 01463 void OmegaSupConNormNBUnchecked( 01464 const Generator& rPlantGen, 01465 const EventSet& rCAlph, 01466 const EventSet& rOAlph, 01467 const Generator& rSpecGen, 01468 StateSet& rPlantMarking, 01469 std::map< Idx , Idx >& rObserverStateMap, 01470 std::map< Idx , EventSet>& rFeedbackMap, 01471 Generator& rResGen) 01472 { 01473 FD_WARN("OmegaSupConNormNB(\"" << rPlantGen.Name() << "\", \"" << rSpecGen.Name() << "\")"); 01474 01475 // prepare result 01476 Generator* pResGen = &rResGen; 01477 if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) { 01478 pResGen= rResGen.New(); 01479 } 01480 pResGen->Clear(); 01481 pResGen->InjectAlphabet(rPlantGen.Alphabet()); 01482 01483 // report events 01484 FD_WARN("OmegaSupConNormNB: controllable events: " << rCAlph.ToString()); 01485 FD_WARN("OmegaSupConNormNB: un-observabel events: " << (rPlantGen.Alphabet()-rOAlph).ToString()); 01486 01487 // perform product 01488 std::map< OPSState , Idx> cmap; 01489 OmegaSupConProduct(rPlantGen, rCAlph, rSpecGen, cmap, *pResGen); 01490 pResGen->OmegaTrim(); 01491 01492 // no statenames impülemented 01493 pResGen->StateNamesEnabled(false); 01494 01495 // figure plant marking 01496 rPlantMarking.Clear(); 01497 std::map< OPSState, Idx>::iterator pcit; 01498 for(pcit=cmap.begin(); pcit!=cmap.end(); ++pcit) 01499 if(rPlantGen.ExistsMarkedState(pcit->first.q1)) 01500 rPlantMarking.Insert(pcit->second); 01501 01502 // extend by observer states 01503 Generator obsG= *pResGen; 01504 MarkAllStates(obsG); 01505 Project(obsG,rOAlph,obsG); 01506 InvProject(obsG,pResGen->Alphabet()); 01507 std::map< std::pair<Idx,Idx>, Idx> rObserverCompositionMap; 01508 Product(*pResGen, obsG, rObserverCompositionMap, *pResGen); 01509 // track plantmarking 01510 StateSet fixmarking; 01511 std::map< std::pair<Idx,Idx>, Idx>::iterator cit; 01512 for(cit=rObserverCompositionMap.begin(); cit!=rObserverCompositionMap.end();++cit) 01513 if(rPlantMarking.Exists(cit->first.first)) fixmarking.Insert(cit->second); 01514 rPlantMarking=fixmarking; 01515 // construct reverse map "pResGen.State --> obsG.State" 01516 std::map< std::pair<Idx,Idx>, Idx>::iterator sit; 01517 for(sit=rObserverCompositionMap.begin(); sit!=rObserverCompositionMap.end();++sit) 01518 rObserverStateMap[sit->second]=sit->first.second; 01519 01520 #ifdef FAUDES_DEBUG_FUNCTION 01521 pResGen->DWrite(); 01522 pResGen->Write("tmp_syn_xxx_"+pResGen->Name()+".gen"); 01523 pResGen->WriteStateSet(rPlantMarking); 01524 #endif 01525 01526 FD_WARN("OmegaSupConNormNB(): cand #" << pResGen->Size() << " obs #" << obsG.Size()); 01527 // make resulting generator trim until it's fully controllable 01528 while(true) { 01529 // catch trivial 01530 if(pResGen->Empty()) break; 01531 // fast inner loop: prefix controllability and omega-trim 01532 while(true) { 01533 Idx count1 = pResGen->Size(); 01534 FD_WARN("OmegaSupConNormNB: iterate: do prefix-contr on #" << pResGen->Size()); 01535 SupConClosedUnchecked(rPlantGen, rCAlph, *pResGen); 01536 FD_WARN("OmegaSupConNormNB: iterate: do accessible on #" << pResGen->Size()); 01537 pResGen->Accessible(); 01538 FD_WARN("OmegaSupConNormNB: iterate: do coaccessible on #" << pResGen->Size()); 01539 pResGen->Coaccessible(); 01540 FD_WARN("OmegaSupConNormNB: iterate: do prefix-norm on #" << pResGen->Size()); 01541 SupConNormClosedUnchecked(rPlantGen, rOAlph, rOAlph, obsG, *pResGen); 01542 FD_WARN("OmegaSupConNormNB: iterate: do coaccessible on #" << pResGen->Size()); 01543 pResGen->Coaccessible(); 01544 FD_WARN("OmegaSupConNormNB: iterate: do accessible on #" << pResGen->Size()); 01545 pResGen->Accessible(); 01546 FD_WARN("OmegaSupConNormNB: iterate: do complete on #" << pResGen->Size()); 01547 pResGen->Complete(); 01548 if(pResGen->Size() == count1) break; 01549 if(pResGen->Size() == 0) break; 01550 } 01551 // slow outer loop: controlled liveness 01552 Idx count2 = pResGen->Size(); 01553 FD_WARN("OmegaSupConNormNB: iterate: do controlled liveness on #" << pResGen->Size()); 01554 01555 // cosmetic: restrict observer map and count effective states 01556 std::map< Idx , Idx>::iterator oit = rObserverStateMap.begin(); 01557 while(oit != rObserverStateMap.end()) 01558 if(!pResGen->ExistsState(oit->first)) rObserverStateMap.erase(oit++); 01559 else oit++; 01560 std::set< Idx > ostates; 01561 for(oit = rObserverStateMap.begin(); oit != rObserverStateMap.end(); ++oit) 01562 ostates.insert(oit->second); 01563 01564 //omega controlled liveness aka controllabe prefix 01565 FD_WARN("OmegaSupConNormNB(): cand #" << pResGen->Size() << " obs #" << ostates.size()); 01566 std::map< Idx , EventSet> feedback; 01567 OmegaControlledLiveness(*pResGen,rCAlph,rPlantMarking,rObserverStateMap,feedback); 01568 //OmegaControlledLiveness(*pResGen,rCAlph,rPlantMarking); 01569 if(pResGen->Size() == count2) break; 01570 } 01571 01572 // copy result 01573 if(pResGen != &rResGen) { 01574 pResGen->Move(rResGen); 01575 delete pResGen; 01576 } 01577 } 01578 01579 01580 /* 01581 **************************************** 01582 * SUPCON: WRAPPER / USER FUNCTIONS * 01583 **************************************** 01584 */ 01585 01586 01587 // OmegaSupConNB(rPlantGen, rCAlph, rSpecGen, rResGen) 01588 void OmegaSupConNB( 01589 const Generator& rPlantGen, 01590 const EventSet& rCAlph, 01591 const Generator& rSpecGen, 01592 Generator& rResGen) 01593 { 01594 // consitenct check 01595 ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSpecGen); 01596 // execute 01597 StateSet plantmarking; 01598 OmegaSupConNBUnchecked(rPlantGen, rCAlph, rSpecGen, plantmarking, rResGen); 01599 // record name 01600 rResGen.Name(CollapsString("OmegaSupConNB(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))")); 01601 } 01602 01603 01604 // OmegaSupConNB for Systems: 01605 // uses and maintains controllablity from plant 01606 void OmegaSupConNB( 01607 const System& rPlantGen, 01608 const Generator& rSpecGen, 01609 Generator& rResGen) { 01610 // prepare result 01611 Generator* pResGen = &rResGen; 01612 if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) { 01613 pResGen= rResGen.New(); 01614 } 01615 // execute 01616 OmegaSupConNB(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,*pResGen); 01617 // copy all attributes of input alphabet 01618 pResGen->EventAttributes(rPlantGen.Alphabet()); 01619 // copy result 01620 if(pResGen != &rResGen) { 01621 pResGen->Move(rResGen); 01622 delete pResGen; 01623 } 01624 } 01625 01626 // OmegaConNB(rPlantGen, rCAlph, rSpecGen, rResGen) 01627 void OmegaConNB( 01628 const Generator& rPlantGen, 01629 const EventSet& rCAlph, 01630 const Generator& rSpecGen, 01631 Generator& rResGen) 01632 { 01633 01634 // consitency check 01635 ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSpecGen); 01636 // compute supremal closed-loop behaviour 01637 StateSet plantmarking; 01638 OmegaSupConNBUnchecked(rPlantGen, rCAlph, rSpecGen, plantmarking, rResGen); 01639 // compute restrictive feedback 01640 std::map< Idx , EventSet> feedback; 01641 OmegaControlledLiveness(rResGen, rCAlph, plantmarking, feedback); 01642 // apply restrictive feedback 01643 StateSet::Iterator sit = rResGen.StatesBegin(); 01644 StateSet::Iterator sit_end = rResGen.StatesEnd(); 01645 for(;sit!=sit_end;++sit) { 01646 const EventSet& pattern = feedback[*sit]; 01647 TransSet::Iterator tit = rResGen.TransRelBegin(*sit); 01648 TransSet::Iterator tit_end = rResGen.TransRelEnd(*sit); 01649 while(tit!=tit_end) { 01650 if(pattern.Exists(tit->Ev)) { tit++; continue;}; 01651 rResGen.ClrTransition(tit++); 01652 } 01653 } 01654 // cosmetic trim 01655 rResGen.Trim(); 01656 01657 #ifdef FAUDES_CODE 01658 // during development: test controllability and livenes 01659 if(!IsControllable(rPlantGen,rCAlph,rResGen)) { 01660 throw Exception("OmegaConNB(..)", "ERROR: controllability test failed", 500); 01661 } 01662 if(!IsRelativelyOmegaClosed(rPlantGen,rResGen)) { 01663 throw Exception("OmegaConNB(..)", "ERROR: rel. top. closedness test failed", 500); 01664 } 01665 #endif 01666 01667 // record name 01668 rResGen.Name(CollapsString("OmegaConNB(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))")); 01669 } 01670 01671 // OmegaConNB for Systems: 01672 // uses and maintains controllablity from plant 01673 void OmegaConNB( 01674 const System& rPlantGen, 01675 const Generator& rSpecGen, 01676 Generator& rResGen) { 01677 // prepare result 01678 Generator* pResGen = &rResGen; 01679 if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) { 01680 pResGen= rResGen.New(); 01681 } 01682 // execute 01683 OmegaConNB(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,*pResGen); 01684 // copy all attributes of input alphabet 01685 pResGen->EventAttributes(rPlantGen.Alphabet()); 01686 // copy result 01687 if(pResGen != &rResGen) { 01688 pResGen->Move(rResGen); 01689 delete pResGen; 01690 } 01691 } 01692 01693 01694 // OmegaSupConNormNB(rPlantGen, rCAlph, rOAlph, rSpecGen, rResGen) 01695 void OmegaSupConNormNB( 01696 const Generator& rPlantGen, 01697 const EventSet& rCAlph, 01698 const EventSet& rOAlph, 01699 const Generator& rSpecGen, 01700 Generator& rResGen) 01701 { 01702 // consitenct check 01703 ControlProblemConsistencyCheck(rPlantGen, rCAlph, rOAlph, rSpecGen); 01704 // execute 01705 std::map< Idx , Idx> constates; 01706 std::map< Idx , EventSet> feedback; 01707 StateSet plantmarking; 01708 OmegaSupConNormNBUnchecked(rPlantGen, rCAlph, rOAlph, rSpecGen, plantmarking, constates, feedback, rResGen); 01709 // record name 01710 rResGen.Name(CollapsString("OmegaSupConNormNB(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))")); 01711 } 01712 01713 01714 // OmegaSupConNormNB for Systems: 01715 // uses and maintains controllablity from plant 01716 void OmegaSupConNormNB( 01717 const System& rPlantGen, 01718 const Generator& rSpecGen, 01719 Generator& rResGen) { 01720 // prepare result 01721 Generator* pResGen = &rResGen; 01722 if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) { 01723 pResGen= rResGen.New(); 01724 } 01725 // execute 01726 OmegaSupConNormNB(rPlantGen, rPlantGen.ControllableEvents(),rPlantGen.ObservableEvents(),rSpecGen,*pResGen); 01727 // copy all attributes of input alphabet 01728 pResGen->EventAttributes(rPlantGen.Alphabet()); 01729 // copy result 01730 if(pResGen != &rResGen) { 01731 pResGen->Move(rResGen); 01732 delete pResGen; 01733 } 01734 } 01735 01736 // OmegaConNrmNB(rPlantGen, rCAlph, rOAlph, rSpecGen, rResGen) 01737 void OmegaConNormNB( 01738 const Generator& rPlantGen, 01739 const EventSet& rCAlph, 01740 const EventSet& rOAlph, 01741 const Generator& rSpecGen, 01742 Generator& rResGen) 01743 { 01744 01745 // consitency check 01746 ControlProblemConsistencyCheck(rPlantGen, rCAlph, rOAlph, rSpecGen); 01747 // compute supremal closed-loop behaviour 01748 StateSet plantmarking; 01749 std::map< Idx , Idx> cxmap; 01750 std::map< Idx , EventSet> feedback; 01751 OmegaSupConNormNBUnchecked(rPlantGen, rCAlph, rOAlph, rSpecGen, plantmarking, cxmap, feedback, rResGen); 01752 // compute restrictive feedback 01753 OmegaControlledLiveness(rResGen, rCAlph, plantmarking, cxmap, feedback); 01754 // apply restrictive feedback 01755 StateSet::Iterator sit = rResGen.StatesBegin(); 01756 StateSet::Iterator sit_end = rResGen.StatesEnd(); 01757 for(;sit!=sit_end;++sit) { 01758 // Idx cx = cxmap[*sit]; etc ... 01759 const EventSet& pattern = feedback[*sit]; 01760 TransSet::Iterator tit = rResGen.TransRelBegin(*sit); 01761 TransSet::Iterator tit_end = rResGen.TransRelEnd(*sit); 01762 while(tit!=tit_end) { 01763 if(pattern.Exists(tit->Ev)) { tit++; continue;}; 01764 rResGen.ClrTransition(tit++); 01765 } 01766 } 01767 // trim (?) 01768 rResGen.OmegaTrim(); 01769 //#ifdef FAUDES_CODE 01770 // during development: test controllability, normality and livenes 01771 if(!IsControllable(rPlantGen,rCAlph,rResGen)) { 01772 throw Exception("OmegaConNormNB(..)", "ERROR: controllability test failed", 500); 01773 } 01774 if(!IsRelativelyOmegaClosed(rPlantGen,rResGen)) { 01775 throw Exception("OmegaConNormNB(..)", "ERROR: rel. top. closedness test failed", 500); 01776 } 01777 Generator prK=rResGen; 01778 MarkAllStates(prK); 01779 Generator prL=rPlantGen; 01780 prL.Trim(); 01781 MarkAllStates(prL); 01782 if(!IsNormal(prL,rOAlph,prK)){ 01783 throw Exception("OmegaConNormNB(..)", "ERROR: prefix normality test failed", 500); 01784 } 01785 //#endif 01786 01787 // record name 01788 rResGen.Name(CollapsString("OmegaConNormNB(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))")); 01789 } 01790 01791 // OmegaConNormNB for Systems 01792 // uses and maintains controllablity from plant 01793 void OmegaConNormNB( 01794 const System& rPlantGen, 01795 const Generator& rSpecGen, 01796 Generator& rResGen) { 01797 // prepare result 01798 Generator* pResGen = &rResGen; 01799 if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) { 01800 pResGen= rResGen.New(); 01801 } 01802 // execute 01803 OmegaConNormNB(rPlantGen, rPlantGen.ControllableEvents(),rPlantGen.ObservableEvents(), rSpecGen,*pResGen); 01804 // copy all attributes of input alphabet 01805 pResGen->EventAttributes(rPlantGen.Alphabet()); 01806 // copy result 01807 if(pResGen != &rResGen) { 01808 pResGen->Move(rResGen); 01809 delete pResGen; 01810 } 01811 } 01812 01813 01814 01815 } // name space libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen |