diag_languagediagnosis.cpp
Go to the documentation of this file.
1 /** @file diag_languagediagnosis.cpp
2 Functions to check a system's language-diagnosability and compute a language-diagnoser.
3 
4 (c) 2009, Tobias Barthel, Thomas Moor, Klaus Schmidt.
5 */
6 
8 
9 using namespace std;
10 
11 namespace faudes {
12 
13 
14 ///////////////////////////////////////////////////////////////////////////////
15 // Functions for specification framework
16 ///////////////////////////////////////////////////////////////////////////////
17 
18 
19 // rti function interface
20 bool IsLanguageDiagnosable(const System& rGen, const System& rSpec) {
21  std::string ignore;
22  return IsLanguageDiagnosable(rGen,rSpec,ignore);
23 }
24 
25 
26 // ComputeGobs()
27 void ComputeGobs(const System& rGenMarkedNonSpecBehaviour, Diagnoser& rGobs) {
28  EventSet gObservableEvents, gUnobservableEvents;
29  StateSet newGobsStates;
30  Idx currDState = 0;
31  Idx nextDState = 0;
32  Idx gStateEstimate = 0;
33  Idx newState = 0;
34  map<Idx,multimap<Idx,DiagLabelSet> > reachMap; // maps executable events to all reachable states and occuring relative failure types
35  map<Idx,multimap<Idx,DiagLabelSet> >::iterator it;
36  multimap<Idx,DiagLabelSet>::iterator mmit, mmit2;
37  pair<Idx,DiagLabelSet> reachMapPair;
38  TransSet transitions;
39  DiagLabelSet oldLabel, newLabel, occFailureTypes;
40  DiagLabelSet::Iterator labelIt;
41  StateSet gObsStates;
42  StateSet::Iterator stateIt, initStateIt;
43  EventSet activeEvents;
45  const TaIndexSet<DiagLabelSet>* pDiagState;
46 
47  FD_DD("ComputeGobs()");
48 
49  // clear Gobs
50  rGobs.Clear();
51  rGobs.ClearAttributes();
52 
53  // get observable events of original generator
54  gObservableEvents = rGenMarkedNonSpecBehaviour.ObservableEvents();
55  FD_DD( "Observable events: " << gObservableEvents.ToString() );
56 
57  // get unobservable events of original generator
58  gUnobservableEvents = rGenMarkedNonSpecBehaviour.UnobservableEvents();
59  FD_DD( "Unobservable events: " << gUnobservableEvents.ToString() );
60 
61  // parse through init states of rGenMarkedNonSpecBehaviour
62  for (initStateIt = rGenMarkedNonSpecBehaviour.InitStatesBegin(); initStateIt != rGenMarkedNonSpecBehaviour.InitStatesEnd(); initStateIt++) {
63  newGobsStates.Clear();
64  newLabel.Clear();
65  newAttr.Clear();
66 
67  // create newAttr with state index of current initial state of rGenMarkedNonSpecBehaviour and label "N"
68  newLabel.Insert(DiagLabelSet::IndexOfLabelN());
69  newAttr.AddStateLabelMap(*initStateIt,newLabel);
70 
71  // if newAttr equals any existing state attribute then use this state and make it an initial state
72  gObsStates = rGobs.States();
73  stateIt = gObsStates.Begin();
74  while (stateIt != gObsStates.End()) {
75  if (newAttr == rGobs.StateAttribute(*stateIt)) {
76  FD_DD("Statelabel " << *initStateIt << "N already exists at state " << *stateIt << " --> make it init state.");
77  rGobs.SetInitState(*stateIt);
78  break;
79  }
80  stateIt++;
81  }
82  // if newAttribute is new to Gobs
83  if (stateIt == gObsStates.End()) {
84  // create new initial state of Gobs and its attribute with label "normal"
85  currDState = rGobs.InsInitState();
86  rGobs.StateAttribute(currDState, newAttr);
87  newGobsStates.Insert(currDState);
88  }
89 
90  // parse through new Gobs states
91  while (!newGobsStates.Empty()) {
92  // set current Gobs state
93  currDState = *newGobsStates.Begin();
94 
95  // get unique state estimate and unique failure label from Gobs
96  pDiagState = rGobs.StateAttribute(currDState).DiagnoserStateMapp();
97  gStateEstimate = *(pDiagState->Begin());
98  oldLabel = pDiagState->Attribute(*(pDiagState->Begin()));
99 
100  // generate reachMap for current state estimate
101  ComputeReachability(rGenMarkedNonSpecBehaviour, gUnobservableEvents, gStateEstimate, reachMap);
102 
103 
104 #ifdef FAUDES_DEBUG_DIAGNOSIS
105  FD_DD("reachMap: ");
106  for (it = reachMap.begin(); it != reachMap.end(); it++) {
107  //print reachMap for current event
108  FD_DD("_" << rGenMarkedNonSpecBehaviour.EventName(it->first) << " ("<< it->second.size() << " state estimates)");
109  for (mmit = it->second.begin(); mmit != it->second.end(); mmit++) {
110  FD_DD(mmit->first << " " << mmit->second.ToString());
111  }
112  }
113 #endif
114 
115  // parse through reachMap (eventwise)
116  for (it = reachMap.begin(); it != reachMap.end(); it++) {
117 #ifdef FAUDES_DEBUG_DIAGNOSIS
118  // print reachMap for current event
119  FD_DD("Parsing reachMap: " << "_" << rGenMarkedNonSpecBehaviour.EventName(it->first));
120  for (mmit = it->second.begin(); mmit != it->second.end(); mmit++) {
121  FD_DD(mmit->first << " " << mmit->second.ToString());
122  }
123  #endif
124 
125  FD_DD("old label: " << oldLabel.ToString());
126 
127  newState = 0;
128  // parse through state failure type map (for current event in reachMap)
129  for (mmit = it->second.begin(); mmit != it->second.end(); mmit++) {
130  newState = mmit->first;
131  FD_DD("new state: " << newState);
132  occFailureTypes = mmit->second;
133  FD_DD("failure types occurred: " << occFailureTypes.ToString());
134  LabelPropagation(oldLabel, occFailureTypes, newLabel);
135  FD_DD("new label: " << newLabel.ToString());
136  newAttr.Clear();
137  newAttr.AddStateLabelMap(newState,newLabel);
138 
139  // if newAttr equals any existing state attribute then we create a transition to this very state
140  gObsStates = rGobs.States();
141  stateIt = gObsStates.Begin();
142  while (stateIt != gObsStates.End()) {
143  if (newAttr == rGobs.StateAttribute(*stateIt)) {
144  FD_DD("realising as back- or self-loop to existing state " << *stateIt);
145  if (!rGobs.ExistsTransition(currDState,it->first,*stateIt)) {
146  if (!rGobs.ExistsEvent(it->first)) {
147  rGobs.InsEvent(it->first);
148  }
149  rGobs.SetTransition(currDState,it->first,*stateIt);
150  }
151  break;
152  }
153  stateIt++;
154  }
155  // if newAttribute is new to Gobs
156  if (stateIt == gObsStates.End()) {
157  // create new Gobs state and add it to new states
158  nextDState = rGobs.InsState();
159  FD_DD("Create new state " << nextDState << " and transition " << currDState << " --" << rGenMarkedNonSpecBehaviour.EventName(it->first) << "--> " << nextDState);
160  newGobsStates.Insert(nextDState);
161  rGobs.InsEvent(it->first);
162  rGobs.SetTransition(currDState,it->first,nextDState);
163 
164  //rGobs.InsStateLabelMap(nextDState,newState,newLabel);
165  rGobs.StateAttribute(nextDState, newAttr);
166  }
167  }
168  }
169 
170  activeEvents = rGobs.ActiveEventSet(currDState);
171  transitions = rGobs.ActiveTransSet(currDState);
172 
173  // delete current Gobs state from new states
174  newGobsStates.Erase(currDState);
175  }
176  }
177 }
178 
179 // ComputeReachability()
180 void ComputeReachability(const System& rGen, const EventSet& rUnobsEvents, Idx State,
181  map<Idx,multimap<Idx,DiagLabelSet> >& rReachabilityMap) {
182 
183  FD_DD("ComputeReachability() for state " << State << "...");
184  StateSet doneStates;
185 
186  doneStates.Clear();
187  rReachabilityMap.clear();
188  ComputeReachabilityRecursive(rGen, rUnobsEvents, State, doneStates, rReachabilityMap);
189  FD_DD("ComputeReachability for state " << State << ": done");
190 
191  #ifdef FAUDES_DEBUG_DIAGNOSIS
192  map<Idx,multimap<Idx,DiagLabelSet> >::iterator it;
193  multimap<Idx,DiagLabelSet>::iterator mmLabelIt;
194  FD_DD("rReachabilityMap: ");
195  for (it = rReachabilityMap.begin(); it != rReachabilityMap.end(); it++) {
196  // print rReachabilityMap for current event
197  FD_DD("_" << rGen.EventName(it->first) << " ("<< it->second.size() << " state estimates)");
198  for (mmLabelIt = it->second.begin(); mmLabelIt != it->second.end(); mmLabelIt++) {
199  FD_DD(mmLabelIt->first << " " << mmLabelIt->second.ToString());
200  }
201  }
202  FD_DD("");
203  #endif
204 }
205 
206 // ComputeReachabilityRecursive()
207 void ComputeReachabilityRecursive(const System& rGen, const EventSet& rUnobsEvents, Idx State, StateSet done,
208  map<Idx,multimap<Idx,DiagLabelSet> >& rReachabilityMap) {
209  TransSet trans;
210  TransSet::Iterator tIt;
211  EventSet tmpFailureSet;
212  EventSet::Iterator evIt;
213  multimap<Idx,DiagLabelSet> stateFailureTypeMap; // maps generator states onto occurred failures types (=labels), part of rReachabilityMap
214  multimap<Idx,DiagLabelSet>::iterator mmLabelIt;
215  map<Idx,multimap<Idx,DiagLabelSet> >::iterator it;
216  DiagLabelSet newFT;
217  bool mappingExists;
218 
219  if (done.Exists(State)) {
220  FD_DD( "State " << State << " has already been processed." );
221  return;
222  }
223  trans = rGen.ActiveTransSet(State);
224 
225  FD_DD("ComputeReachabilityRecursive() for state " << State << ": Events in ActiveTransSet: ");
226  // parse through active transitions of current generator state
227  for (tIt = trans.Begin(); tIt != trans.End(); tIt++) {
228  FD_DD(tIt->X1 << "--" << rGen.EventName(tIt->Ev) << "-->" << tIt->X2);
229  // if current event is unobservable
230  if (rUnobsEvents.Exists(tIt->Ev)) {
231  // call ComputeReachabilityRecursive for successor state
232  done.Insert(tIt->X1);
233  ComputeReachabilityRecursive(rGen, rUnobsEvents, tIt->X2, done, rReachabilityMap);
234  }
235  // if current event is observable add failure (spec violation) to rReachabilityMap
236  else {
237  FD_DD(rGen.EventName(tIt->Ev) << " is observable: add it to rReachabilityMap ");
238  // get old entry of rReachabilityMap if it exists
239  stateFailureTypeMap.clear();
240  if (rReachabilityMap.find(tIt->Ev) != rReachabilityMap.end()) {
241  stateFailureTypeMap = rReachabilityMap[tIt->Ev];
242 #ifdef FAUDES_DEBUG_DIAGNOSIS
243  FD_DD("old entry of rReachabilityMap for " << rGen.EventName(tIt->Ev));
244  for (mmLabelIt = stateFailureTypeMap.begin(); mmLabelIt != stateFailureTypeMap.end(); mmLabelIt++) {
245  FD_DD(mmLabelIt->first << " " << mmLabelIt->second.ToString());
246  }
247 #endif
248  }
249  newFT.Clear();
250  // if successor state is marked: add failure label
251  if (rGen.ExistsMarkedState(tIt->X2)) {
252  newFT.Insert(DiagLabelSet::IndexOfLabelSpecViolated());
253  }
254  // if no failure occurred add normal label
255  if (newFT.Empty()) {
256  newFT.Insert(DiagLabelSet::IndexOfLabelRelN());
257  }
258  // check if new mapping does already exist
259  mappingExists = false;
260  for (mmLabelIt = stateFailureTypeMap.lower_bound(tIt->X2); mmLabelIt != stateFailureTypeMap.upper_bound(tIt->X2); mmLabelIt++) {
261  if (mmLabelIt->second == newFT) {
262  mappingExists = true;
263  }
264  }
265  // if new mapping does not yet exist: add it to rReachabilityMap
266  if (!mappingExists) {
267  stateFailureTypeMap.insert(pair<Idx,DiagLabelSet>(tIt->X2,newFT));
268  rReachabilityMap[tIt->Ev] = stateFailureTypeMap;
269  }
270  }
271  }
272 }
273 
274 // ComputeLanguageDiagnoser()
275 void LanguageDiagnoser(const System& rGen, const System& rSpec, Diagnoser& rDiagGen) {
276  System genMarkedNonSpecBehaviour, specComplement;
277  Diagnoser genGobs;
278 
279  FD_DD("LanguageDiagnoser()");
280 
281  // copy const arguments
282  System gen = rGen;
283  System spec = rSpec;
284 
285  // prepare result
286  rDiagGen.Clear();
287 
288  // mark all states in generator and specification
289  StateSet::Iterator sit;
290  for (sit = gen.StatesBegin(); sit != gen.StatesEnd(); sit++)
291  gen.SetMarkedState(*sit);
292  for (sit = spec.StatesBegin(); sit != spec.StatesEnd(); sit++)
293  spec.SetMarkedState(*sit);
294 
295  // lift spec to same alphabet (insert missing events)
296  EventSet diffEventsGenAndSpec = gen.Alphabet() - spec.Alphabet();
297  FD_DD("diffEventsGenAndSpec: " << diffEventsGenAndSpec.ToString() );
298  spec.InsEvents(diffEventsGenAndSpec);
299 
300  // figure failure behaviour Gtilde= Closure(G) ^ Complement(Closure(Specification))
301  // technical note: to obtain a diagnoser that refers to G state indicees, we use the reverse
302  // composition map to track the correspondance to the original state space.
303  specComplement = spec;
304  LanguageComplement(specComplement);
305  ProductCompositionMap rcmap;
306  Parallel(gen, specComplement, rcmap, genMarkedNonSpecBehaviour);
307 
308  genMarkedNonSpecBehaviour.ClrObservable(gen.UnobservableEvents());
309 #ifdef FAUDES_DEBUG_DIAGNOSIS
310  genMarkedNonSpecBehaviour.GraphWrite("tmp_wrtb_Gtilde_spec.png");
311  genMarkedNonSpecBehaviour.Write("tmp_wrtb_Gtilde_spec.gen");
312 #endif
313 
314  // bail out trivial case "no failures"
315  if (genMarkedNonSpecBehaviour.MarkedStatesEmpty()) {
316  rDiagGen.InjectAlphabet(gen.ObservableEvents());
317  Idx dstate = rDiagGen.InsInitState();
318  // TODO: loop over all possible states
319  rDiagGen.InsStateLabelMapping(dstate,rGen.InitState(),DiagLabelSet::IndexOfLabelN());
320  SelfLoop(rDiagGen,gen.ObservableEvents());
321  return;
322  }
323 
324  // compute the observer, i.e. non-deterministic basis for diagnoser
325  ComputeGobs(genMarkedNonSpecBehaviour, genGobs);
326 
327 #ifdef FAUDES_DEBUG_DIAGNOSIS
328  genGobs.GraphWrite("tmp_wrtb_gobs.png");
329 #endif
330 
331 
332  // post process
333  // We construct a deterministic diagnoser from the non-deterministic GObs by
334  // parsing the transition structure of GObs and merging possible diagnosis
335  // labels.
336 
337  // have all observable events
338  rDiagGen.InjectAlphabet(gen.ObservableEvents());
339 
340 
341  // create initial state of diagnoser and its attribute with label "normal"
342 #ifdef FAUDES_CHECKED
343  if(genGobs.InitStatesSize() != 1) {
344  std::stringstream errstr;
345  errstr << "Diagnosis: Internal Error: Go must have one initial state only" << std::endl;
346  throw Exception("LanguageDiagnoser()", errstr.str(), 301);
347  }
348 #endif
349  Idx gInitState = genGobs.InitState();
350  Idx dInitState = rDiagGen.InsInitState();
351  rDiagGen.InsStateLabelMapping(dInitState,gInitState,DiagLabelSet::IndexOfLabelN());
352 
353  // track state correspondence (map diagnoser states to genObs states)
354  std::multimap<Idx,Idx> dgmap;
355  dgmap.insert(std::pair<Idx,Idx>(dInitState,gInitState));
356 
357  // loop variables
358  EventSet activeEvents;
359  AttributeDiagnoserState newDAttr;
360 
361  // parse through gObsStates states
362  StateSet dStates;
363  dStates.Insert(dInitState);
364  while (!dStates.Empty()) {
365  // set current diagnoser state
366  Idx dstate = *dStates.Begin();
367  // prepare reachmap: ev -> gSuccessors
368  std::multimap<Idx,Idx> gSuccessors;
369  // iterate over corresponding genObs States
370  std::multimap<Idx,Idx>::iterator gsit= dgmap.lower_bound(dstate);
371  std::multimap<Idx,Idx>::iterator gsit_end= dgmap.upper_bound(dstate);
372  for(;gsit!=gsit_end; gsit++) {
373  Idx gState = gsit->second;
374  // iterate over all successors
375  TransSet::Iterator tit= genGobs.TransRelBegin(gState);
376  TransSet::Iterator tit_end= genGobs.TransRelEnd(gState);
377  for(; tit!=tit_end; tit++)
378  gSuccessors.insert(std::pair<Idx,Idx>(tit->Ev,tit->X2));
379  }
380  // per event, accumulate estimates
381  gsit= gSuccessors.begin();
382  gsit_end= gSuccessors.end();
383  std::multimap<Idx,Idx>::iterator gsit_beg= gsit;
384  newDAttr.Clear();
385  while(gsit!=gsit_end) {
386  Idx ev= gsit->first;
387  // TODO: need merge method for diagnoser estimates
388  const AttributeDiagnoserState sestimate= genGobs.StateAttribute(gsit->second);
389  StateSet::Iterator lit=sestimate.DiagnoserStateMap().Begin();
390  StateSet::Iterator lit_end=sestimate.DiagnoserStateMap().End();
391  for(; lit!=lit_end; lit++) {
392  //newDAttr.AddStateLabelMap(*lit, sestimate.DiagnoserStateMap().Attribute(*lit));
393  newDAttr.AddStateLabelMap(rcmap.Arg1State(*lit), sestimate.DiagnoserStateMap().Attribute(*lit));
394  }
395  // increment
396  gsit++;
397  // sense new event to set label
398  bool nextev=false;
399  if(gsit== gsit_end) nextev=true;
400  if(gsit!= gsit_end) if(gsit->first!=ev) nextev=true;
401  if(!nextev) continue;
402  // insert new diag state set attribute
403  // case 1: attribute exists, so use the corresponding diagnoser state
404  // note: rather hold a map rather than to iterate over all attributes
405  StateSet::Iterator sit= rDiagGen.StatesBegin();
406  StateSet::Iterator sit_end= rDiagGen.StatesEnd();
407  for(; sit!=sit_end; sit++) {
408  if(!(newDAttr == rDiagGen.StateAttribute(*sit))) continue;
409  FD_DD("LanguageDiagnoser(): insert diag transition " << rDiagGen.TStr(Transition(dstate,ev,*sit)));
410  rDiagGen.SetTransition(dstate,ev,*sit);
411  break;
412  }
413  // case 2: attribute does not exist, so insert new diagnoser state
414  if(sit==sit_end) {
415  // insert new dstate
416  Idx newDState=rDiagGen.InsState();
417  dStates.Insert(newDState);
418  rDiagGen.StateAttribute(newDState,newDAttr);
419  FD_DD("LanguageDiagnoser(): insert state with attr " << newDAttr.Str());
420  // track corresponding gstates
421  std::multimap<Idx,Idx>::iterator gesit= gsit_beg;
422  for(;gesit!=gsit;gesit++) {
423  FD_DD("LanguageDiagnoser(): corresponding gstate " << gesit->second);
424  dgmap.insert(std::pair<Idx,Idx>(newDState,gesit->second));
425  }
426  // insert transition
427  FD_DD("LanguageDiagnoser(): insert diag transition " << rDiagGen.TStr(Transition(dstate,ev,newDState)));
428  rDiagGen.SetTransition(dstate,ev,newDState);
429  }
430  // initialise per event variables in multimap loop
431  gsit_beg=gsit;
432  newDAttr.Clear();
433  }
434  // delete current state from todo list
435  dStates.Erase(dstate);
436  }
437 
438 #ifdef FAUDES_DEBUG_DIAGNOSIS
439  rDiagGen.GraphWrite("tmp_wrtb_diag.png");
440 #endif
441 }
442 
443 
444 // IsLanguageDiagnosable
445 bool IsLanguageDiagnosable(const System& rGen, const System rSpec, std::string& rReportString){
446  FD_DD("IsLanguageDiagnosable()");
447  EventSet obsEvents = rGen.ObservableEvents();
448 #ifdef FAUDES_DEBUG_DIAGNOSIS
449  obsEvents.DWrite();
450 #endif
451  Generator verifier; // Graph for diagnosability verification
452  Idx nullEvent = verifier.InsEvent("nullEvent"); // event that corresponds to the value 0
453  Idx negEvent = verifier.InsEvent("negEvent"); // event that corresponds to the value -1
454  //Generator verifierTest; // verifier with eeent information
455  //verifierTest.InjectAlphabet(rGen.Alphabet() ); // FIXME remove this.
456  //verifierTest.InsEvent(nullEvent);
457  map<Idx, VerifierState> stateToVerifierMap;
458  map<VerifierState, Idx> verifierToStateMap;
459  stack<pair<Idx, VerifierState> > waitingStates;
460  StateSet doneStates;
461  // initialize the algorithm
462  EventSet fullAlphabet = rGen.Alphabet();
463  EventSet::Iterator eIt, eEndIt;
464  eEndIt = fullAlphabet.End();
465  Idx newState = verifier.InsInitState();
466  //verifierTest.InsInitState(newState);
467  VerifierState newVerifierState = VerifierState(rSpec.InitState(), rSpec.InitState(), rGen.InitState(),NORMAL);
468  stateToVerifierMap[newState] = newVerifierState;
469  verifierToStateMap[newVerifierState ] = newState;
470  waitingStates.push(make_pair(newState, newVerifierState) );
471  // extend the verifier graph until no new nodes can be added
472  pair<Idx, VerifierState> currentState;
473  Idx blockingState; // = verifier.InsMarkedState();
474  TransSet::Iterator tIt;
475  map<VerifierState, Idx>::const_iterator vsIt;
476  Idx X2;
477  bool block = false; // set to true if the BLOCK state is reachable
478  FD_DD("Main loop");
479  while(waitingStates.empty() == false){
480  // take the first element from the stack
481  currentState = waitingStates.top();
482  waitingStates.pop();
483  doneStates.Insert(currentState.first);
484  FD_DD("currentState: " + ToStringInteger(currentState.first) + " VerifierState: (" + rSpec.StateName(currentState.second.mSpec1State) + "," + rSpec.StateName(currentState.second.mSpec2State) + "," + rGen.StateName(currentState.second.mPlantState) + "," + ToStringInteger(currentState.second.mLabel) + ")");
485  // go over all possible events
486  eIt = fullAlphabet.Begin();
487  for(; eIt != eEndIt; eIt++){
488  // if the event is not observable, the specification and the plant can evolve independently
489  if(obsEvents.Exists(*eIt) == false){
490  tIt = rSpec.TransRelBegin(currentState.second.mSpec1State,*eIt);
491  // transition in Spec1 exists
492  if(tIt != rSpec.TransRelEnd(currentState.second.mSpec1State,*eIt) ){
493  if(currentState.second.mLabel == NORMAL ){ // transition in spec1 from normal state
494  newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, currentState.second.mPlantState, NORMAL);
495  }
496  else // transition in spec1 from confused state
497  newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, currentState.second.mPlantState, CONFUSED);
498  // check if the new VerifierState already exist snd insert new transitions (rule 1 and 4)
499  vsIt = verifierToStateMap.find(newVerifierState);
500  // a new state is inserted into the verifier
501  if(vsIt == verifierToStateMap.end() ){
502  newState = verifier.InsState();
503  //verifierTest.InsState(newState);
504  verifier.SetTransition(currentState.first,nullEvent,newState);
505  //verifierTest.SetTransition(currentState.first,*eIt,newState);
506  verifierToStateMap[newVerifierState] = newState;
507  stateToVerifierMap[newState] = newVerifierState;
508  if(doneStates.Exists(newState) == false)
509  waitingStates.push(make_pair(newState,newVerifierState) );
510  }
511  // a transition to the existing state is added
512  else{
513  //verifierTest.SetTransition(currentState.first,*eIt,vsIt->second);
514  verifier.SetTransition(currentState.first,nullEvent,vsIt->second);
515 
516  }
517  }
518  tIt = rGen.TransRelBegin(currentState.second.mPlantState,*eIt);
519  // transition in plant exists
520  if(tIt != rGen.TransRelEnd(currentState.second.mPlantState,*eIt) ){
521  X2 = tIt->X2;
522  if(currentState.second.mLabel == CONFUSED)
523  newVerifierState = VerifierState(currentState.second.mSpec1State, currentState.second.mSpec2State, X2, CONFUSED);
524  else{ // current state is NORMAL
525  tIt = rSpec.TransRelBegin(currentState.second.mSpec2State,*eIt);
526  if(tIt == rSpec.TransRelEnd(currentState.second.mSpec2State,*eIt) ){ // violation of the specification
527  newVerifierState = VerifierState(currentState.second.mSpec1State, currentState.second.mSpec2State, X2, CONFUSED);
528  }
529  else{ // correct behavior
530  newVerifierState = VerifierState(currentState.second.mSpec1State, tIt->X2, X2, NORMAL);
531  }
532  }
533  // check if a new state has to be inserted into the verifier a
534  vsIt = verifierToStateMap.find(newVerifierState);
535  // a new state is inserted into the verifier
536  if(vsIt == verifierToStateMap.end() ){
537  newState = verifier.InsState();
538  //verifierTest.InsState(newState);
539  verifierToStateMap[newVerifierState] = newState;
540  stateToVerifierMap[newState] = newVerifierState;
541  if(doneStates.Exists(newState) == false)
542  waitingStates.push(make_pair(newState,newVerifierState) );
543  }
544  else
545  newState = vsIt->second;
546  // new transition in the verifier
547  if(newVerifierState.mLabel == NORMAL || (currentState.second.mLabel == CONFUSED && newVerifierState.mPlantState == currentState.second.mPlantState) ){ // normal behavior or confused behavior extended in the specification (rule 3 or 4)
548  //verifierTest.SetTransition(currentState.first,*eIt,newState);
549  verifier.SetTransition(currentState.first,nullEvent,newState);
550  }
551  else{ // faulty behavior extended in the plant (rule 5)
552  //verifierTest.SetTransition(currentState.first,*eIt,newState);
553  verifier.SetTransition(currentState.first,negEvent,newState);
554  }
555  }
556  }// (obsEvents.Exists(*eIt) == false)
557  else{
558  TransSet::Iterator plantIt, specIt;
559  Idx eventIdx;
560  tIt = rSpec.TransRelBegin(currentState.second.mSpec1State, *eIt);
561  plantIt= rGen.TransRelBegin(currentState.second.mPlantState, *eIt);
562  specIt = rSpec.TransRelBegin(currentState.second.mSpec2State, *eIt);
563  if(tIt != rSpec.TransRelEnd(currentState.second.mSpec1State, *eIt) && plantIt != rGen.TransRelEnd(currentState.second.mPlantState, *eIt) ){ // event occurs in the potentially confused specification and in the plant
564  if(currentState.second.mLabel == NORMAL && specIt != rSpec.TransRelEnd(currentState.second.mSpec2State, *eIt) ){ // no confusion (rule 6)
565  newVerifierState = VerifierState(tIt->X2, specIt->X2, plantIt->X2, NORMAL);
566  eventIdx = nullEvent;
567  }
568  else if(currentState.second.mLabel == NORMAL){// faulty behavior occurs (rule 7)
569  newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, plantIt->X2, CONFUSED);
570  eventIdx = negEvent;
571  }
572  else{ // there is already confusion (rule 8)
573  newVerifierState = VerifierState(tIt->X2, currentState.second.mSpec2State, plantIt->X2, CONFUSED);
574  eventIdx = negEvent;
575  }
576  // check if a new state has to be inserted into the verifier a
577  vsIt = verifierToStateMap.find(newVerifierState);
578  // a new state is inserted into the verifier
579  if(vsIt == verifierToStateMap.end() ){
580  newState = verifier.InsState();
581  //verifierTest.InsState(newState);
582  verifierToStateMap[newVerifierState] = newState;
583  stateToVerifierMap[newState] = newVerifierState;
584  if(doneStates.Exists(newState) == false)
585  waitingStates.push(make_pair(newState,newVerifierState) );
586  }
587  else
588  newState = vsIt->second;
589 
590  // update the verifier
591  //verifierTest.SetTransition(currentState.first,*eIt,newState);
592  verifier.SetTransition(currentState.first,eventIdx,newState);
593  }
594  }
595  }
596  // check if the Block state is reachable
597  if(rGen.TransRelBegin(currentState.second.mPlantState) == rGen.TransRelEnd(currentState.second.mPlantState) && currentState.second.mLabel == CONFUSED){
598  blockingState = verifier.InsMarkedState();
599  verifier.SetTransition(currentState.first,nullEvent,blockingState);
600  //verifierTest.InsMarkedState(blockingState);
601  //verifierTest.SetTransition(currentState.first,nullEvent,blockingState);
602  FD_DD("Blocking State Reachable");
603  block = true;
604  }
605  }
606  #ifdef FAUDES_DEBUG_DIAGNOSIS
607  verifier.GraphWrite("data/verifier.png");
608  #endif
609  //verifierTest.GraphWrite("data/verifierTest.png");
610  // Seach for cycles with "-1"-transitions (negEvent) in the verifier
611  list<StateSet> sccList;
612  StateSet rootSet;
613  // compute the strongly connected components in the verifier
614  ComputeScc(verifier,sccList,rootSet);
615  // Check if there is a "-1"-transition in any of the SCCs
616  list<StateSet>::const_iterator sccIt, sccEndIt;
617  sccIt = sccList.begin();
618  sccEndIt = sccList.end();
619  StateSet::Iterator stIt, stEndIt;
620  bool existsCycle = false;
621  for( ; sccIt != sccEndIt; sccIt++){
622 #ifdef FAUDES_DEBUG_DIAGNOSIS
623  sccIt->Write();
624 #endif
625  stIt = sccIt->Begin();
626  stEndIt = sccIt->End();
627  for(; stIt != stEndIt; stIt++){// check all states in the SCC
628  tIt = verifier.TransRelBegin(*stIt, negEvent);
629  if(tIt != verifier.TransRelEnd(*stIt, negEvent) && sccIt->Exists(tIt->X2) ){ // there is a transition with negEvent within the SCC
630  FD_DD("Confused Cycle Found");
631  existsCycle = true;
632  break;
633  }
634  }
635  if(existsCycle == true)
636  break;
637  }
638  if(block == true || existsCycle == true)
639  return false;
640  else
641  return true;
642 }
643 
644 //IsLoopPreservingObserver()
645 bool IsLoopPreservingObserver(const System& rGen, const EventSet& rHighAlph){
646  System genCopy;
647  TransSet::Iterator tit;
648  string report;
649  FD_DD("IsLoopPreservingObserver()");
650  genCopy = rGen;
651  genCopy.InjectMarkedStates(genCopy.States() );
652  // Verify if the observer condition is fulfilled
653  if(IsObs(genCopy,rHighAlph) == false){
654  FD_DD("Observer Condition violated");
655  return false;
656  }
657  FD_DD("Observer Condition fulfilled");
658  // Verify if there are loops with abstracted events
659  // delete all transitions that do not belong to local high-alphabet
660  for (tit = genCopy.TransRelBegin(); tit != genCopy.TransRelEnd();) {
661  if (rHighAlph.Exists(tit->Ev))
662  tit=genCopy.ClrTransition(tit);
663  else
664  ++tit;
665  }
666  // search for cycles in remainder automaton
667  std::list<StateSet> sccList;
668  StateSet sccRoots;
669  ComputeScc(genCopy,sccList,sccRoots);
670  std::list<StateSet>::const_iterator sIt = sccList.begin();
671  for( ; sIt != sccList.end(); sIt++){
672  if(sIt->Size() > 1){
673  #ifdef FAUDES_DEBUG_DIAGNOSIS
674  cout << "Bad states that form a cycle with abstracted events: " << endl;
675  StateSet::Iterator stIt = sIt->Begin();
676  for(; stIt != sIt->End(); stIt++)
677  cout << *stIt << " ";
678  cout << endl;
679  #endif
680  return false;
681  }
682  }
683  return true;
684 }
685 
686 
687 void LoopPreservingObserver(const System& rGen, const EventSet& rInitialHighAlph, EventSet& rHighAlph){
688  // Verify if the projection with the given initial alphabet is already a loop-preserving observer
689  rHighAlph = rInitialHighAlph;
690  rHighAlph.Name("HiAlph");
691  FD_DD("LoopPreservingObserver()");
692  if(IsLoopPreservingObserver(rGen,rHighAlph) == true)
693  return;
694 
695  // check all combinations of events from the difference set
696  EventSet diffSet = rGen.Alphabet() - rHighAlph;
697  EventSet::Iterator eIt = diffSet.Begin();
698  std::vector<Idx> diffVector;
699  for( ; eIt != diffSet.End(); eIt++) // ordered list of events in the diffSet
700  diffVector.push_back(*eIt);
701 
702  for(Idx numberEvents = 1; numberEvents <= diffVector.size(); numberEvents++){// number events that are chosen in this step
703  FD_DD("numberEvents: " + ToStringInteger(numberEvents));
704  Idx currentNumberEvents = 1; // number of events under investigation
705  Idx currentLocation = 0; // start position for the search for new events
706  EventSet chosenEvents;
707  if(rec_ComputeLoopPreservingObserver(rGen,rInitialHighAlph,rHighAlph,diffVector,numberEvents,currentNumberEvents,currentLocation,chosenEvents) == true)
708  break;
709  }
710  // fix name
711  rHighAlph.Name("HiAlph");
712 }
713 
714 // rec_ComputeLoopPreservingObserver(rGen,
715 bool rec_ComputeLoopPreservingObserver(const System& rGen, const EventSet& rInitialHighAlph, EventSet& rHighAlph, const std::vector<Idx>& rDiffVector, Idx numberEvents, Idx currentNumberEvents, Idx currentLocation, EventSet chosenEvents){
716  FD_DD("rec_ComputeLoopPreservingObserver()");
717  bool valid;
718  for(Idx i = currentLocation; i < rDiffVector.size(); i++){
719  FD_DD("currentNumberEvents: " + ToStringInteger(currentNumberEvents) + "currentLocation: " + ToStringInteger(i) + " event: " + SymbolTable::GlobalEventSymbolTablep()->Symbol(rDiffVector[i]));
720  chosenEvents.Insert(rDiffVector[i]);
721  rHighAlph = rInitialHighAlph + chosenEvents;
722  if(currentNumberEvents == numberEvents){// enough events found
723  valid = IsLoopPreservingObserver(rGen,rHighAlph);
724  if(valid == true){
725  return true;
726  }
727  }
728  else if(rDiffVector.size() - 1 - i < numberEvents - currentNumberEvents){ // not enough events left to find numberEvents
729  return false;
730  }
731  else{// go to the next level to add events
732  FD_DD("currentLevel: " + ToStringInteger(i));
733  valid = rec_ComputeLoopPreservingObserver(rGen,rInitialHighAlph,rHighAlph,rDiffVector,numberEvents,currentNumberEvents + 1,i + 1, chosenEvents);
734  if(valid == true){
735  return true;
736  }
737  }
738  chosenEvents.Erase(rDiffVector[i]);
739  }
740  return false;
741 }
742 
743 } // namespace faudes
Implements state estimates for the current status of the generator.
virtual void Clear(void)
Delete the mDiagnoserStateMap.
std::string Str(void) const
Pretty printable string of mDiagnoserStateMap.
const TaIndexSet< DiagLabelSet > & DiagnoserStateMap(void) const
Get mDiagnoserStateMap.
void AddStateLabelMap(Idx gstate, const DiagLabelSet &labels)
Add state estimates to mDiagnoserStateMap.
Implements the label representation for state estimates.
NameSet::Iterator Iterator
Convenience definition of NameSet::Iterator.
void Clear(void)
Clear mDiagLabels.
bool Insert(Idx index)
Add an element by index.
bool Empty(void) const
Check if mDiagLabels is empty.
Faudes exception class.
Set of indices.
Definition: cfl_indexset.h:78
Idx Insert(void)
Insert new index to set.
Set of indices with symbolic names.
Definition: cfl_nameset.h:69
bool Exists(const Idx &rIndex) const
Test existence of index.
bool Insert(const Idx &rIndex)
Add an element by index.
Rti-wrapper for composition maps.
Definition: cfl_parallel.h:43
Idx Arg1State(Idx s12) const
Iterator Begin(void) const
Iterator to begin of set.
Iterator End(void) const
Iterator to end of set.
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Iterator on transition.
Definition: cfl_transset.h:269
Idx InsState(void)
Add new anonymous state to generator.
virtual void Clear(void)
Clear generator data.
bool InsEvent(Idx index)
Add an existing event to alphabet by index.
const TaStateSet< StateAttr > & States(void) const
Return reference to state set.
const TaEventSet< EventAttr > & Alphabet(void) const
Return const reference to alphabet.
bool SetTransition(Idx x1, Idx ev, Idx x2)
Add a transition to generator by indices.
void StateAttribute(Idx index, const StateAttr &rAttr)
Set attribute for existing state.
void InjectAlphabet(const EventSet &rNewalphabet)
Set mpAlphabet without consistency check.
Set of indices with attributes.
Definition: cfl_indexset.h:316
const Attr & Attribute(const Idx &rElem) const
Definition: cfl_indexset.h:528
Generator with controllability attributes.
void ClrObservable(Idx index)
Mark event unobservable (by index)
EventSet UnobservableEvents(void) const
Get EventSet with unobservable events.
EventSet ObservableEvents(void) const
Get EventSet with observable events.
Provides the structure and methods to build and handle diagnosers.
void InsStateLabelMapping(Idx dStateIndex, Idx gStateIndex, Idx labelIndex)
Inserts a generator state estimate to a diagnoser state.
Triple (X1,Ev,X2) to represent current state, event and next state.
Definition: cfl_transset.h:57
void DWrite(const Type *pContext=0) const
Write configuration data to console, debugging format.
Definition: cfl_types.cpp:225
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
Write configuration data to a string.
Definition: cfl_types.cpp:169
void Write(const Type *pContext=0) const
Write configuration data to console.
Definition: cfl_types.cpp:139
Base class of all FAUDES generators.
StateSet::Iterator StatesBegin(void) const
Iterator to Begin() of state set.
StateSet::Iterator InitStatesBegin(void) const
Iterator to Begin() of mInitStates.
bool SetTransition(Idx x1, Idx ev, Idx x2)
Add a transition to generator by indices.
Idx InsMarkedState(void)
Create new anonymous state and set as marked state.
EventSet ActiveEventSet(Idx x1) const
Return active event set at state x1.
TransSet::Iterator TransRelBegin(void) const
Iterator to Begin() of transition relation.
void ClrTransition(Idx x1, Idx ev, Idx x2)
Remove a transition by indices.
Idx InitStatesSize(void) const
Get number of initial states.
void InsEvents(const EventSet &events)
Add new named events to generator.
bool MarkedStatesEmpty(void) const
Check if set of marked states are empty.
bool ExistsTransition(const std::string &rX1, const std::string &rEv, const std::string &rX2) const
Test for transition given by x1, ev, x2.
void InjectMarkedStates(const StateSet &rNewMarkedStates)
Replace mMarkedStates with StateSet given as parameter without consistency checks.
void SetInitState(Idx index)
Set an existing state as initial state by index.
TransSet ActiveTransSet(Idx x1) const
Return active transition set at state x1.
std::string TStr(const Transition &rTrans) const
Return pretty printable transition (eg for debugging)
std::string StateName(Idx index) const
State name lookup.
StateSet::Iterator StatesEnd(void) const
Iterator to End() of state set.
TransSet::Iterator TransRelEnd(void) const
Iterator to End() of transition relation.
bool ExistsEvent(Idx index) const
Test existence of event in alphabet.
Idx InsState(void)
Add new anonymous state to generator.
void SetMarkedState(Idx index)
Set an existing state as marked state by index.
Idx InitState(void) const
Return initial state.
Idx InsInitState(void)
Create new anonymous state and set as initial state.
bool InsEvent(Idx index)
Add an existing event to alphabet by index.
StateSet::Iterator InitStatesEnd(void) const
Iterator to End() of mInitStates.
void GraphWrite(const std::string &rFileName, const std::string &rOutFormat="", const std::string &rDotExec="dot") const
Produce graphical representation of this generator.
std::string EventName(Idx index) const
Event name lookup.
virtual void ClearAttributes(void)
Clear Attributes.
bool ExistsMarkedState(Idx index) const
Test existence of state in mMarkedStates.
#define FD_DD(message)
Definition: diag_debug.h:13
Functions to check a system's diagnosability with respect to a specification automaton and compute a ...
bool Empty(void) const
Test whether if the TBaseSet is Empty.
Definition: cfl_baseset.h:1824
bool Exists(const T &rElem) const
Test existence of element.
Definition: cfl_baseset.h:2115
virtual void Clear(void)
Clear all set.
Definition: cfl_baseset.h:1902
Iterator End(void) const
Iterator to the end of set.
Definition: cfl_baseset.h:1896
Iterator Begin(void) const
Iterator to the begin of set.
Definition: cfl_baseset.h:1891
virtual bool Erase(const T &rElem)
Erase element by reference.
Definition: cfl_baseset.h:2019
const std::string & Name(void) const
Return name of TBaseSet.
Definition: cfl_baseset.h:1755
void LanguageDiagnoser(const System &rGen, const System &rSpec, Diagnoser &rDiagGen)
Compute a standard diagnoser from an input generator and a specification.
void LoopPreservingObserver(const System &rGen, const EventSet &rInitialHighAlph, EventSet &rHighAlph)
Computes a loop-preserving observer with minimal state size of the abstraction.
bool IsLoopPreservingObserver(const System &rGen, const EventSet &rHighAlph)
Verifies a loop-preserving observer.
void SelfLoop(Generator &rGen, const EventSet &rAlphabet)
Self-loop all states.
bool ComputeScc(const Generator &rGen, const SccFilter &rFilter, std::list< StateSet > &rSccList, StateSet &rRoots)
Compute strongly connected components (SCC)
void Parallel(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
Parallel composition.
void LanguageComplement(Generator &rGen, const EventSet &rAlphabet)
Language complement wrt specified alphabet.
bool IsObs(const Generator &rLowGen, const EventSet &rHighAlph)
Verification of the natural observer property.
libFAUDES resides within the namespace faudes.
uint32_t Idx
Type definition for index type (allways 32bit)
void ComputeReachability(const System &rGen, const EventSet &rUnobsEvents, Idx State, map< Idx, multimap< Idx, DiagLabelSet > > &rReachabilityMap)
void ComputeReachabilityRecursive(const System &rGen, const EventSet &rUnobsEvents, Idx State, StateSet done, map< Idx, multimap< Idx, DiagLabelSet > > &rReachabilityMap)
void ComputeGobs(const System &rGenMarkedNonSpecBehaviour, Diagnoser &rGobs)
Compute G_o for a generator that marks the faulty behaviour of a plant.
bool IsLanguageDiagnosable(const System &rGen, const System rSpec, std::string &rReportString)
Test function to verify language-diagnosability.
std::string ToStringInteger(Int number)
integer to string
Definition: cfl_helper.cpp:43
void LabelPropagation(const DiagLabelSet &lastLabel, const DiagLabelSet &failureTypes, DiagLabelSet &newLabel)
Generate a new label.
bool rec_ComputeLoopPreservingObserver(const System &rGen, const EventSet &rInitialHighAlph, EventSet &rHighAlph, const std::vector< Idx > &rDiffVector, Idx numberEvents, Idx currentNumberEvents, Idx currentLocation, EventSet chosenEvents)
rec_ComputeLoopPreservingObserver(rGen, rInitialHighAlph, rHighAlph, rDdffVector, numberEvents,...

libFAUDES 2.32b --- 2024.03.01 --- c++ api documentaion by doxygen