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
const TaIndexSet< DiagLabelSet > & DiagnoserStateMap(void) const
void AddStateLabelMap(Idx gstate, const DiagLabelSet &labels)
NameSet::Iterator Iterator
bool Empty(void) const
bool Exists(const Idx &rIndex) const
bool Insert(const Idx &rIndex)
Idx Arg1State(Idx s12) const
Iterator Begin(void) const
Iterator End(void) const
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Definition: cfl_transset.h:273
virtual void Clear(void)
bool InsEvent(Idx index)
const TaStateSet< StateAttr > & States(void) const
const TaEventSet< EventAttr > & Alphabet(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
void StateAttribute(Idx index, const StateAttr &rAttr)
void InjectAlphabet(const EventSet &rNewalphabet)
const Attr & Attribute(const Idx &rElem) const
Definition: cfl_indexset.h:535
void ClrObservable(Idx index)
EventSet UnobservableEvents(void) const
EventSet ObservableEvents(void) const
void InsStateLabelMapping(Idx dStateIndex, Idx gStateIndex, Idx labelIndex)
void DWrite(const Type *pContext=0) const
Definition: cfl_types.cpp:226
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
Definition: cfl_types.cpp:170
void Write(const Type *pContext=0) const
Definition: cfl_types.cpp:140
StateSet::Iterator StatesBegin(void) const
StateSet::Iterator InitStatesBegin(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
EventSet ActiveEventSet(Idx x1) const
TransSet::Iterator TransRelBegin(void) const
void ClrTransition(Idx x1, Idx ev, Idx x2)
Idx InitStatesSize(void) const
void InsEvents(const EventSet &events)
bool MarkedStatesEmpty(void) const
bool ExistsTransition(const std::string &rX1, const std::string &rEv, const std::string &rX2) const
void InjectMarkedStates(const StateSet &rNewMarkedStates)
void SetInitState(Idx index)
TransSet ActiveTransSet(Idx x1) const
std::string TStr(const Transition &rTrans) const
std::string StateName(Idx index) const
StateSet::Iterator StatesEnd(void) const
TransSet::Iterator TransRelEnd(void) const
bool ExistsEvent(Idx index) const
void SetMarkedState(Idx index)
Idx InitState(void) const
bool InsEvent(Idx index)
StateSet::Iterator InitStatesEnd(void) const
void GraphWrite(const std::string &rFileName, const std::string &rOutFormat="", const std::string &rDotExec="dot") const
std::string EventName(Idx index) const
virtual void ClearAttributes(void)
bool ExistsMarkedState(Idx index) const
#define FD_DD(message)
Definition: diag_debug.h:13
bool Empty(void) const
Definition: cfl_baseset.h:1841
bool Exists(const T &rElem) const
Definition: cfl_baseset.h:2132
virtual void Clear(void)
Definition: cfl_baseset.h:1919
Iterator End(void) const
Definition: cfl_baseset.h:1913
Iterator Begin(void) const
Definition: cfl_baseset.h:1908
virtual bool Erase(const T &rElem)
Definition: cfl_baseset.h:2036
const std::string & Name(void) const
Definition: cfl_baseset.h:1772
void LanguageDiagnoser(const System &rGen, const System &rSpec, Diagnoser &rDiagGen)
void LoopPreservingObserver(const System &rGen, const EventSet &rInitialHighAlph, EventSet &rHighAlph)
bool IsLoopPreservingObserver(const System &rGen, const EventSet &rHighAlph)
void SelfLoop(Generator &rGen, const EventSet &rAlphabet)
bool ComputeScc(const Generator &rGen, const SccFilter &rFilter, std::list< StateSet > &rSccList, StateSet &rRoots)
void Parallel(const Generator &rGen1, const Generator &rGen2, Generator &rResGen)
void LanguageComplement(Generator &rGen, const EventSet &rAlphabet)
bool IsObs(const Generator &rLowGen, const EventSet &rHighAlph)
static int report(lua_State *L, int status)
Definition: luafaudes.cpp:86
uint32_t Idx
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)
bool IsLanguageDiagnosable(const System &rGen, const System rSpec, std::string &rReportString)
std::string ToStringInteger(Int number)
Definition: cfl_utils.cpp:43
void LabelPropagation(const DiagLabelSet &lastLabel, const DiagLabelSet &failureTypes, DiagLabelSet &newLabel)
bool rec_ComputeLoopPreservingObserver(const System &rGen, const EventSet &rInitialHighAlph, EventSet &rHighAlph, const std::vector< Idx > &rDiffVector, Idx numberEvents, Idx currentNumberEvents, Idx currentLocation, EventSet chosenEvents)

libFAUDES 2.33c --- 2025.05.15 --- c++ api documentaion by doxygen