syn_sscon.cpp
Go to the documentation of this file.
1 /** @file syn_sscon.cpp Standard synthesis consistency test */
2 
3 /* FAU Discrete Event Systems Library (libfaudes)
4 
5  Copyright (C) 2014 Matthias Leinfelder, Thomas Moor
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2.1 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
20 
21 
22 #include "syn_sscon.h"
23 #include <stack>
24 
25 
26 namespace faudes {
27 
28 
29 
30 
31 /*
32  ***************************************************************************************
33  ***************************************************************************************
34 
35  The core algorithm is implemented as the function IsStdSynthesisConsistentUnchecked(...)
36  The function assumes that the arguments satisfy their respecive conditions. For a
37  detailed discussion on the algorithm see
38 
39  Moor, T.: Natural projections for the synthesis of
40  non-conflicting supervisory controllers,
41  Workshop on Discrete Event Systems (WODES), Paris, 2014.
42 
43  and
44 
45  Moor, T., Baier, Ch., Wittmann, Th.:
46  Consistent abstractions for the purpose of supervisory control,
47  Proc. 52nd IEEE Conference on Decision and Control (CDC), pp. 7291-7196, Firenze, 2013.
48 
49  The initial version of this function was implemented by Matthias Leinfelder in course
50  of his bachelor thesis.
51 
52  ***************************************************************************************
53  ***************************************************************************************
54  */
55 
56 
57 //IsStdSynthesisConsistentUnchecked (rPlantGen, rPlant0Gen, rCAlph)
59  const Generator& rPlantGen,
60  const EventSet& rCAlph,
61  const Generator& rPlant0Gen) {
62 
63  // prepare: extract relevant alpahbets
64  const EventSet& sig = rPlantGen.Alphabet();
65  const EventSet& sigo = rPlant0Gen.Alphabet();
66  const EventSet& sigc = rCAlph;
67  EventSet sigco = sigc * sigo;
68  EventSet siguc = sig - sigc;
69 
70  // prepare: construct rich plant representation by parallel composition with abstraction
71  // (implementation of Paralle guarantees a trim result --- we rely on this)
72  Generator gg0;
73  ProductCompositionMap gg0pmap;
74  Parallel(rPlantGen,rPlant0Gen,gg0pmap,gg0);
75 
76  // prepare: construct a so-called trace generator with exactly the same reachable
77  // states as the rich plant gg0, but with only one path to reach each state; thus,
78  // each class of strings that reaches any particular state in gg0 has exaclty
79  // one representative string in the generated language of the trace generator
80 
81  // initialize result and prepare the todo-stack for the loop invariant "todo states
82  // are reachable in trace by exactly one path"
83  Generator trace;
84  trace.InsEvents(sig);
85  std::stack<Idx> todo;
86  todo.push(gg0.InitState());
87  trace.InsInitState(gg0.InitState());
88 
89  // forward reachability search
90  while(!todo.empty()){
91  // pick state from todo
92  Idx q = todo.top();
93  todo.pop();
94  // iterate all reachable states
95  TransSet::Iterator tit,tit_end;
96  tit = gg0.TransRelBegin(q);
97  tit_end = gg0.TransRelEnd(q);
98  for(;tit != tit_end; ++tit){
99  // by the invariant "tit->X2 not in trace" implies "tit->X2 is not on the stack"
100  if(!trace.ExistsState(tit->X2)){
101  todo.push(tit->X2);
102  trace.InsState(tit->X2);
103  trace.SetTransition(*tit);
104  }
105  }
106  }
107  // this completes the construction of the trace generator
108 
109  /*
110  rPlantGen.GraphWrite("tmp_gen.jpg");
111  rPlant0Gen.GraphWrite("tmp_gen0.jpg");
112  gg0.GraphWrite("tmp_gg0.jpg");
113  trace.GraphWrite("tmp_trace.jpg");
114  */
115 
116  // prepare: backward reach via reverse transistion relation
117  TTransSet<TransSort::X2EvX1> revtransrel;
118  gg0.TransRel().ReSort(revtransrel);
119 
120  // initialize target states by marked states
121  StateSet target = gg0.MarkedStates();
122  // provide restricted target to focus backward reach (performance gain is debateble)
123  StateSet rtarget = target;
124 
125  // grow target set by backward 'reach and test'
126  while(true) {
127  // prepare to sense when stuck / break on success
128  Idx tsz=target.Size();
129  if(tsz==gg0.Size()) break;
130 
131  // report
132  FD_DF("IsStdSynthesisConsistent(..): targets for one-transition tests: #" << target.Size());
133 
134  // inner loop to grow by fast one-transition tests first
135  while(true) {
136  // allow for user interrupt
137  FD_WPC(target.Size(),gg0.Size(),"IsStdSynthesisConsistent(): processing one-step tests");
138  // prepare to sense when stuck / break on success
139  Idx tszi=target.Size();
140  if(tszi==gg0.Size()) break;
141  // iterate over all relevant target states
142  StateSet::Iterator sit = rtarget.Begin();
143  StateSet::Iterator sit_end = rtarget.End();
144  while(sit != sit_end){
145  Idx x2=*sit;
146  FD_DF("IsStdSynthesisConsistent(..): testing predecessors of target " << gg0.StateName(x2));
147  // sense if all predecessors pass
148  bool allpass=true;
149  // iterate over all target predecessors
150  TTransSet<TransSort::X2EvX1>:: Iterator rit =revtransrel.BeginByX2(x2);
151  TTransSet<TransSort::X2EvX1>:: Iterator rit_end=revtransrel.EndByX2(x2);
152  for(;rit != rit_end; ++rit){
153  // predecessor technically passes if allready identified as target
154  if(target.Exists(rit->X1)) continue;
155  // test A and B from [ref2]: passes if uncontrollable/unobservable event leads to the target
156  if(siguc.Exists(rit->Ev)) {
157  target.Insert(rit->X1);
158  rtarget.Insert(rit->X1);
159  FD_DF("IsStdSynthesisConsistent(..): one-transition test AB passed: " << gg0.StateName(rit->X1));
160  continue;
161  }
162  // test C adapted from [ref2]: predecessor passes if abstraction state is not marked and all successors lead to the target
163  if(!rPlant0Gen.ExistsMarkedState(gg0pmap.Arg2State(rit->X1))){
164  if(gg0.SuccessorStates(rit->X1) <= target) {
165  target.Insert(rit->X1);
166  rtarget.Insert(rit->X1);
167  FD_DF("IsStdSynthesisConsistent(..): one-transition test C passed: " << gg0.StateName(rit->X1));
168  continue;
169  }
170  }
171  // record the fail
172  allpass=false;
173  }
174  // safely increment sit
175  ++sit;
176  // if all predecessors passed we can restrict the backward search
177  if(allpass) {
178  FD_DF("IsStdSynthesisConsistent(..): all predecessors of " << gg0.StateName(x2) << " have passed");
179  rtarget.Erase(x2);
180  }
181  }
182  // break inner loop when stuck
183  if(target.Size()==tszi) break;
184  }
185 
186  // break on success
187  if(target.Size()==gg0.Size()) break;
188 
189  FD_DF("IsStdSynthesisConsistent(..): targets for multi-transition tests: #" << target.Size());
190  // iterate over all relevant target states to apply the multi-transition test until success
191  bool onepass=false;
192  StateSet::Iterator sit = rtarget.Begin();
193  StateSet::Iterator sit_end = rtarget.End();
194  for(; (!onepass) && (sit != sit_end); ++sit){
195  // iterate over all target predecessors
196  TTransSet<TransSort::X2EvX1>:: Iterator rit =revtransrel.BeginByX2(*sit);
197  TTransSet<TransSort::X2EvX1>:: Iterator rit_end=revtransrel.EndByX2(*sit);
198  for(; (!onepass) && (rit != rit_end); ++rit){
199  // cannot gain target if predecessor is already identified
200  if(target.Exists(rit->X1)) continue;
201  // allow for user interrupt
202  FD_WPC(target.Size(),gg0.Size(),"IsStdSynthesisConsistent(): processing star-step tests");
203 
204  // prepare tests D/E from [ref2]/[ref1]
205 
206  // Ls: a) s
207  Generator Ls(trace);
208  Ls.SetMarkedState(rit->X1);
209  // Ls: b) s . sig^* --- all future of s
210  Ls.ClrTransitions(rit->X1);
211  SelfLoopMarkedStates(Ls,sig);
212  // Ms: a) M --- all successful future of s
213  Generator Ms=gg0;
214  Ms.InjectMarkedStates(target);
215  // Ms: b) Ls . M
216  LanguageIntersection(Ls,Ms,Ms);
217  // M0s: projection of Ms --- all successful future of s from the perspective of the abstraction
218  Generator M0s;
219  Project(Ms,sigo,M0s);
220  // Es0: a) Ms0 . sigo^* --- evil specification to prevent succesful future of s
221  Generator E0s=M0s;
222  StateSet::Iterator ssit = E0s.MarkedStatesBegin();
223  StateSet::Iterator ssit_end = E0s.MarkedStatesEnd();
224  for(; ssit!=ssit_end; ++ssit)
225  E0s.ClrTransitions(*ssit);
226  SelfLoopMarkedStates(E0s,sigo);
227  // Es0: b) L0 - M0s . sigo^*
228  LanguageDifference(rPlant0Gen,E0s,E0s);
229  Trim(E0s);
230 
231  // apply test D: does reachability of X1 contradict with the evil specification ?
232  Generator Es=E0s;
233  InvProject(Es,sig);
234  PrefixClosure(Es);
235  if(EmptyLanguageIntersection(Ls,Es)) {
236  // pass: evil specification renders X1 unreachable
237  FD_DF("IsStdSynthesisConsistent(..): multi-transition test D passed: " << gg0.StateName(rit->X1));
238  onepass=true;
239  target.Insert(rit->X1);
240  rtarget.Insert(rit->X1);
241  continue;
242  }
243 
244  // apply test E: use the supremal evil supervisor to test whether reachability of X1 complies with E0s
245  Generator K0s;
246  SupRelativelyPrefixClosed(rPlant0Gen,E0s,E0s);
247  SupConNB(rPlant0Gen,sigco,E0s,K0s);
248  // test whether X1 is reachable under evil supervision
249  Generator Ks=K0s;
250  InvProject(Ks,sig);
251  PrefixClosure(Ks);
252  Product(Ls,Ks,Ks);
253  if(EmptyLanguageIntersection(Ls,Ks)) {
254  // pass: evil supervisor renders X1 unreachable
255  FD_DF("IsStdSynthesisConsistent(..): multi-transition test E passed: " << gg0.StateName(rit->X1));
256  onepass=true;
257  target.Insert(rit->X1);
258  rtarget.Insert(rit->X1);
259  continue;
260  }
261 
262  } // iterate target predecessors
263  } // iterate targets
264 
265  // break outer loop if tests D/E did not gain one more target
266  if(!onepass) break;
267 
268  // break outer loop if tests A/B are stuck
269  if(target.Size()==tsz) break;
270  if(target.Size()==gg0.Size()) break;
271  }
272 
273  // return success
274  return target.Size()==gg0.Size();
275 }
276 
277 
278 
279 
280 /*
281  ***************************************************************************************
282  ***************************************************************************************
283 
284  Application Interface
285 
286  ***************************************************************************************
287  ***************************************************************************************
288  */
289 
290 
291 // IsStdSynthesisConsistent(rPlantGen, rCAlph, rPlant0Gen)
293  const Generator& rPlantGen,
294  const EventSet& rCAlph,
295  const Generator& rPlant0Gen)
296 {
297  // test if the plant is deterministic
298  if(!IsDeterministic(rPlantGen)){
299  std::stringstream errstr;
300  errstr << "Plant generator must be deterministic, " << "but is nondeterministic";
301  throw Exception("IsStdSynthesisConsistent", errstr.str(), 501);
302  }
303  // test if the Alphabet with the controllable events matches the Alphabet of the Generator
304  if(! (rCAlph <= rPlant0Gen.Alphabet()) ){
305  std::stringstream errstr;
306  errstr << "Controllable events must be a subset of the abstraction alphabet specified by \"" << rPlant0Gen.Name() << "\"";
307  throw Exception("IsStdSynthesisConsistent", errstr.str(), 506);
308  }
309  // test if the abstraction alphabet matches the plant alphabet
310  const EventSet& sigo = rPlant0Gen.Alphabet();
311  if(! (sigo <= rPlantGen.Alphabet() ) ){
312  std::stringstream errstr;
313  errstr << "Abstraction alphabet must be a subset of the plant alphabet pescified by \"" << rPlantGen.Name() << "\"";
314  throw Exception("IsStdSynthesisConsistent", errstr.str(), 506);
315  }
316 
317  // test the consistency of the plant
318  return IsStdSynthesisConsistentUnchecked(rPlantGen,rCAlph,rPlant0Gen);
319 }
320 
321 
322 // IsStdSynthesisConsistent(rPlantGen,rPlant0Gen)
324  const System& rPlantGen,
325  const Generator& rPlant0Gen)
326 {
327  // extract controllable events
328  const EventSet& calph = rPlantGen.ControllableEvents();
329  // pass on
330  return IsStdSynthesisConsistent(rPlantGen,calph,rPlant0Gen);
331 }
332 
333 
334 } // name space

libFAUDES 2.26g --- 2015.08.17 --- c++ api documentaion by doxygen