libFAUDES

Sections

Index

mtc_supcon.cpp

Go to the documentation of this file.
00001 /** @file mtc_supcon.cpp
00002 
00003 Supremal controllable sublanguage and controllablity
00004 
00005 */
00006 
00007 /* FAU Discrete Event Systems Library (libfaudes)
00008 
00009    Copyright (C) 2008  Matthias Singer
00010    Copyright (C) 2006  Bernd Opitz
00011    Exclusive copyright is granted to Klaus Schmidt
00012 
00013    This library is free software; you can redistribute it and/or
00014    modify it under the terms of the GNU Lesser General Public
00015    License as published by the Free Software Foundation; either
00016    version 2.1 of the License, or (at your option) any later version.
00017 
00018    This library is distributed in the hope that it will be useful,
00019    but WITHOUT ANY WARRANTY; without even the implied warranty of
00020    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021    Lesser General Public License for more details.
00022 
00023    You should have received a copy of the GNU Lesser General Public
00024    License along with this library; if not, write to the Free Software
00025    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00026 
00027 
00028 #include "mtc_supcon.h"
00029 #include "syn_include.h"
00030 
00031 namespace faudes {
00032 
00033 /*
00034 ******************************
00035 * SUPCON: USER FUNCTIONS     *
00036 ******************************
00037 */
00038 
00039 
00040 // mtcSupConNB(rPlantGen, rSpecGen, rResGen)
00041 void mtcSupConNB(const  mtcGenerator& rPlantGen, const mtcGenerator& rSpecGen, mtcGenerator& rResGen) {
00042   // HELPERS:
00043   std::map< std::pair<Idx,Idx>, Idx> rcmap;
00044   // ALGORITHM:
00045   mtcSupConNB(rPlantGen, rSpecGen, rcmap, rResGen);
00046 }
00047 
00048 
00049 // mtcSupConNB(rPlantGen, rSpecGen, rReverseCompositionMap, rResGen)
00050 void mtcSupConNB(const  mtcGenerator& rPlantGen, const mtcGenerator& rSpecGen,
00051   std::map< std::pair<Idx,Idx>, Idx>& rReverseCompositionMap,  mtcGenerator& rResGen) {
00052   FD_DF("mtcSupConNB(" << &rPlantGen << "," << &rSpecGen << ")");
00053 
00054   // PREPARE RESULT:
00055 
00056   rResGen.Clear();
00057   rResGen.Name("mtcSupConNB(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))");
00058   rResGen.InjectAlphabet(rPlantGen.Alphabet());
00059 
00060   rResGen.SetControllable(rPlantGen.ControllableEvents());
00061   rResGen.SetForcible(rPlantGen.ForcibleEvents());
00062   rResGen.ClrObservable(rPlantGen.UnobservableEvents());
00063 
00064   // HELPERS:
00065 
00066   // controllable events
00067   const EventSet ualph = rPlantGen.UncontrollableEvents();
00068   FD_DF("mtcSupConNB: controllable events: " << rPlantGen.ControllableEvents().ToString());
00069   FD_DF("mtcSupConNB: uncontrollable events: " << ualph.ToString());
00070 
00071   // CONSISTENCY CHECK:
00072 
00073   // alphabets must match
00074   if (rPlantGen.Alphabet() != rSpecGen.Alphabet()) {
00075     EventSet only_in_plant = rPlantGen.Alphabet() - rSpecGen.Alphabet();
00076     EventSet only_in_spec = rSpecGen.Alphabet() - rPlantGen.Alphabet();
00077     std::stringstream errstr;
00078     errstr << "Alphabets of generators do not match. Only in plant: " << only_in_plant.ToString()
00079       << ". Only in spec: " << only_in_spec.ToString() << ".";
00080     throw Exception("mtcSupConNB", errstr.str(), 500);
00081   }
00082 
00083   // plant and spec must be deterministic
00084   bool plant_det = rPlantGen.IsDeterministic();
00085   bool spec_det = rSpecGen.IsDeterministic();
00086 
00087   if ((plant_det == false) && (spec_det == true)) {
00088     std::stringstream errstr;
00089     errstr << "Plant generator must be deterministic, "
00090                     << "but is nondeterministic";
00091     throw Exception("mtcSupConNB", errstr.str(), 501);
00092   }
00093   else if ((plant_det == true) && (spec_det == false)) {
00094     std::stringstream errstr;
00095     errstr << "Spec generator must be deterministic, "
00096                     << "but is nondeterministic";
00097     throw Exception("mtcSupConNB", errstr.str(), 503);
00098   }
00099   else if ((plant_det == false) && (spec_det == false)) {
00100     std::stringstream errstr;
00101     errstr << "Plant and spec generator must be deterministic, "
00102                     << "but both are nondeterministic";
00103     throw Exception("mtcSupConNB", errstr.str(), 504);
00104   }
00105 
00106   // ALGORITHM:
00107 
00108   mtcSupConParallel(rPlantGen, rSpecGen, ualph, rReverseCompositionMap, rResGen);
00109   FD_DF("mtcSupConNB: mtcSupConParallel passed...");
00110 
00111   // make resulting generator trim until it's fully controllable
00112   while (1) {
00113     if (rResGen.Empty()) {
00114       return;
00115     }
00116     Idx state_num = rResGen.Size();
00117     bool supcon = SupConUnchecked(rPlantGen, rPlantGen.ControllableEvents(), rResGen);
00118     bool trim = rResGen.StronglyTrim();
00119     if (supcon && trim && (rResGen.Size() == state_num)) {
00120       return;
00121     }
00122     FD_DF("mtcSupConNB: rResGen.Size() = " << ToStringInteger(rResGen.Size()) << ", state_num = " << ToStringInteger(state_num));
00123   }
00124 }
00125 
00126 // mtcSupCon(rPlantGen, rSpecGen, rResGen)
00127 void mtcSupCon(const  mtcGenerator& rPlantGen, const mtcGenerator& rSpecGen, mtcGenerator& rResGen) {
00128   // HELPERS:
00129   std::map< std::pair<Idx,Idx>, Idx> rcmap;
00130 
00131   // ALGORITHM:
00132   mtcSupCon(rPlantGen, rSpecGen, rcmap, rResGen);
00133 }
00134 
00135 
00136 // mtcSupCon(rPlantGen, rSpecGen, rReverseCompositionMap, rResGen)
00137 void mtcSupCon(const  mtcGenerator& rPlantGen, const mtcGenerator& rSpecGen,
00138   std::map< std::pair<Idx,Idx>, Idx>& rReverseCompositionMap,  mtcGenerator& rResGen) {
00139   FD_DF("mtcSupCon(" << &rPlantGen << "," << &rSpecGen << ")");
00140 
00141   // PREPARE RESULT:
00142   rResGen.Clear();
00143   rResGen.Name("mtcSupCon(("+rPlantGen.Name()+"),("+rSpecGen.Name()+"))");
00144 
00145   rResGen.InjectAlphabet(rPlantGen.Alphabet());
00146 
00147   rResGen.SetControllable(rPlantGen.ControllableEvents());
00148   rResGen.SetForcible(rPlantGen.ForcibleEvents());
00149   rResGen.ClrObservable(rPlantGen.UnobservableEvents());
00150 
00151   // HELPERS:
00152 
00153   // controllable events
00154   const EventSet ualph = rPlantGen.UncontrollableEvents();
00155   FD_DF("mtcSupCon: controllable events: " << rPlantGen.ControllableEvents().ToString());
00156   FD_DF("mtcSupCon: uncontrollable events: " << ualph.ToString());
00157 
00158   // CONSISTENCY CHECK:
00159 
00160   // alphabets must match
00161   if (rPlantGen.Alphabet() != rSpecGen.Alphabet()) {
00162     EventSet only_in_plant = rPlantGen.Alphabet() - rSpecGen.Alphabet();
00163     EventSet only_in_spec = rSpecGen.Alphabet() - rPlantGen.Alphabet();
00164     std::stringstream errstr;
00165     errstr << "Alphabets of generators do not match. Only in plant: " 
00166       << only_in_plant.ToString() << ". Only in spec: "
00167       << only_in_spec.ToString() << ".";
00168     throw Exception("mtcSupCon", errstr.str(), 500);
00169   }
00170 
00171   // plant and spec must be deterministic
00172   bool plant_det = rPlantGen.IsDeterministic();
00173   bool spec_det = rSpecGen.IsDeterministic();
00174 
00175   if ((plant_det == false) && (spec_det == true)) {
00176     std::stringstream errstr;
00177     errstr << "Plant generator must be deterministic, " << "but is nondeterministic";
00178     throw Exception("mtcSupCon", errstr.str(), 501);
00179   }
00180   else if ((plant_det == true) && (spec_det == false)) {
00181     std::stringstream errstr;
00182     errstr << "Spec generator must be deterministic, " << "but is nondeterministic";
00183     throw Exception("mtcSupCon", errstr.str(), 503);
00184   }
00185   else if ((plant_det == false) && (spec_det == false)) {
00186     std::stringstream errstr;
00187     errstr << "Plant and spec generator must be deterministic, "
00188                     << "but both are nondeterministic";
00189     throw Exception("mtcSupConNB", errstr.str(), 504);
00190   }
00191 
00192   // ALGORITHM:
00193 
00194   // parallel composition
00195   mtcSupConParallel(rPlantGen, rSpecGen, ualph, rReverseCompositionMap, rResGen);
00196   // make resulting generator controllable
00197   mtcSupConUnchecked(rPlantGen, rPlantGen.ControllableEvents(), rResGen);
00198 }
00199 
00200 
00201 
00202 /*
00203 ********************************************
00204 * Fast parallel composition for mtcSupCon     *
00205 ********************************************
00206 */
00207 
00208 
00209 // mtcSupConParallel(rPlantGen, rSpecGen, rUAlph, rReverseCompositionMap, rResGen)
00210 void mtcSupConParallel(const  mtcGenerator& rPlantGen, const mtcGenerator& rSpecGen, const EventSet& rUAlph,
00211   std::map< std::pair<Idx,Idx>, Idx>& rReverseCompositionMap, mtcGenerator& rResGen) {
00212   FD_DF("mtcSupConParallel(" << &rPlantGen << "," << &rSpecGen << ")");
00213 
00214   // HELPERS:
00215 
00216   // todo stack
00217   std::stack< std::pair<Idx,Idx> > todo;
00218   // set of forbidden states
00219   StateSet forbidden;
00220   // actual pair, new pair
00221   std::pair<Idx,Idx> currentstates, newstates;
00222   // other stuff
00223   Idx tmpstate;
00224   std::map< std::pair<Idx,Idx>, Idx>::iterator rcmapit;
00225   StateSet::Iterator lit1, lit2;
00226   TransSet::Iterator titg, titg_end, tith, tith_end;
00227 
00228   // ALGORITHM:
00229   if (rPlantGen.InitStatesEmpty()) {
00230     FD_DF("SupconParallel: plant got no initial states. "
00231         << "parallel composition contains empty language.");
00232     return;
00233   }
00234 
00235   if (rSpecGen.InitStatesEmpty()) {
00236     FD_DF("mtcSupConParallel: spec got no initial states. "
00237         << "parallel composition contains empty language.");
00238     return;
00239   }
00240   ColorSet plantColors = rPlantGen.Colors();
00241   ColorSet specColors = rSpecGen.Colors();
00242   // create initial state
00243   currentstates = std::make_pair(*rPlantGen.InitStatesBegin(), *rSpecGen.InitStatesBegin());
00244   todo.push(currentstates);
00245   ColorSet ComposedSet;
00246   ComposedColorSet(rPlantGen, currentstates.first, plantColors, rSpecGen, currentstates.second,
00247       specColors, ComposedSet);
00248     if (! ComposedSet.Empty() ) {
00249       Idx StateIndex = rResGen.InsInitState();
00250       rReverseCompositionMap[currentstates] = StateIndex;
00251       rResGen.InsColors(StateIndex, ComposedSet);
00252       FD_DF("mtcSupConParallel: NEW IMSTATE: (" << rPlantGen.SStr(currentstates.first)
00253           << "|" << rSpecGen.SStr(currentstates.second) << ") -> "  << rReverseCompositionMap[currentstates]);
00254     }
00255     else {
00256       rReverseCompositionMap[currentstates] = rResGen.InsInitState();
00257       FD_DF("mtcSupConParallel: NEW ISTATE: (" << rPlantGen.SStr(currentstates.first) 
00258         << "|" << rSpecGen.SStr(currentstates.second) << ") -> " << rReverseCompositionMap[currentstates]);
00259     }
00260 
00261     // first do parallel composition of allowed states
00262     // by deleting forbidden states on the fly.
00263     // this creates an accessible new generator
00264     FD_DF("mtcSupConParallel: *** processing reachable states ***");
00265     while (! todo.empty()) {
00266       // get next reachable pair of states from todo stack
00267       currentstates = todo.top();
00268       todo.pop();
00269       FD_DF("mtcSupConParallel: todo pop: (" << rPlantGen.SStr(currentstates.first) 
00270         << "|" << rSpecGen.SStr(currentstates.second) << ") -> " << rReverseCompositionMap[currentstates]);
00271 
00272       titg = rPlantGen.TransRelBegin(currentstates.first);
00273       titg_end = rPlantGen.TransRelEnd(currentstates.first);
00274       tith = rSpecGen.TransRelBegin(currentstates.second);
00275       tith_end = rSpecGen.TransRelEnd(currentstates.second);
00276 
00277 #ifdef FAUDES_DEBUG_FUNCTION
00278       // print all transitions of current states
00279       FD_DF("mtcSupConParallel: transitions from current states:");
00280       for (;titg != titg_end; ++titg) { 
00281         FD_DF("mtcSupConParallel: g: " << rPlantGen.SStr(titg->X1) << "-" << rPlantGen.EStr(titg->Ev) 
00282                               << "-" << rPlantGen.SStr(titg->X2));
00283       }
00284       for (;tith != tith_end; ++tith) {
00285         FD_DF("mtcSupConParallel: h: " << rSpecGen.SStr(tith->X1) << "-" << rSpecGen.EStr(tith->Ev) 
00286                               << "-" << rSpecGen.SStr(tith->X2));
00287       }
00288       titg = rPlantGen.TransRelBegin(currentstates.first);
00289               tith = rSpecGen.TransRelBegin(currentstates.second);
00290 #endif
00291       // process all h transitions while there could be matching g transitions
00292       while ((tith != tith_end) && (titg != titg_end)) {
00293         FD_DF("mtcSupConParallel: actual g-transition: " << rPlantGen.SStr(titg->X1) 
00294                         << "-" << rPlantGen.EStr(titg->Ev) << "-" << rPlantGen.SStr(titg->X2));
00295         FD_DF("mtcSupConParallel: actual h-transition: " << rSpecGen.SStr(tith->X1) 
00296                         << "-" << rSpecGen.EStr(tith->Ev) << "-" << rSpecGen.SStr(tith->X2));
00297         // execute common events
00298         if (titg->Ev == tith->Ev) {
00299           FD_DF("mtcSupConParallel: executing common event " 
00300                           << rPlantGen.EStr(titg->Ev));
00301           newstates = std::make_pair(titg->X2, tith->X2);
00302           rcmapit = rReverseCompositionMap.find(newstates);
00303           // add to todo list if state is new
00304           if (rcmapit == rReverseCompositionMap.end()) {
00305             todo.push(newstates);
00306             // if colored state
00307             ComposedColorSet(rPlantGen, newstates.first, plantColors, rSpecGen, newstates.second,
00308                specColors, ComposedSet);
00309             if (not ComposedSet.Empty() ) {
00310               tmpstate = rResGen.InsState();
00311               rResGen.InsColors(tmpstate, ComposedSet);
00312               FD_DF("mtcSupConParallel: NEW MSTATE: (" 
00313                 << rPlantGen.SStr(newstates.first) << "|"
00314                 << rSpecGen.SStr(newstates.second) << ") -> " << tmpstate);
00315             }
00316             // if "normal" state
00317             else {
00318               tmpstate = rResGen.InsState();
00319               FD_DF("mtcSupConParallel: NEW STATE: (" 
00320                 << rPlantGen.SStr(newstates.first) << "|" 
00321                 << rSpecGen.SStr(newstates.second) << ") -> " << tmpstate);
00322             }
00323             rReverseCompositionMap[newstates] = tmpstate;
00324             FD_DF("mtcSupConParallel: todo push: (" << rPlantGen.SStr(newstates.first)
00325               << "|" << rSpecGen.SStr(newstates.second) << ") -> " << tmpstate);
00326           }
00327           // if state already exists
00328           else {
00329             tmpstate = rcmapit->second;
00330           }
00331           // if successor state not in forbidden set add transition
00332           if (! forbidden.Exists(tmpstate)) {
00333             FD_DF("mtcSupConParallel: ADDING TRANSITION " 
00334               << rPlantGen.SStr(rReverseCompositionMap[currentstates]) << "-" << rPlantGen.EStr(titg->Ev) 
00335               << "-" << rPlantGen.SStr(tmpstate));
00336             rResGen.SetTransition(rReverseCompositionMap[currentstates], titg->Ev, tmpstate);
00337             FD_DF("mtcSupConParallel: incrementing g transrel");
00338             ++titg;
00339             FD_DF("mtcSupConParallel: incrementing h transrel");
00340             ++tith;
00341           }
00342           // if successor state in forbidden and event uncontrollable 
00343           // delete state
00344           else if (rUAlph.Exists(titg->Ev)) {
00345             FD_DF("mtcSupConParallel: successor " << rSpecGen.SStr(tmpstate) 
00346               << "in forbidden and common event " << rSpecGen.EStr(titg->Ev) 
00347               << " uncontrollable:");
00348             FD_DF("mtcSupConParallel: forbidden insert" << rPlantGen.SStr(tmpstate));
00349             forbidden.Insert(tmpstate);
00350 #ifdef FAUDES_CHECKED
00351             // do not end while loops here for detecting all h transitions 
00352             // not in g
00353             FD_DF("mtcSupConParallel: incrementing g transrel (FAUDES_CHECKED)");
00354             ++titg;
00355             FD_DF("mtcSupConParallel: incrementing h transrel (FAUDES_CHECKED)");
00356             ++tith;
00357 #else
00358             // exit all loops
00359             titg = titg_end;
00360             tith = tith_end;
00361 #endif
00362           }
00363           // else if successor state in forbidden and event controllable
00364           else {
00365             FD_DF("mtcSupConParallel: incrementing g transrel");
00366             ++titg;
00367             FD_DF("mtcSupConParallel: incrementing h transrel");
00368             ++tith;
00369           }
00370         }
00371         // if g got some more transitions try to resync events
00372         else if (titg->Ev < tith->Ev) {
00373           FD_DF("mtcSupConParallel: asynchronous execution of event " 
00374             << rPlantGen.EStr(titg->Ev) << " in g while " << rSpecGen.EStr(tith->Ev)
00375           << " in h");
00376           // if uncontrollable transition leaves specification
00377           // delete state from res and put into forbiddenset
00378           if (rUAlph.Exists(titg->Ev)) {
00379             FD_DF("mtcSupConParallel: asynchronous event " << rPlantGen.EStr(titg->Ev) 
00380                             << " in g is uncontrollable");
00381             tmpstate = rReverseCompositionMap[currentstates]; 
00382             FD_DF("mtcSupConParallel: forbidden insert" << rPlantGen.SStr(tmpstate));
00383             forbidden.Insert(tmpstate);
00384             // exit all loops
00385             titg = titg_end;
00386             tith = tith_end;
00387             break;
00388           }
00389           FD_DF("mtcSupConParallel: incrementing g transrel");
00390           ++titg;
00391         } // if specification leaves plant model emit warning
00392         else {
00393 #ifdef FAUDES_CHECKED
00394 //          FD_WARN("mtcSupConParallel:  transition " << rSpecGen.SStr(tith->X1) 
00395 //            << "-" << rSpecGen.EStr(tith->Ev) << "-" << rSpecGen.SStr(tith->X2) 
00396 //            << " in specification h not found in g");
00397 #endif
00398           FD_DF("mtcSupConParallel: incrementing h transrel");
00399           ++tith;
00400         }
00401       }
00402     if (rResGen.InitStates().Empty()) FD_DF("mtcSupConParallel: rResGen has no initial states... (2)");
00403 
00404       // if g got some more transitions not in h
00405       while (titg != titg_end) {
00406         FD_DF("mtcSupConParallel: asynchronous execution of event " 
00407           << rPlantGen.EStr(titg->Ev) << " in g at end of h");
00408         FD_DF("mtcSupConParallel: actual g-transition: " << rPlantGen.SStr(titg->X1) 
00409           << "-" << rPlantGen.EStr(titg->Ev) << "-" << rPlantGen.SStr(titg->X2));
00410         FD_DF("mtcSupConParallel: actual h-transition: end");
00411         // if uncontrollable transition leaves specification
00412         if (rUAlph.Exists(titg->Ev)) {
00413           tmpstate = rReverseCompositionMap[currentstates];
00414           FD_DF("mtcSupConParallel: asynchron executed uncontrollable end "
00415             << "event " << rPlantGen.EStr(titg->Ev) << " leaves specification:");
00416           FD_DF("mtcSupConParallel: forbidden insert" << rPlantGen.SStr(tmpstate));
00417           forbidden.Insert(tmpstate);
00418           // exit this loop
00419           // if FAUDES_CHECKED not defined this means exiting all loops
00420           break;
00421         }
00422         FD_DF("mtcSupConParallel: incrementing g transrel");
00423         ++titg;
00424       }
00425 #ifdef FAUDES_CHECKED
00426       // if h got some more transitions not in g
00427 //      while (tith != tith_end) {
00428 //  FD_WARN("mtcSupConParallel:  transition " << rSpecGen.SStr(tith->X1) << "-" 
00429 //    << rSpecGen.EStr(tith->Ev) << "-" << rSpecGen.SStr(tith->X2) 
00430 //    << "in specification h not found in g");
00431 //  FD_DF("mtcSupConParallel: incrementing h transrel");
00432 //    ++tith;
00433 // }
00434 #endif
00435     }
00436     FD_DF("mtcSupConParallel: deleting forbidden states...");
00437     // remove attributes belonging to forbidden states
00438     StateSet::Iterator st_it;
00439     for(st_it = forbidden.Begin(); st_it != forbidden.End(); ++st_it){
00440       rResGen.ClrStateAttribute(*st_it);
00441     }
00442     // remove forbidden states from stateset
00443     rResGen.DelStates(forbidden);
00444 }
00445 
00446 /*
00447 *****************************************
00448 * mtcSupConUnchecked: REAL SUPCON FUNCTION *
00449 *****************************************
00450 */
00451 
00452 
00453 // mtcSupConUnchecked(rPlantGen, rSupGen)
00454 bool mtcSupConUnchecked(const  mtcGenerator& rPlantGen, const EventSet& rCAlph, mtcGenerator& rSupGen) {
00455   FD_DF("mtcSupConUnchecked...");
00456 
00457   // HELPERS:
00458 
00459   // set of forbidden states
00460   StateSet forbidden;
00461 
00462   // ALGORITHM:
00463 
00464   // return true if plant or parallelcomp contain no initial states
00465   if (rPlantGen.InitStatesEmpty() || rSupGen.InitStatesEmpty()) {
00466     FD_DF("mtcSupConUnchecked: no initial states...");
00467     return true;
00468   }
00469 
00470   IsControllable(rPlantGen, rCAlph, rSupGen, forbidden);
00471 
00472   // remove attributes belonging to forbidden states
00473   StateSet::Iterator st_it;
00474   for(st_it = forbidden.Begin(); st_it != forbidden.End(); ++st_it){
00475     rSupGen.ClrStateAttribute(*st_it);
00476     }
00477   // remove forbidden states from stateset
00478   rSupGen.DelStates(forbidden);
00479 
00480   // return true if no states had to be deleted
00481   if (forbidden.Empty()) {
00482     FD_DF("mtcSupCon: controllable");
00483     return true;
00484   }
00485   // return false if states had to be deleted
00486   else {
00487     FD_DF("mtcSupCon: not controllable");
00488     return false;
00489   }
00490 }
00491 
00492 
00493 // IsControllableUnchecked(rPlantGen, rSpecGen, rUAlph, forbidden)
00494 bool IsControllableUnchecked(const  mtcGenerator& rPlantGen, 
00495           const mtcGenerator& rSpecGen, const EventSet& rUAlph, StateSet& forbidden) {
00496   FD_DF("IsControllableUnchecked(" << &rSpecGen << "," << &rPlantGen << ")");
00497 
00498   // HELPERS:
00499 
00500   // todo stack
00501   std::stack<Idx> todog, todoh;
00502   // set of already discovered states
00503   StateSet discovered;
00504   // reverse sorted transition relation build on the fly
00505   TransSetX2EvX1 rtransrel;
00506 
00507   // PREPARE RESULT:
00508   forbidden.Clear();
00509 
00510   // ALGORITHM:
00511 
00512       // return false (uncontrollable) if there is no initial state
00513   if (rPlantGen.InitStatesEmpty() || rSpecGen.InitStatesEmpty()) {
00514     return false;
00515   }
00516 
00517   // push combined initial state on todo stack
00518   todog.push(*rPlantGen.InitStatesBegin());
00519   todoh.push(*rSpecGen.InitStatesBegin());
00520   FD_DF("IsControllable: todo push: (" << rPlantGen.SStr(*rPlantGen.InitStatesBegin()) << "|"
00521     << rSpecGen.SStr(*rSpecGen.InitStatesBegin()) << ")");
00522 
00523   // process todo stack
00524   while (! todog.empty()) {
00525     // get top elements from todo stack
00526     Idx currentg = todog.top();
00527     Idx currenth = todoh.top();
00528     todog.pop();
00529     todoh.pop();
00530     FD_DF("IsControllable: todo pop: (" << rPlantGen.SStr(currentg) << "|" 
00531       << rSpecGen.SStr(currenth) << ")");
00532 
00533 #ifdef FAUDES_DEBUG_FUNCTION
00534     TransSet::Iterator _titg, _tith;
00535     // print all transitions of current states
00536     FD_DF("IsControllable: transitions from current states:");
00537     for (_titg = rPlantGen.TransRelBegin(currentg); _titg != rPlantGen.TransRelEnd(currentg); ++_titg) 
00538     FD_DF("IsControllable: g: " << rPlantGen.SStr(_titg->X1) << "-" 
00539       << rPlantGen.EStr(_titg->Ev) << "-" << rPlantGen.SStr(_titg->X2));
00540     for (_tith = rSpecGen.TransRelBegin(currenth); _tith != rSpecGen.TransRelEnd(currenth); ++_tith) 
00541     FD_DF("IsControllable: h: " << rSpecGen.SStr(_tith->X1) << "-" 
00542       << rSpecGen.EStr(_tith->Ev) << "-" << rSpecGen.SStr(_tith->X2));
00543 #endif 
00544 
00545     // process all h transitions while there could be matching g transitions
00546     TransSet::Iterator titg = rPlantGen.TransRelBegin(currentg);
00547     TransSet::Iterator titg_end = rPlantGen.TransRelEnd(currentg);
00548     TransSet::Iterator tith = rSpecGen.TransRelBegin(currenth);
00549     TransSet::Iterator tith_end = rSpecGen.TransRelEnd(currenth);
00550     while ((tith != tith_end) && (titg != titg_end)) {
00551       FD_DF("IsControllable: actual g-transition: " << rPlantGen.SStr(titg->X1) 
00552         << "-" << rPlantGen.EStr(titg->Ev) << "-" << rPlantGen.SStr(titg->X2));
00553       FD_DF("IsControllable: actual h-transition: " << rSpecGen.SStr(tith->X1) 
00554         << "-" << rSpecGen.EStr(tith->Ev) << "-" << rSpecGen.SStr(tith->X2));
00555       // execute common events
00556       if (titg->Ev == tith->Ev) {
00557         FD_DF("IsControllable: executing common event " << rPlantGen.EStr(titg->Ev));
00558         // add to todo list if state is undiscovered
00559         if (! discovered.Exists(currenth)) {
00560           todog.push(titg->X2);
00561           todoh.push(tith->X2);
00562           FD_DF("IsControllable: todo push: (" << rPlantGen.SStr(titg->X2) << "|"
00563             << rSpecGen.SStr(tith->X2) << ")");
00564         }
00565         // if h successor state not in forbidden set add transition to rtransrel
00566         if (! forbidden.Exists(tith->X2)) {
00567           rtransrel.Insert(*tith);
00568           FD_DF("IsControllable: incrementing g transrel");
00569           ++titg;
00570           FD_DF("IsControllable: incrementing h transrel");
00571           ++tith;
00572         }
00573         // if successor state is forbidden and event uncontrollable 
00574         else if (rUAlph.Exists(titg->Ev)) {
00575           FD_DF("IsControllable: successor state " << rSpecGen.SStr(tith->X2) << 
00576             " forbidden and event " << rPlantGen.EStr(titg->Ev) << " uncontrollable:");
00577           FD_DF("IsControllable: TraverseUncontrollableBackwards(" << rSpecGen.SStr(currenth) << ")");
00578           TraverseUncontrollableBackwards(rUAlph, rtransrel, forbidden, currenth);
00579 #ifdef FAUDES_CHECKED
00580           // just increment transrel iterators to find all h transitions not in g
00581           FD_DF("IsControllable: incrementing g transrel (FAUDES_CHECKED)");
00582           ++titg;
00583           FD_DF("IsControllable: incrementing h transrel (FAUDES_CHECKED)");
00584           ++tith;
00585 #else
00586           // exit all loops
00587           titg = titg_end;
00588           tith = tith_end;
00589 #endif
00590           break;
00591         }
00592         // else if successor state in forbidden and event controllable
00593         else {
00594           FD_DF("IsControllable: incrementing g transrel");
00595           ++titg;
00596           FD_DF("IsControllable: incrementing h transrel");
00597           ++tith;
00598         }
00599       }
00600       // if g got some more transitions try to resync events
00601       else if (titg->Ev < tith->Ev) {
00602         FD_DF("IsControllable: asynchronous execution of event " 
00603           << rPlantGen.EStr(titg->Ev) << " in g while " << rSpecGen.EStr(tith->Ev)
00604           << " in h");
00605         // if uncontrollable transition leaves specification
00606         // delete state from rResGen and put into forbiddenset
00607         if (rUAlph.Exists(titg->Ev)) {
00608         FD_DF("IsControllable: asynchronous event " << rPlantGen.EStr(titg->Ev) 
00609           << " in g is uncontrollable");
00610         FD_DF("IsControllable: TraverseUncontrollableBackwards(" << rSpecGen.SStr(currenth) << ")");
00611         TraverseUncontrollableBackwards(rUAlph, rtransrel, forbidden, currenth);
00612         // exit all loops over g transrel
00613           titg = titg_end;
00614           break;
00615         }
00616         FD_DF("IsControllable: incrementing g transrel");
00617         ++titg;
00618       }
00619       // if specification leaves plant model emit warning
00620       else {
00621 #ifdef FAUDES_CHECKED
00622         FD_WARN("IsControllable: transition " << rSpecGen.SStr(tith->X1) << "-" 
00623           << rSpecGen.EStr(tith->Ev) << "-" << rSpecGen.SStr(tith->X2)
00624           << "in specification h not found in g");
00625 #endif
00626         FD_DF("IsControllable: incrementing h transrel");
00627         ++tith;
00628       }
00629     }
00630     // process other transitions not in h
00631     while (titg != titg_end) {
00632       FD_DF("IsControllable: asynchronous execution of event " 
00633         << rPlantGen.EStr(titg->Ev) << " in g at end of h");
00634       FD_DF("IsControllable: actual g-transition: " << rPlantGen.SStr(titg->X1) 
00635         << "-" << rPlantGen.EStr(titg->Ev) << "-" << rPlantGen.SStr(titg->X2));
00636       FD_DF("IsControllable: actual h-transition: end");
00637       // if uncontrollable transition leaves specification
00638       if (rUAlph.Exists(titg->Ev)) {
00639         FD_DF("IsControllable: asynchronous execution of uncontrollable event "
00640           << rPlantGen.EStr(titg->Ev) << " in g");
00641         FD_DF("IsControllable: TraverseUncontrollableBackwards(" << rPlantGen.SStr(currenth) << ")");
00642         TraverseUncontrollableBackwards(rUAlph, rtransrel, forbidden, currenth);
00643         // exit this loop
00644         break;
00645       }
00646       FD_DF("IsControllable: incrementing g transrel");
00647       ++titg;
00648     }
00649 #ifdef FAUDES_CHECKED
00650     // process other transitions not in g
00651     while (tith != tith_end) {
00652       FD_WARN("IsControllable: transition " << rSpecGen.SStr(tith->X1) << "-" 
00653         << rSpecGen.EStr(tith->Ev) << "-" << rSpecGen.SStr(tith->X2)
00654         << "in specification h not found in g");
00655       FD_DF("IsControllable: incrementing h transrel");
00656       ++tith;
00657     }
00658 #endif
00659     discovered.Insert(currenth);
00660   }
00661 
00662   // compute complete set of forbidden states
00663   forbidden = rSpecGen.States() - ( discovered - forbidden );
00664 
00665   if (forbidden.Empty()) {
00666     FD_DF("IsControllable: controllable");
00667     return true;
00668   }
00669   else {
00670     FD_DF("IsControllable: not controllable");
00671     return false;
00672   }
00673 }
00674 
00675 } // namespace faudes

libFAUDES 2.16b --- 2010-9-8 --- c++ source docu by doxygen 1.6.3