diag_languagediagnosis.cpp
Go to the documentation of this file.
1/** @file diag_languagediagnosis.cpp
2Functions 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
9using namespace std;
10
11namespace faudes {
12
13
14///////////////////////////////////////////////////////////////////////////////
15// Functions for specification framework
16///////////////////////////////////////////////////////////////////////////////
17
18
19// rti function interface
20bool IsLanguageDiagnosable(const System& rGen, const System& rSpec) {
21 std::string ignore;
22 return IsLanguageDiagnosable(rGen,rSpec,ignore);
23}
24
25
26// ComputeGobs()
27void 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;
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"
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()
180void 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()
207void ComputeReachabilityRecursive(const System& rGen, const EventSet& rUnobsEvents, Idx State, StateSet done,
208 map<Idx,multimap<Idx,DiagLabelSet> >& rReachabilityMap) {
209 TransSet trans;
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)) {
253 }
254 // if no failure occurred add normal label
255 if (newFT.Empty()) {
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()
275void 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);
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
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;
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
445bool 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();
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()
645bool IsLoopPreservingObserver(const System& rGen, const EventSet& rHighAlph){
646 System genCopy;
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
687void 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,
715bool 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)
static Idx IndexOfLabelSpecViolated(void)
NameSet::Iterator Iterator
static Idx IndexOfLabelN(void)
static Idx IndexOfLabelRelN(void)
const std::string & Name(void) const
bool Exists(const Idx &rIndex) const
bool Insert(const Idx &rIndex)
static SymbolTable * GlobalEventSymbolTablep(void)
Iterator Begin(void) const
Iterator End(void) const
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
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
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
void Write(const Type *pContext=0) const
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
bool Exists(const T &rElem) const
virtual void Clear(void)
Iterator End(void) const
Iterator Begin(void) const
virtual bool Erase(const T &rElem)
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)
uint32_t Idx
bool IsLanguageDiagnosable(const System &rGen, const System &rSpec)
void ComputeReachability(const System &rGen, const EventSet &rUnobsEvents, const EventSet &rFailures, Idx State, const AttributeFailureTypeMap &rAttrFTMap, map< Idx, multimap< Idx, DiagLabelSet > > &rReachabilityMap)
std::string ToStringInteger(Int number)
Definition cfl_utils.cpp:43
void LabelPropagation(const DiagLabelSet &lastLabel, const DiagLabelSet &failureTypes, DiagLabelSet &newLabel)
void ComputeReachabilityRecursive(const System &rGen, const EventSet &rUnobsEvents, const EventSet &rFailures, Idx State, const AttributeFailureTypeMap &rAttrFTMap, map< Idx, multimap< Idx, DiagLabelSet > > &rReachabilityMap, const DiagLabelSet FToccurred)
void ComputeGobs(const System &rOrigGen, const string &rFailureType, const EventSet &rFailureEvents, Diagnoser &rGobs)
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.33k --- 2025.09.16 --- c++ api documentaion by doxygen