About
User Reference
C++ API
luafaudes
Developer
Links
libFAUDES online
libFAUDES

Sections

Index

syn_supcon.cpp

Go to the documentation of this file.
00001 /** @file syn_supcon.cpp Supremal controllable sublanguage */
00002 
00003 /* FAU Discrete Event Systems Library (libfaudes)
00004 
00005    Copyright (C) 2006  Bernd Opitz
00006    Exclusive copyright is granted to Klaus Schmidt
00007 
00008    This library is free software; you can redistribute it and/or
00009    modify it under the terms of the GNU Lesser General Public
00010    License as published by the Free Software Foundation; either
00011    version 2.1 of the License, or (at your option) any later version.
00012 
00013    This library is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016    Lesser General Public License for more details.
00017 
00018    You should have received a copy of the GNU Lesser General Public
00019    License along with this library; if not, write to the Free Software
00020    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00021    
00022 
00023 #include "syn_supcon.h"
00024 
00025 
00026 namespace faudes {
00027 
00028 
00029 
00030 
00031 /*
00032 ***************************************************************************************
00033 ***************************************************************************************
00034  Implementation
00035 ***************************************************************************************
00036 ***************************************************************************************
00037 */
00038 
00039 
00040 /*
00041 Revision fro libFAUDES 2.20b:
00042 
00043 SupCon and IsControllable used to share the same algorithm to identify critical
00044 states, implemented as IsControllableUnchecked().
00045 
00046 The implementation, however, was only correct under the assumption that the state set of the 
00047 supervisor/candidate H would also distinguish plant states. The later assumption is
00048 true in the context of SupCon, where the candidate is built as the parallel composition. 
00049 It is not true in general.
00050 
00051 Thus, in libFAUDES 2.20b the original algorithm was moved from  IsControllableUnchecked to
00052 SupConUnchecked and IsControllableUnchecked was reimplemented.
00053 */
00054 
00055 
00056 // SupConUnchecked(rPlantGen, rCAlph, rSupCandGen)
00057 void SupConUnchecked(
00058   const Generator& rPlantGen,  // aka G
00059   const EventSet& rCAlph,  
00060   Generator& rSupCandGen // aka H
00061 ) 
00062 {
00063   FD_DF("SupConUnchecked(" << &rSupCandGen << "," << &rPlantGen << ")");
00064 
00065   // bail out if plant or candidate contain no initial states
00066   if(rPlantGen.InitStatesEmpty() || rSupCandGen.InitStatesEmpty()) 
00067     return;
00068    
00069   // todo stack (pairs of states)
00070   std::stack<Idx> todog, todoh;
00071   // set of already processed states of H (this is where we need H-states to also distinguish G-states) 
00072   StateSet processed;
00073   // reverse sorted transition relation of H (to be built on the fly)
00074   TransSetX2EvX1 rtransrel;
00075   // critical states
00076   StateSet critical;
00077 
00078   // push combined initial state on todo stack
00079   todog.push(*rPlantGen.InitStatesBegin());
00080   todoh.push(*rSupCandGen.InitStatesBegin());
00081   FD_DF("SupCon: todo push: (" << rPlantGen.SStr(*rPlantGen.InitStatesBegin()) << "|"
00082      << rSupCandGen.SStr(*rSupCandGen.InitStatesBegin()) << ")");
00083 
00084   // process todo stack
00085   while (! todog.empty()) {
00086     // allow for user interrupt
00087     // LoopCallback();
00088     // allow for user interrupt, incl progress report
00089     FD_WPC(1,2,"Controllability(): iterating states"); 
00090     // get top element from todo stack
00091     Idx currentg = todog.top();
00092     Idx currenth = todoh.top();
00093     todog.pop();
00094     todoh.pop();
00095     FD_DF("SupCon: todo pop: (" << rPlantGen.SStr(currentg) << "|" 
00096        << rSupCandGen.SStr(currenth) << ")");
00097 
00098     // break on doublets (tmoor 201104)
00099     if(processed.Exists(currenth)) continue;
00100 
00101 #ifdef FAUDES_DEBUG_FUNCTION
00102     TransSet::Iterator _titg, _tith;
00103     // print all transitions of current states
00104     FD_DF("SupCon: transitions from current states:");
00105     for (_titg = rPlantGen.TransRelBegin(currentg); _titg != rPlantGen.TransRelEnd(currentg); ++_titg) 
00106        FD_DF("SupCon: g: " << rPlantGen.SStr(_titg->X1) << "-" 
00107      << rPlantGen.EStr(_titg->Ev) << "-" << rPlantGen.SStr(_titg->X2));
00108     for (_tith = rSupCandGen.TransRelBegin(currenth); _tith != rSupCandGen.TransRelEnd(currenth); ++_tith) 
00109        FD_DF("SupCon: h: " << rSupCandGen.SStr(_tith->X1) << "-" 
00110      << rSupCandGen.EStr(_tith->Ev) << "-" << rSupCandGen.SStr(_tith->X2));
00111 #endif 
00112 
00113     // process all h transitions while there could be matching g transitions
00114     TransSet::Iterator titg = rPlantGen.TransRelBegin(currentg);
00115     TransSet::Iterator titg_end = rPlantGen.TransRelEnd(currentg);
00116     TransSet::Iterator tith = rSupCandGen.TransRelBegin(currenth);
00117     TransSet::Iterator tith_end = rSupCandGen.TransRelEnd(currenth);
00118     while ((tith != tith_end) && (titg != titg_end)) {
00119       FD_DF("SupCon: processing g-transition: " << rPlantGen.SStr(titg->X1) 
00120       << "-" << rPlantGen.EStr(titg->Ev) << "-" << rPlantGen.SStr(titg->X2));
00121       FD_DF("SupCon: processing h-transition: " << rSupCandGen.SStr(tith->X1) 
00122             << "-" << rSupCandGen.EStr(tith->Ev) << "-" << rSupCandGen.SStr(tith->X2));
00123       // increment tith and titg case A: process common events
00124       if (titg->Ev == tith->Ev) {
00125   FD_DF("SupCon: processing common event " << rPlantGen.EStr(titg->Ev));
00126   // add to todo list if state not processed (tmoor 201104: record next H state on stack)
00127   if(!processed.Exists(tith->X2)) {
00128     todog.push(titg->X2);
00129     todoh.push(tith->X2);
00130     FD_DF("SupCon: todo push: (" << rPlantGen.SStr(titg->X2) << "|"
00131       << rSupCandGen.SStr(tith->X2) << ")");
00132   }
00133   // if h successor state is not critical add transition to rtransrel
00134   if (!critical.Exists(tith->X2)) {
00135     rtransrel.Insert(*tith);
00136     FD_DF("SupCon: incrementing g and h transrel");
00137     ++titg;
00138     ++tith;
00139   }
00140   // if successor state is critical and event uncontrollable 
00141   else if (!rCAlph.Exists(titg->Ev)) {
00142     FD_DF("SupCon: successor state " << rSupCandGen.SStr(tith->X2) << 
00143       " critical and event " << rPlantGen.EStr(titg->Ev) << " uncontrollable:");
00144     FD_DF("SupCon: TraverseUncontrollableBackwards(" << rSupCandGen.SStr(currenth) << ")");
00145       TraverseUncontrollableBackwards(rCAlph, rtransrel, critical, currenth);
00146 #ifdef FAUDES_CHECKED
00147       // just increment transrel iterators to find all h transitions not in g
00148       FD_DF("IsControllable: incrementing g an h transrel (FAUDES_CHECKED)");
00149       ++titg;
00150       ++tith;
00151       break;
00152 #else
00153             // exit all loops
00154       titg = titg_end;
00155       tith = tith_end;
00156       break;
00157 #endif
00158   }
00159         // if successor state is critical and event controllable
00160         else {
00161           FD_DF("SupCon: incrementing g and h transrel");
00162           ++titg;
00163           ++tith;
00164         }   
00165       }
00166       // increment tith and titg case B: process g event that is not enabled in h
00167       else if (titg->Ev < tith->Ev) {
00168   FD_DF("SupCon: asynchronous execution of event " 
00169            << rPlantGen.EStr(titg->Ev) << " in g while " << rSupCandGen.EStr(tith->Ev)
00170      << " in h");
00171         // if uncontrollable transition violates specification
00172         // delete state from rResGen and put into criticalset
00173         if (!rCAlph.Exists(titg->Ev)) {
00174     FD_DF("SupCon: asynchronous event " << rPlantGen.EStr(titg->Ev) 
00175          << " in g is uncontrollable");
00176     FD_DF("SupCon: TraverseUncontrollableBackwards(" << rSupCandGen.SStr(currenth) << ")");
00177     TraverseUncontrollableBackwards(rCAlph, rtransrel, critical, currenth);
00178     // exit all loops over g transrel
00179     titg = titg_end;
00180     break;
00181         }
00182   FD_DF("SupCon: incrementing g transrel");
00183   ++titg;
00184       }
00185       // increment tith and titg case C: process h event that is not enabled in g
00186       else {
00187        // #ifdef FAUDES_CHECKED
00188        // FD_WARN("SupCon: transition " << rSupCandGen.TStr(*tith) 
00189        //  << " in specification h not found in g");
00190        // #endif
00191        FD_DF("SupCon: incrementing h transrel");
00192        ++tith;
00193       }
00194     } // end while tith and titg
00195     // increment tith and titg case D: process leftover g events 
00196     while (titg != titg_end) {
00197       FD_DF("SupCon: asynchronous execution of event " 
00198           << rPlantGen.EStr(titg->Ev) << " in g at end of h");
00199       FD_DF("SupCon: actual g-transition: " << rPlantGen.SStr(titg->X1) 
00200     << "-" << rPlantGen.EStr(titg->Ev) << "-" << rPlantGen.SStr(titg->X2));
00201       FD_DF("SupCon: actual h-transition: end");
00202       // if uncontrollable transition violates specification
00203       if (!rCAlph.Exists(titg->Ev)) {
00204   FD_DF("SupCon: asynchronous execution of uncontrollable event "
00205       << rPlantGen.EStr(titg->Ev) << " in g");
00206   FD_DF("SupCon: TraverseUncontrollableBackwards(" << rPlantGen.SStr(currenth) << ")");
00207         TraverseUncontrollableBackwards(rCAlph, rtransrel, critical, currenth);
00208   // exit this loop
00209   break;
00210       }
00211       FD_DF("SupCon: incrementing g transrel");
00212       ++titg;
00213     }
00214     //#ifdef FAUDES_CHECKED
00215     // increment tith and titg case E: process leftover h events 
00216     //while (tith != tith_end) {
00217     //  FD_WARN("SupCon: transition " << rSupCandGen.TStr(*tith) << " in specification h not found in g");
00218     //  FD_DF("SupCon: incrementing h transrel");
00219     //  ++tith;
00220     //}
00221     //#endif
00222     processed.Insert(currenth);
00223   } //end while todog
00224 
00225   // remove all states that have been identified as critical or that have
00226   // been not processed
00227   critical = rSupCandGen.States() - ( processed - critical );
00228   rSupCandGen.DelStates(critical);
00229 }
00230 
00231 
00232 
00233 /*
00234 Revision fro libFAUDES 2.20b:
00235 
00236 The re-implemented version will only report states as critical 
00237 if they disable an uncontrollable plant event. No reverse
00238 search is performed.
00239 */
00240 
00241 
00242 // IsControllableUnchecked(rPlantGen, rCAlph, rSupCandGen, rCriticalStates)
00243 bool IsControllableUnchecked(
00244   const Generator& rPlantGen,
00245   const EventSet& rCAlph,  
00246   const Generator& rSupCandGen, 
00247   StateSet& rCriticalStates) 
00248 {
00249   FD_DF("IsControllableUnchecked(" << &rSupCandGen << "," << &rPlantGen << ")");
00250 
00251   // todo stack
00252   std::stack< std::pair<Idx,Idx> > todo;
00253   // set of already processed states
00254   std::set< std::pair<Idx,Idx> > processed;
00255 
00256   // PREPARE RESULT:
00257   rCriticalStates.Clear();
00258   rCriticalStates.Name("CriticalStates");
00259 
00260   // return true (controllable) if there is no initial state
00261   if(rPlantGen.InitStatesEmpty() || rSupCandGen.InitStatesEmpty()) 
00262     return true;
00263 
00264   // push combined initial state on todo stack
00265   todo.push( std::make_pair(*rPlantGen.InitStatesBegin(),*rSupCandGen.InitStatesBegin()) );
00266   FD_DF("IsControllable: todo push: (" << rPlantGen.SStr(*rPlantGen.InitStatesBegin()) << "|"
00267      << rSupCandGen.SStr(*rSupCandGen.InitStatesBegin()) << ")");
00268 
00269   // process todo stack
00270   while (! todo.empty()) {
00271     // allow for user interrupt
00272     // LoopCallback();
00273     // allow for user interrupt, incl progress report
00274     FD_WPC(1,2,"Controllability(): iterating states"); 
00275     // get top element from todo stack
00276     std::pair<Idx,Idx> current = todo.top(); todo.pop();
00277     processed.insert(current);
00278     Idx currentg = current.first;
00279     Idx currenth = current.second;
00280     FD_DF("IsControllable: todo pop: (" << rPlantGen.SStr(currentg) << "|" 
00281        << rSupCandGen.SStr(currenth) << ")");
00282 
00283 #ifdef FAUDES_DEBUG_FUNCTION
00284     TransSet::Iterator _titg, _tith;
00285     // print all transitions of current states
00286     FD_DF("IsControllable: transitions from current states:");
00287     for (_titg = rPlantGen.TransRelBegin(currentg); _titg != rPlantGen.TransRelEnd(currentg); ++_titg) 
00288        FD_DF("IsControllable: g: " << rPlantGen.SStr(_titg->X1) << "-" 
00289      << rPlantGen.EStr(_titg->Ev) << "-" << rPlantGen.SStr(_titg->X2));
00290     for (_tith = rSupCandGen.TransRelBegin(currenth); _tith != rSupCandGen.TransRelEnd(currenth); ++_tith) 
00291        FD_DF("IsControllable: h: " << rSupCandGen.SStr(_tith->X1) << "-" 
00292      << rSupCandGen.EStr(_tith->Ev) << "-" << rSupCandGen.SStr(_tith->X2));
00293 #endif 
00294 
00295     // process all h transitions while there could be matching g transitions
00296     TransSet::Iterator titg = rPlantGen.TransRelBegin(currentg);
00297     TransSet::Iterator titg_end = rPlantGen.TransRelEnd(currentg);
00298     TransSet::Iterator tith = rSupCandGen.TransRelBegin(currenth);
00299     TransSet::Iterator tith_end = rSupCandGen.TransRelEnd(currenth);
00300     while ((tith != tith_end) && (titg != titg_end)) {
00301       FD_DF("IsControllable: processing g-transition: " << rPlantGen.SStr(titg->X1) 
00302       << "-" << rPlantGen.EStr(titg->Ev) << "-" << rPlantGen.SStr(titg->X2));
00303       FD_DF("IsControllable: processing h-transition: " << rSupCandGen.SStr(tith->X1) 
00304             << "-" << rSupCandGen.EStr(tith->Ev) << "-" << rSupCandGen.SStr(tith->X2));
00305       // increment tith and titg case A: process common events
00306       if (titg->Ev == tith->Ev) {
00307   FD_DF("IsControllable: processing common event " << rPlantGen.EStr(titg->Ev));
00308         // form next state and add to stack
00309         std::pair<Idx,Idx> next = std::make_pair(titg->X2,tith->X2);       
00310   // add to todo list if not processed so far 
00311       if(processed.find(next)==processed.end()) {
00312     FD_DF("IsControllable: todo push: (" << rPlantGen.SStr(titg->X2) << "|"
00313       << rSupCandGen.SStr(tith->X2) << ")");
00314           todo.push(next);
00315   }
00316         // proceed
00317   ++titg;
00318   ++tith;
00319       }
00320       // increment tith and titg case B: process g event that is not enabled in h
00321       else if (titg->Ev < tith->Ev) {
00322   FD_DF("IsControllable: asynchronous execution of event " 
00323            << rPlantGen.EStr(titg->Ev) << " in g while " << rSupCandGen.EStr(tith->Ev)
00324      << " in h");
00325         // if uncontrollable transition violates specification
00326         // record that state as critical
00327         if (!rCAlph.Exists(titg->Ev)) {
00328     FD_DF("IsControllable: asynchronous event " << rPlantGen.EStr(titg->Ev) 
00329          << " in g is uncontrollable");
00330     FD_DF("IsControllable: TraverseUncontrollableBackwards(" << rSupCandGen.SStr(currenth) << ")");
00331     rCriticalStates.Insert(currenth);
00332     // exit all loops over g transrel
00333     titg = titg_end;
00334     break;
00335         }
00336   FD_DF("IsControllable: incrementing g transrel");
00337   ++titg;
00338       }
00339       // increment tith and titg case C: process h event that is not enabled in g
00340       else {
00341        // #ifdef FAUDES_CHECKED
00342        // FD_WARN("IsControllable: transition " << rSupCandGen.TStr(*tith) 
00343        //  << " in specification h not found in g");
00344        // #endif
00345        FD_DF("IsControllable: incrementing h transrel");
00346        ++tith;
00347       }
00348     } // end while tith and titg
00349     // increment tith and titg case D: process leftover g events 
00350     while (titg != titg_end) {
00351       FD_DF("IsControllable: asynchronous execution of event " 
00352           << rPlantGen.EStr(titg->Ev) << " in g at end of h");
00353       FD_DF("IsControllable: actual g-transition: " << rPlantGen.SStr(titg->X1) 
00354     << "-" << rPlantGen.EStr(titg->Ev) << "-" << rPlantGen.SStr(titg->X2));
00355       FD_DF("IsControllable: actual h-transition: end");
00356       // if uncontrollable transition violates specification
00357       if (!rCAlph.Exists(titg->Ev)) {
00358   FD_DF("IsControllable: asynchronous execution of uncontrollable event "
00359       << rPlantGen.EStr(titg->Ev) << " in g");
00360   FD_DF("IsControllable: TraverseUncontrollableBackwards(" << rPlantGen.SStr(currenth) << ")");
00361   rCriticalStates.Insert(currenth);
00362   // exit this loop
00363   break;
00364       }
00365       FD_DF("IsControllable: incrementing g transrel");
00366       ++titg;
00367     }
00368     //#ifdef FAUDES_CHECKED
00369     // increment tith and titg case E: process leftover h events 
00370     //while (tith != tith_end) {
00371     //  FD_WARN("IsControllable: transition " << rSupCandGen.TStr(*tith) << " in specification h not found in g");
00372     //  FD_DF("IsControllable: incrementing h transrel");
00373     //  ++tith;
00374     //}
00375     //#endif
00376   } //end while todo
00377 
00378 
00379   // return identified critical states
00380   return rCriticalStates.Empty();
00381 }
00382 
00383 
00384 
00385 
00386 
00387 // SupconParallel(rPlantGen, rCAlph, rSpecGen, rReverseCompositionMap, rResGen)
00388 void SupconParallel(
00389   const Generator& rPlantGen, 
00390   const EventSet& rCAlph,
00391   const Generator& rSpecGen,
00392   std::map< std::pair<Idx,Idx>, Idx>& rReverseCompositionMap, 
00393   Generator& rResGen) 
00394 {
00395   FD_DF("SupconParallel(" << &rPlantGen << "," << &rSpecGen << ")");
00396   
00397   // HELPERS:
00398 
00399   // todo stack
00400   std::stack< std::pair<Idx,Idx> > todo;
00401   // set of critical states
00402   StateSet critical;
00403   // actual pair, new pair
00404   std::pair<Idx,Idx> currentstates, newstates;
00405   // other stuff
00406   Idx tmpstate;
00407   std::map< std::pair<Idx,Idx>, Idx>::iterator rcmapit;
00408   StateSet::Iterator lit1, lit2;
00409   TransSet::Iterator titg, titg_end, tith, tith_end;
00410 
00411   // prepare
00412   rResGen.ClearStates();
00413 
00414   // ALGORITHM:
00415   
00416   if (rPlantGen.InitStatesEmpty()) {
00417     FD_DF("SupconParallel: plant got no initial states. "
00418             << "parallel composition contains empty language.");
00419     return;
00420   }
00421   if (rSpecGen.InitStatesEmpty()) {
00422     FD_DF("SupconParallel: spec got no initial states. "
00423               << "parallel composition contains empty language.");
00424     return;
00425   }
00426 
00427   // create initial state
00428   currentstates = std::make_pair(*rPlantGen.InitStatesBegin(), *rSpecGen.InitStatesBegin());
00429   todo.push(currentstates);
00430   rReverseCompositionMap[currentstates] = rResGen.InsInitState();
00431   FD_DF("SupconParallel: NEW ISTATE: (" << rPlantGen.SStr(currentstates.first) 
00432       << "|" << rSpecGen.SStr(currentstates.second) << ") -> " 
00433                   << rReverseCompositionMap[currentstates]);
00434   if (rPlantGen.ExistsMarkedState(*rPlantGen.InitStatesBegin()) 
00435                 && rSpecGen.ExistsMarkedState(*rSpecGen.InitStatesBegin())) {
00436     rResGen.SetMarkedState(rReverseCompositionMap[currentstates]);
00437      FD_DF("SupconParallel: recent ISTATE Marked");
00438   }
00439 
00440   // do parallel composition of allowed states by deleting critical states on the fly.
00441   // this creates an accessible generator
00442   FD_DF("SupconParallel: *** processing reachable states ***");
00443   while (! todo.empty()) {
00444     // allow for user interrupt
00445     // LoopCallback();
00446     // allow for user interrupt, incl progress report
00447     FD_WPC(rReverseCompositionMap.size(),rReverseCompositionMap.size()+todo.size(),"SupconParallel(): processing"); 
00448     // get next reachable pair of states from todo stack
00449     currentstates = todo.top();
00450     todo.pop();
00451     FD_DF("SupconParallel: todo pop: (" << rPlantGen.SStr(currentstates.first) 
00452          << "|" << rSpecGen.SStr(currentstates.second) << ") -> " 
00453                << rReverseCompositionMap[currentstates]);
00454     
00455     titg = rPlantGen.TransRelBegin(currentstates.first);
00456     titg_end = rPlantGen.TransRelEnd(currentstates.first);
00457     tith = rSpecGen.TransRelBegin(currentstates.second);
00458     tith_end = rSpecGen.TransRelEnd(currentstates.second);
00459 
00460 #ifdef FAUDES_DEBUG_FUNCTION
00461     // print all transitions of current states
00462     FD_DF("SupConParallel: transitions from current states:");
00463     for (;titg != titg_end; ++titg) { 
00464       FD_DF("SupConParallel: g: " << rPlantGen.SStr(titg->X1) << "-" << rPlantGen.EStr(titg->Ev) 
00465          << "-" << rPlantGen.SStr(titg->X2));
00466     }
00467     for (;tith != tith_end; ++tith) {
00468       FD_DF("SupConParallel: h: " << rSpecGen.SStr(tith->X1) << "-" << rSpecGen.EStr(tith->Ev) 
00469           << "-" << rSpecGen.SStr(tith->X2));
00470     }
00471     titg = rPlantGen.TransRelBegin(currentstates.first);
00472     tith = rSpecGen.TransRelBegin(currentstates.second);
00473 #endif                                                                      
00474 
00475     // process all h transitions while there could be matching g transitions
00476     while ((tith != tith_end) && (titg != titg_end)) {
00477       FD_DF("SupconParallel: current g-transition: " << rPlantGen.TStr(*titg) );
00478       FD_DF("SupconParallel: actual h-transition: " << rSpecGen.TStr(*tith));
00479       // increment titg and titg, case A: execute common events
00480       if (titg->Ev == tith->Ev) {
00481   FD_DF("SupconParallel: executing common event "  << rPlantGen.EStr(titg->Ev));
00482   newstates = std::make_pair(titg->X2, tith->X2);
00483   rcmapit = rReverseCompositionMap.find(newstates);
00484   // if state is new: add to todo list and result
00485   if (rcmapit == rReverseCompositionMap.end()) {
00486     todo.push(newstates);
00487     // if marked 
00488     if (rPlantGen.ExistsMarkedState(newstates.first) && 
00489     rSpecGen.ExistsMarkedState(newstates.second)) {
00490       tmpstate = rResGen.InsMarkedState();
00491       FD_DF("SupconParallel: NEW MSTATE: (" << rPlantGen.SStr(newstates.first) << "|"
00492          << rSpecGen.SStr(newstates.second) << ") -> " << tmpstate);
00493     }
00494     // if not maked 
00495     else {
00496       tmpstate = rResGen.InsState();
00497       FD_DF("SupconParallel: NEW STATE: (" << rPlantGen.SStr(newstates.first) << "|" 
00498                << rSpecGen.SStr(newstates.second) << ") -> " << tmpstate);
00499     }
00500     rReverseCompositionMap[newstates] = tmpstate;
00501     FD_DF("SupconParallel: todo push: (" << rPlantGen.SStr(newstates.first)
00502        << "|" << rSpecGen.SStr(newstates.second) << ") -> " << tmpstate);
00503   }
00504   // if state already exists
00505   else {
00506     tmpstate = rcmapit->second;
00507   }
00508   // if successor state is not critical add transition and increment titg and tith
00509   if (! critical.Exists(tmpstate)) {
00510     FD_DF("SupconParallel: ADDING TRANSITION " 
00511        << rPlantGen.SStr(rReverseCompositionMap[currentstates]) << "-" << rPlantGen.EStr(titg->Ev) 
00512        << "-" << rPlantGen.SStr(tmpstate));
00513     rResGen.SetTransition(rReverseCompositionMap[currentstates], titg->Ev, tmpstate);
00514     FD_DF("SupconParallel: incrementing g and h transrel");
00515     ++titg;
00516     ++tith;
00517   }
00518   // if successor state is critical and event is uncontrollable then delete current state 
00519   else if (!rCAlph.Exists(titg->Ev)) {
00520     FD_DF("SupconParallel: successor " << rSpecGen.SStr(tmpstate) 
00521            << "in critical and common event " << rSpecGen.EStr(titg->Ev) 
00522            << " uncontrollable:");
00523     FD_DF("SupconParallel: critical insert" << rPlantGen.SStr(tmpstate));
00524     critical.Insert(tmpstate);
00525 #ifdef FAUDES_CHECKED
00526     // do not end while loops here for detecting all h transitions 
00527     // not in g
00528     FD_DF("SupconParallel: incrementing g and h transrel (FAUDES_CHECKED)");
00529     ++titg;
00530     ++tith;
00531 #else
00532     // exit all loops
00533     titg = titg_end;
00534     tith = tith_end;
00535 #endif
00536         }
00537         // else if successor state in critical and event controllable increment titg and tith
00538         else {
00539     FD_DF("SupconParallel: incrementing g and h transrel");
00540           ++titg;
00541           ++tith;
00542         }
00543       } // end: if processing common event 
00544       // increment titg and titg, case B: process g event that is not enebled for h
00545       else if (titg->Ev < tith->Ev) {
00546   FD_DF("SupconParallel: asynchronous execution of event " 
00547      << rPlantGen.EStr(titg->Ev) << " in g while " << rSpecGen.EStr(tith->Ev) << " in h");
00548   // if uncontrollable transition leaves specification
00549   // delete state from res and put into criticalset
00550   if (!rCAlph.Exists(titg->Ev)) {
00551     FD_DF("SupconParallel: asynchronous event " << rPlantGen.EStr(titg->Ev) 
00552        << " in g is uncontrollable");
00553     tmpstate = rReverseCompositionMap[currentstates]; 
00554     FD_DF("SupconParallel: critical insert" << rPlantGen.SStr(tmpstate));
00555     critical.Insert(tmpstate);
00556     // exit all loops
00557     titg = titg_end;
00558     tith = tith_end;
00559     break;
00560   }
00561   FD_DF("SupconParallel: incrementing g transrel");
00562   ++titg;
00563       } 
00564       // increment titg and titg, case C: process h event that is not enabled for g
00565       else {
00566   //#ifdef FAUDES_CHECKED
00567   // FD_WARN("SupconParallel:  transition " << rSpecGen.TStr(*tith) << " in specification h not found in g");
00568   //#endif
00569   FD_DF("SupconParallel: incrementing h transrel");
00570   ++tith;
00571       }
00572     } // end while incrementing tith and titg 
00573     // increment titg and titg, case D: process leftover events of g
00574     while (titg != titg_end) {
00575       FD_DF("SupconParallel: asynchronous execution of event " 
00576          << rPlantGen.EStr(titg->Ev) << " in g at end of h");
00577       FD_DF("SupconParallel: actual g-transition: " << rPlantGen.SStr(titg->X1) 
00578          << "-" << rPlantGen.EStr(titg->Ev) << "-" << rPlantGen.SStr(titg->X2));
00579       FD_DF("SupconParallel: actual h-transition: end");
00580       // if uncontrollable transition leaves specification
00581       if (!rCAlph.Exists(titg->Ev)) {
00582   tmpstate = rReverseCompositionMap[currentstates];
00583   FD_DF("SupconParallel: asynchron executed uncontrollable end "
00584            << "event " << rPlantGen.EStr(titg->Ev) << " leaves specification:");
00585   FD_DF("SupconParallel: critical insert" << rPlantGen.SStr(tmpstate));
00586   critical.Insert(tmpstate);
00587   // exit this loop 
00588   break;
00589       }
00590       FD_DF("SupconParallel: incrementing g transrel");
00591       ++titg;
00592     }
00593     //#ifdef FAUDES_CHECKED
00594     // increment titg and titg, case E: process leftover events of h
00595     //while (txoith != tith_end) {
00596     //  FD_WARN("SupconParallel:  transition " << rSpecGen.TStr(*tith)  << " in specification h not found in g");
00597     //  FD_DF("SupconParallel: incrementing h transrel");
00598     //  ++tith;
00599     //}
00600     //#endif
00601   } // while todo
00602   FD_DF("SupconParallel: deleting critical states...");
00603   StateSet::Iterator sit;
00604   for(sit = critical.Begin(); sit!= critical.End(); ++sit)
00605      rResGen.DelState(*sit); 
00606   //rResGen.DelStates(critical);
00607 }
00608 
00609 
00610 
00611 // SupConNBUnchecked(rPlantGen, rCAlph, rSpecGen, rReverseCompositionMap, rResGen)
00612 void SupConNBUnchecked(
00613   const Generator& rPlantGen,
00614   const EventSet& rCAlph,  
00615   const Generator& rSpecGen,
00616   std::map< std::pair<Idx,Idx>, Idx>& rReverseCompositionMap, 
00617   Generator& rResGen) 
00618 {
00619   FD_DF("SupConNB(" << &rPlantGen << "," << &rSpecGen << ")");
00620 
00621   // PREPARE RESULT:  
00622   Generator* pResGen = &rResGen;
00623   if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
00624     pResGen= rResGen.New();
00625   }
00626   pResGen->Clear();
00627   pResGen->Name(CollapsString("SupConNB(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
00628   pResGen->InjectAlphabet(rPlantGen.Alphabet());
00629 
00630   // controllable events
00631   FD_DF("SupConNB: controllable events: "   << rCAlph.ToString());
00632 
00633   // ALGORITHM:
00634   SupconParallel(rPlantGen, rCAlph, rSpecGen, rReverseCompositionMap, *pResGen);
00635 
00636   // make resulting generator trim until it's fully controllable
00637   while (1) {
00638     if(pResGen->Empty()) break;
00639     Idx state_num = pResGen->Size();
00640     SupConUnchecked(rPlantGen, rCAlph, *pResGen);
00641     pResGen->Trim();
00642     if(pResGen->Size() == state_num) break;
00643   }
00644 
00645   // convenience state names
00646   if(rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && rResGen.StateNamesEnabled()) 
00647     SetComposedStateNames(rPlantGen, rSpecGen, rReverseCompositionMap, *pResGen);
00648   else
00649     pResGen->ClearStateNames();
00650 
00651   // copy result
00652   if(pResGen != &rResGen) {
00653     pResGen->Move(rResGen);
00654     delete pResGen;
00655   }
00656 
00657 }
00658 
00659 // ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSpecGen)
00660 void ControlProblemConsistencyCheck(
00661   const Generator& rPlantGen,
00662   const EventSet& rCAlph, 
00663   const Generator& rSpecGen) 
00664 {
00665 
00666   // alphabets must match
00667   if ( rPlantGen.Alphabet() != rSpecGen.Alphabet()) {
00668     EventSet only_in_plant = rPlantGen.Alphabet() - rSpecGen.Alphabet();
00669     EventSet only_in_spec = rSpecGen.Alphabet() - rPlantGen.Alphabet();
00670     only_in_plant.Name("Only_In_Plant");
00671     only_in_spec.Name("Only_In_Specification");
00672     std::stringstream errstr;
00673     errstr << "Alphabets of generators do not match.";
00674     if(!only_in_plant.Empty())
00675       errstr << " " << only_in_plant.ToString() << ".";
00676     if(!only_in_spec.Empty())
00677       errstr << " " << only_in_spec.ToString() << ".";
00678     throw Exception("SupCon/SupConNB", errstr.str(), 100);
00679   }
00680   
00681   // TODO: add test for rCAlph <= Alphabet
00682 
00683   // TODO: check symboltables to match
00684 
00685   // plant and spec must be deterministic
00686   bool plant_det = rPlantGen.IsDeterministic();
00687   bool spec_det = rSpecGen.IsDeterministic();
00688 
00689   if ((plant_det == false) && (spec_det == true)) {
00690     std::stringstream errstr;
00691     errstr << "Plant generator must be deterministic, "
00692       << "but is nondeterministic";
00693     throw Exception("ControllableConsistencyCheck", errstr.str(), 201);
00694   }
00695   else if ((plant_det == true) && (spec_det == false)) {
00696     std::stringstream errstr;
00697     errstr << "Spec generator must be deterministic, "
00698        << "but is nondeterministic";
00699     throw Exception("ControllableConsistencyCheck", errstr.str(), 203);
00700   }
00701   else if ((plant_det == false) && (spec_det == false)) {
00702     std::stringstream errstr;
00703     errstr << "Plant and spec generator must be deterministic, "
00704        << "but both are nondeterministic";
00705     throw Exception("ControllableConsistencyCheck", errstr.str(), 204);
00706   }
00707 }
00708 
00709 
00710 /*
00711 ****************************************
00712 * SUPCON: WRAPPER / USER FUNCTIONS     *
00713 ****************************************
00714 */
00715 
00716 
00717 // IsControllable(rPlantGen, rCAlph, rSupCandGen)
00718 bool IsControllable(
00719   const Generator& rPlantGen, 
00720   const EventSet& rCAlph, 
00721   const Generator& rSupCandGen) 
00722 {
00723   FD_DF("IsControllable(" << &rSupCandGen << "," << &rPlantGen << ")");
00724 
00725   // HELPERS:
00726   FD_DF("IsControllable: controllable events: " << rCAlph.ToString());
00727   // critical set
00728   StateSet critical;
00729 
00730   // CONSISTENCY CHECKS:
00731   ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSupCandGen);
00732 
00733   // ALGORITHM:
00734   return IsControllableUnchecked(rPlantGen, rCAlph, rSupCandGen, critical);
00735 }
00736 
00737 
00738 // IsControllable(rPlantGen, rCAlph, rSupCandGen, critical)
00739 bool IsControllable(
00740   const Generator& rPlantGen, 
00741   const EventSet& rCAlph, 
00742   const Generator& rSupCandGen, 
00743   StateSet& rCriticalStates) 
00744 {
00745   FD_DF("IsControllable(" << &rSupCandGen << "," << &rPlantGen << ")");
00746 
00747   // CONSISTENCY CHECKS:
00748   ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSupCandGen);
00749 
00750   // ALGORITHM:
00751   return IsControllableUnchecked(rPlantGen, rCAlph, rSupCandGen, rCriticalStates);
00752 }
00753 
00754 
00755 // SupConNB(rPlantGen, rCAlph, rSpecGen, rResGen)
00756 void SupConNB(
00757   const Generator& rPlantGen, 
00758   const EventSet& rCAlph, 
00759   const Generator& rSpecGen, 
00760   Generator& rResGen) 
00761 {
00762 
00763   // CONSISTENCY CHECK:
00764   ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSpecGen);
00765 
00766   // HELPERS:
00767   std::map< std::pair<Idx,Idx>, Idx> rcmap;
00768 
00769   // ALGORITHM:
00770   SupConNBUnchecked(rPlantGen, rCAlph, rSpecGen, rcmap, rResGen);
00771 }
00772 
00773 
00774 
00775 
00776 // SupConNBNonDet(rPlantGen, rCAlph, rSpecGen, rReverseCompositionMap, 
00777 //     pDetPlantGen, pDetSpecGen, rResGen)
00778 void SupConNBNonDet(
00779   const Generator& rPlantGen, 
00780   const EventSet& rCAlph,
00781   const Generator& rSpecGen,
00782   std::map< std::pair<Idx,Idx>, Idx>& rReverseCompositionMap,
00783   Generator rDetPlantGen, 
00784   Generator rDetSpecGen, 
00785   std::map<Idx,StateSet>& rPowerStatesPlant, 
00786   std::map<Idx,StateSet>& rPowerStatesSpec,
00787   bool& rDetPlantBool, 
00788   bool& rDetSpecBool, 
00789   Generator& rResGen) 
00790 {
00791   FD_DF("SupConNBNonDet(" << &rPlantGen << "," << &rSpecGen << ")");
00792 
00793   // alphabets must match
00794   if (rPlantGen.Alphabet() != rSpecGen.Alphabet()) {
00795     throw Exception("SupConNBNonDet", "Alphabets of generators don't match", 100);
00796   }
00797 
00798   // PREPARE RESULT:
00799   Generator* pResGen = &rResGen;
00800   if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
00801     pResGen= rResGen.New();
00802   }
00803   pResGen->Clear();
00804   pResGen->Name(CollapsString("SupConNBNonDet(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
00805   pResGen->InjectAlphabet(rPlantGen.Alphabet());
00806   
00807   // HELPERS:
00808   rPowerStatesPlant.clear();
00809   rPowerStatesSpec.clear();
00810 
00811   // controllable events
00812   FD_DF("SupConNB: controllable events: " << rCAlph.ToString());
00813 
00814   // pointers to actual generators
00815   Generator* plantp;
00816   Generator* specp;
00817 
00818   // plant and spec determinism
00819   rDetPlantBool = rPlantGen.IsDeterministic();
00820   rDetSpecBool = rSpecGen.IsDeterministic();
00821   
00822   // create deterministic generators and set pointers to the actual ones
00823   plantp = const_cast<Generator*>(&rPlantGen);
00824   specp = const_cast<Generator*>(&rSpecGen);
00825   if (rDetPlantBool == false) {
00826       Deterministic(rPlantGen, rPowerStatesPlant, rDetPlantGen);    
00827       plantp = &rDetPlantGen;
00828   }
00829   if (rDetSpecBool == false) {
00830       Deterministic(rSpecGen, rPowerStatesSpec, rDetSpecGen);
00831       specp = &rDetSpecGen;
00832   }
00833   
00834   // ALGORITHM:
00835 
00836   // compute supervisor
00837   SupconParallel(*plantp, rCAlph, *specp, rReverseCompositionMap, *pResGen);
00838 
00839   // make resulting generator trim until it's fully controllable
00840   while(1) {
00841     if(pResGen->Empty()) break;
00842     Idx state_num = pResGen->Size();
00843     SupConUnchecked(*plantp, rCAlph, *pResGen);
00844     pResGen->Trim();
00845     if(pResGen->Size() == state_num) break;
00846   }
00847 
00848   // copy result
00849   if(pResGen != &rResGen) {
00850     pResGen->Move(rResGen);
00851     delete pResGen;
00852   }
00853 }
00854 
00855 // SupCon(rPlantGen, rCAlph, rSpecGen, rResGen)
00856 void SupCon(
00857   const Generator& rPlantGen, 
00858   const EventSet& rCAlph,
00859   const Generator& rSpecGen, 
00860   Generator& rResGen) 
00861 {
00862   // HELPERS:
00863   std::map< std::pair<Idx,Idx>, Idx> rcmap;
00864 
00865   // ALGORITHM:
00866   SupCon(rPlantGen, rCAlph, rSpecGen, rcmap, rResGen);
00867 }
00868 
00869 
00870 // SupCon(rPlantGen, rCAlph, rSpecGen, rReverseCompositionMap, rResGen)
00871 void SupCon(
00872   const Generator& rPlantGen, 
00873   const EventSet& rCAlph,
00874   const Generator& rSpecGen,
00875   std::map< std::pair<Idx,Idx>, Idx>& rReverseCompositionMap, 
00876   Generator& rResGen) 
00877 {
00878   FD_DF("SupCon(" << &rPlantGen << "," << &rSpecGen << ")");
00879 
00880   // PREPARE RESULT:
00881   
00882 
00883   // prepare result
00884   Generator* pResGen = &rResGen;
00885   if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
00886     pResGen= rResGen.New();
00887   }
00888   pResGen->Clear();
00889   pResGen->Name(CollapsString("SupCon(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))"));
00890   pResGen->InjectAlphabet(rPlantGen.Alphabet());
00891   
00892   // HELPERS:
00893   FD_DF("SupCon: controllable events: " << rCAlph.ToString());
00894 
00895   // CONSISTENCY CHECK:
00896   ControlProblemConsistencyCheck(rPlantGen, rCAlph, rSpecGen);
00897 
00898   // ALGORITHM:
00899 
00900   // parallel composition
00901   SupconParallel(rPlantGen, rCAlph, rSpecGen, rReverseCompositionMap, *pResGen);
00902   // make resulting generator controllable
00903   SupConUnchecked(rPlantGen, rCAlph, *pResGen);
00904 
00905   // convenience state names
00906   if (rPlantGen.StateNamesEnabled() && rSpecGen.StateNamesEnabled() && rResGen.StateNamesEnabled()) 
00907     SetComposedStateNames(rPlantGen, rSpecGen, rReverseCompositionMap, *pResGen);
00908   else
00909     pResGen->ClearStateNames();
00910 
00911   // copy result
00912   if(pResGen != &rResGen) {
00913     pResGen->Move(rResGen);
00914     delete pResGen;
00915   }
00916 }
00917 
00918 
00919 // TraverseUncontrollableBackwards(rCAlph, rtransrel, critical, current)
00920 void TraverseUncontrollableBackwards(
00921   const EventSet& rCAlph, 
00922   TransSetX2EvX1& rtransrel, 
00923   StateSet& rCriticalStates, 
00924   Idx current) {
00925   FD_DF("TraverseUncontrollableBackwards: " << rCriticalStates.Str(current));
00926 
00927   // HELPERS:
00928   std::stack<Idx> todo;
00929   TransSetX2EvX1::Iterator rtit = rtransrel.BeginByX2(current);
00930   TransSetX2EvX1::Iterator rtit_end = rtransrel.EndByX2(current);
00931 
00932   // ALGORITHM:
00933   rCriticalStates.Insert(current);
00934   todo.push(current);
00935   FD_DF("TraverseUncontrollableBackwards: current rCriticalStates set: " 
00936      << rCriticalStates.ToString());
00937   // process todo stack
00938   while (! todo.empty()) {
00939     // get top state from todo stack
00940     current = todo.top(); todo.pop();
00941     // iteration over all transitions with x2 == current
00942     rtit_end = rtransrel.EndByX2(current);
00943     rtit = rtransrel.BeginByX2(current);
00944     for (; rtit != rtit_end; ++rtit) {
00945       // if uncontrollable event and predecessor state not already critical
00946       if ((!rCAlph.Exists(rtit->Ev)) && (! rCriticalStates.Exists(rtit->X1))) {
00947         FD_DF("TraverseUncontrollableBackwards: todo push " << rCriticalStates.Str(rtit->X1));
00948   todo.push(rtit->X1);
00949   FD_DF("TraverseUncontrollableBackwards: critical insert: " << rCriticalStates.Str(rtit->X1));
00950   rCriticalStates.Insert(rtit->X1);
00951       }
00952     }
00953   } // end while todo
00954 }
00955 
00956 
00957 // controllability test for System plant
00958 bool IsControllable(
00959   const System& rPlantGen, 
00960   const Generator& rSupCandGen)
00961 {
00962   return IsControllable(rPlantGen, rPlantGen.ControllableEvents(), rSupCandGen);
00963 }
00964 
00965 
00966 // supcon for Systems:
00967 // uses and maintains controllablity from plant 
00968 void SupConNB(
00969   const System& rPlantGen, 
00970   const Generator& rSpecGen, 
00971   Generator& rResGen) {
00972 
00973   // prepare result
00974   Generator* pResGen = &rResGen;
00975   if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
00976     pResGen= rResGen.New();
00977   }
00978 
00979   // execute 
00980   SupConNB(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,*pResGen);
00981 
00982   // copy all attributes of input alphabet
00983   pResGen->EventAttributes(rPlantGen.Alphabet());
00984 
00985   // copy result
00986   if(pResGen != &rResGen) {
00987     pResGen->Move(rResGen);
00988     delete pResGen;
00989   }
00990 
00991 }
00992 
00993 // supcon for Systems
00994 // uses and maintains controllablity from plant 
00995 void SupCon(
00996   const System& rPlantGen, 
00997   const Generator& rSpecGen, 
00998   Generator& rResGen) {
00999 
01000   // prepare result
01001   Generator* pResGen = &rResGen;
01002   if(&rResGen== &rPlantGen || &rResGen== &rSpecGen) {
01003     pResGen= rResGen.New();
01004   }
01005 
01006   // execute
01007   SupCon(rPlantGen, rPlantGen.ControllableEvents(),rSpecGen,*pResGen);
01008 
01009   // copy all attributes of input alphabet
01010   pResGen->EventAttributes(rPlantGen.Alphabet());
01011 
01012   // copy result
01013   if(pResGen != &rResGen) {
01014     pResGen->Move(rResGen);
01015     delete pResGen;
01016   }
01017 
01018 }
01019 
01020 } // name space 

libFAUDES 2.20d --- 2011.04.26 --- c++ source docu by doxygen