hyb_experiment.cpp
Go to the documentation of this file.
1 /** @file hyb_experiment.cpp Exhaustive experments on linear hybrid automata */
2 
3 /*
4  Hybrid systems plug-in for FAU Discrete Event Systems Library
5 
6  Copyright (C) 2017 Thomas Moor, Stefan Goetz
7 
8 */
9 
10 #include "hyb_experiment.h"
11 #include "hyb_compute.h"
12 #include "hyb_reachability.h"
13 
14 using namespace faudes;
15 
16 // consructor
18  mpRoot(0),
19  rAlphabet(alph)
20 {
21  Clear();
22 }
23 
24 // destructor
26  Clear();
27  delete mpRoot;
28 }
29 
30 // clear all
31 void Experiment::Clear(void) {
32  // free nodes
33  Iterator nit=mNodeMap.begin();
34  for(;nit!=mNodeMap.end();++nit) {
35  delete nit->second->mpStates;
36  delete nit->second;
37  }
38  mNodeMap.clear();
39  // setup root
40  mpRoot = new Node;
41  Index(mpRoot)=1;
42  mNodeMap[1]=mpRoot;
43  mLeaves.Clear();
44  mLeaves.Insert(1);
45  // aux data
46  mCost=0;
47 }
48 
49 // must set initialstates (we take ownership)
51  if(mpRoot->mpStates) Clear();
52  mpRoot->mpStates = istates;
53 }
54 
55 
56 // size
57 Idx Experiment::Size(void) const {
58  return mNodeMap.size();
59 }
60 
61 const EventSet& Experiment::Alphabet(void) const{
62  return rAlphabet;
63 }
64 
65 
66 // navigate tree, external interface
67 Idx Experiment::Root(void) const {
68  return Index(mpRoot);
69 }
71  const Node* node = NodePtr(nid);
72  if(!node) {
73  std::stringstream errstr;
74  errstr << "Node #" << nid << " unknown.";
75  throw Exception("Experiment::EnabledEvents(..)", errstr.str(), 90);
76  }
77  EventSet res;
78  Node::Iterator cit = Children(node).begin();
79  Node::Iterator cit_end = Children(node).end();
80  for(;cit!=cit_end;++cit) res.Insert(cit->first);
81  return res;
82 }
84  const Node* node = NodePtr(nid);
85  if(!node) return 0;
86  Node::Iterator cit = Children(node).find(ev);
87  if(cit==Children(node).end()) return 0;
88  return Index(cit->second);
89 }
90 bool Experiment::IsLeave(Idx nid) const {
91  const Node* node = NodePtr(nid);
92  if(!node) return false;
93  /*
94 {
95  std::stringstream errstr;
96  errstr << "Node #" << nid << " unknown.";
97  throw Exception("Experiment::IsLeave(..)", errstr.str(), 90);
98  }
99  */
100  return IsLeave(node);
101 }
102 bool Experiment::IsLock(Idx nid) const {
103  const Node* node = NodePtr(nid);
104  if(!node) {
105  std::stringstream errstr;
106  errstr << "Node #" << nid << " unknown.";
107  throw Exception("Experiment::IsLock(..)", errstr.str(), 90);
108  }
109  return IsLock(node);
110 }
112  const Node* node = NodePtr(nid);
113  if(!node) {
114  std::stringstream errstr;
115  errstr << "Node #" << nid << " unknown.";
116  throw Exception("Experiment::CStates(..)", errstr.str(), 90);
117  }
118  if(!node->mpStates) {
119  std::stringstream errstr;
120  errstr << "Node #" << nid << " no compatible states set.";
121  throw Exception("Experiment::CStates(..)", errstr.str(), 90);
122  }
123  return node->mpStates;
124 }
125 
126 
127 // access by sequence
128 Idx Experiment::Find(const std::deque< Idx >& seq) const {
129  Node* node = mpRoot;
130  std::deque< Idx >::const_iterator eit= seq.begin();
131  std::deque< Idx >::const_iterator eit_end= seq.end();
132  for(;eit!=eit_end;++eit) {
133  Node::Iterator cit = Children(node).find(*eit);
134  if(cit==Children(node).end()) return 0;
135  node=cit->second;
136  }
137  return Index(node);
138 }
139 std::deque< Idx > Experiment::Sequence(Idx nid) const {
140  const Node* node=NodePtr(nid);
141  if(!node) {
142  std::stringstream errstr;
143  errstr << "Node #" << nid << " unknown.";
144  throw Exception("Experiment::Sequence(..)", errstr.str(), 90);
145  }
146  std::deque< Idx > res;
147  while(node!=mpRoot) {
148  res.push_front(RecEvent(node));
149  node=Parent(node);
150  }
151  return res;
152 }
153 
154 
155 
156 // inspect for debugging
157 void Experiment::DWrite(Idx nid) const{
158  FAUDES_WRITE_CONSOLE("% -------------------------------------------------------------------- ");
159  Node* node= NodePtr(nid);
160  if(!node) {
161  FAUDES_WRITE_CONSOLE("Node Idx " << nid << " (no such node) ");
162  return;
163  }
164  if(node==mpRoot) {
165  FAUDES_WRITE_CONSOLE("Node Idx " << Index(node) << " (Root) ");
166  } else {
167  if(!Parent(node)) {
168  FAUDES_WRITE_CONSOLE("Node Idx " << Index(node) << " No Parent (!) ");
169  } else {
170  FAUDES_WRITE_CONSOLE("Node Idx " << Index(node) << " Parent " << Index(Parent(node)));
171  }
172  }
173  std::deque<Idx> seq = Sequence(Index(node));
174  if(!seq.empty()) {
175  std::string msg;
176  std::deque<Idx>::const_iterator eit = seq.begin();
177  std::deque<Idx>::const_iterator eit_end = seq.end();
178  for(; eit!=eit_end;++eit){
179  msg.append(rAlphabet.SymbolicName(*eit));
180  msg.append(" ");
181  }
182  FAUDES_WRITE_CONSOLE("Event-sequence: " << msg);
183  }
184  if(States(node)) States(node)->DWrite();
185  if(Children(node).size()>0) {
186  std::stringstream msg;
187  Node::Iterator cit=Children(node).begin();
188  for(; cit!=Children(node).end(); ++cit){
189  msg << "(" << rAlphabet.SymbolicName(cit->first) << ")->(" << Index(cit->second) << ") ";
190  }
191  FAUDES_WRITE_CONSOLE(msg.str());
192  }
193 }
194 void Experiment::DWrite(void) const{
195  FAUDES_WRITE_CONSOLE("% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ");
196  FAUDES_WRITE_CONSOLE("% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ");
197  FAUDES_WRITE_CONSOLE("% Dumping experiment ... ");
198  Iterator nit=mNodeMap.begin();
199  for(;nit!=mNodeMap.end();++nit)
200  DWrite(nit->first);
201  FAUDES_WRITE_CONSOLE("% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ");
202  FAUDES_WRITE_CONSOLE("% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ");
203 }
204 
205 void Experiment::SWrite(void) const{
206  FAUDES_WRITE_CONSOLE("% +++++++++++++++++++++++++++ ");
207  FAUDES_WRITE_CONSOLE("% Experiment Statistics");
208  std::vector<int> seqcnt;
209  std::vector<int> seqlck;
210  int lockcnt=0;
211  Iterator nit=mNodeMap.begin();
212  for(;nit!=mNodeMap.end();++nit) {
213  Node* node=nit->second;
214  if(seqcnt.size()<Depth(node)+1) {
215  seqcnt.resize(Depth(node)+1);
216  seqlck.resize(Depth(node)+1);
217  }
218  if(IsLeave(node)){
219  seqcnt[Depth(node)]++;
220  }
221  if(IsLock(node)) {
222  seqlck[Depth(node)]++;
223  lockcnt++;
224  }
225  }
226  std::stringstream rep;
227  for(unsigned int i=0; i<seqcnt.size(); ++i) {
228  if(seqcnt[i]==0) continue;
229  rep << "#" << seqcnt[i];
230  if(seqlck[i]>0) rep << "[locks #" << seqlck[i] << "]";
231  rep << "[@" << i << "] ";
232  }
233  FAUDES_WRITE_CONSOLE("% Nodes #" << Size() << " Leaves #" << Leaves().Size() << " Locks #" << lockcnt << " Cost #" << Cost());
234  if(mLeaves.Size()>0)
235  FAUDES_WRITE_CONSOLE("% " << rep.str());
236  FAUDES_WRITE_CONSOLE("% +++++++++++++++++++++++++++ ");
237 }
238 
239 // reprot leaves
240 const IndexSet& Experiment::Leaves(void) const {
241  /*
242  const_cast<Experiment*>(this)->mLeaves.Clear();
243  Iterator nit=mNodeMap.begin();
244  for(;nit!=mNodeMap.end();++nit)
245  if(IsLeave(nit->second)) const_cast<Experiment*>(this)->mLeaves.Insert(nit->first);
246  */
247  return mLeaves;
248 }
249 
250 // do the job: refine at specified node
252  Node* node=NodePtr(idx);
253  if(!node) return; // should throw
254  if(!IsLeave(node)) return;
255  FAUDES_WRITE_CONSOLE("Experiment::RefineAt(..): node=#" << idx << " at depth=#" << Depth(node));
256  //DWrite(Index(node));
257  CompatibleStates* cstates = States(node);
258  if(!cstates) return; // should throw
259  // nothing to do
260  if(!IsLeave(node)) return;
261  if(IsLock(node)) return;
262  // do the job
263  cstates->ExecuteTransitions();
264  IsLock(node)=true;
265  mCost+=cstates->Cost();
266  // distribute results
267  EventSet::Iterator eit=rAlphabet.Begin();
268  EventSet::Iterator eit_end=rAlphabet.End();
269  for(; eit!=eit_end;++eit) {
270  CompatibleStates* nstates = cstates->TakeByEvent(*eit);
271  // null: emptyset
272  if(!nstates) continue;
273  // non-null: we take ownership; null: emptyset
274  Node* child=Insert(node,*eit);
275  States(child) = nstates;
276  IsLock(node)=false;
277  }
278  /*
279  if(IsLock(node)) {
280  FAUDES_WRITE_CONSOLE("no successor states --- record lock");
281  } else {
282  std::stringstream msg;
283  msg << "child nodes inserted at d=#" << Depth(node) << ": ";
284  Node::Iterator cit=Children(node).begin();
285  for(; cit!=Children(node).end(); ++cit){
286  msg << "(" << rAlphabet.SymbolicName(cit->first) << ")->(" << Index(cit->second) << ") ";
287  }
288  FAUDES_WRITE_CONSOLE(msg.str());
289  }
290  FAUDES_WRITE_CONSOLE("Experiment::RefineAt(..): done");
291  */
292 }
293 
294 void Experiment::RefineUniformly(unsigned int depth) {
295  std::stack<Node*> todo;
296  todo.push(mpRoot);
297  while(!todo.empty()) {
298  Node* node=todo.top();
299  todo.pop();
300  if(Depth(node)>=depth) continue;
301  if(IsLock(node)) continue;
302  if(!IsLeave(node)) continue;
303  RefineAt(Index(node));
304  Node::Iterator cit=Children(node).begin();
305  Node::Iterator cit_end=Children(node).end();
306  for(;cit!=cit_end;++cit)
307  if(cit->second)
308  todo.push(cit->second);
309  }
310 }
311 
312 // do the job: refine for a sequence (return final node or 0)
313 Idx Experiment::RefineSequence(const std::deque< Idx >& seq) {
314  Node* node=mpRoot;
315  unsigned int cnt=0;
316  while(cnt<seq.size()) {
317  if(IsLock(node)) break;
318  if(IsLeave(node)) RefineAt(Index(node));
319  Node::Iterator cit = Children(node).find(seq.at(cnt));
320  if(cit == Children(node).end()) break;
321  node=cit->second;
322  cnt++;
323  }
324  if(cnt==seq.size()) return Index(node);
325  return 0;
326 }
327 
328 
329 
330 /*
331 ********************************************************************************************
332 ********************************************************************************************
333 
334 Reachability analysis for DES
335 
336 ********************************************************************************************
337 ********************************************************************************************
338 */
339 
340 // DES dynamics operator construct
342  mpStates= new StateSet();
343 }
344 
345 // DES dynamics operator destruct
347  std::map<Idx, StateSet*>::iterator sit=mReachSets.begin();
348  std::map<Idx, StateSet*>::iterator sit_end=mReachSets.end();
349  for(;sit!=sit_end;++sit) {
350  if(sit->second) delete sit->second;
351  }
352  delete mpStates;
353 }
354 
355 // Optional initialisation
358 }
361 }
362 
363 // do the job
365  // lopp all events
366  EventSet::Iterator eit=rGen.AlphabetBegin();
367  EventSet::Iterator eit_end=rGen.AlphabetEnd();
368  for(; eit!=eit_end;++eit) {
369  StateSet* nstates=new StateSet;
370  nstates->Name("CompatibleStates");
371  // loop over all current states
372  StateSet::Iterator sit=mpStates->Begin();
373  StateSet::Iterator sit_end=mpStates->End();
374  for(; sit!=sit_end; ++sit ) {
375  TransSet::Iterator tit= rGen.TransRelBegin(*sit,*eit);
376  TransSet::Iterator tit_end= rGen.TransRelEnd(*sit,*eit);
377  for(; tit!=tit_end;++tit) nstates->Insert(tit->X2);
378  }
379  // continue in disabled event
380  if(nstates->Empty()) {delete nstates; continue;}
381  mReachSets[*eit]=nstates;
382  }
383 }
384 
385 // pass on result (give away ownership)
387  std::map<Idx, StateSet*>::iterator sit=mReachSets.find(ev);
388  if(sit==mReachSets.end()) return 0;
389  if(sit->second==0) return 0;
391  delete res->mpStates;
392  res->mpStates= sit->second;
393  sit->second=0;
394  return res;
395 }
396 
397 
398 // dump
399 void DesCompatibleStates::DWrite(void) const {
400  mpStates->DWrite();
401 }
402 
403 
404 /*
405 ********************************************************************************************
406 ********************************************************************************************
407 
408 Reachability analysis for LHA
409 
410 ********************************************************************************************
411 ********************************************************************************************
412 */
413 
414 
415  // LHA dynamics operator construct
417  mpStates= new HybridStateSet();
418  mCnt=0;
419 }
420 
421 // LHA dynamics operator destruct
423  std::map<Idx, HybridStateSet*>::iterator sit=mHybridReachSets.begin();
424  std::map<Idx, HybridStateSet*>::iterator sit_end=mHybridReachSets.end();
425  for(;sit!=sit_end;++sit) {
426  if(sit->second) delete sit->second;
427  }
428  delete mpStates;
429 }
430 
431 // Optional initialisation
433  mpStates->Clear();
434  StateSet::Iterator qit=rLha.StatesBegin();
435  StateSet::Iterator qit_end=rLha.StatesEnd();
436  for(;qit!=qit_end;++qit){
437  Polyhedron* poly = new Polyhedron(rLha.StateSpace());
438  PolyFinalise(*poly);
439  mpStates->Insert(*qit,poly);
440  }
441 }
443  FD_DF("LhaCompatibleStates::InitialiseConstraint()");
444  mpStates->Clear();
445  StateSet::Iterator qit=rLha.InitStatesBegin();
446  StateSet::Iterator qit_end=rLha.InitStatesEnd();
447  for(;qit!=qit_end;++qit){
448  Polyhedron* poly = new Polyhedron(rLha.InitialConstraint(*qit));
450  PolyFinalise(*poly);
451  mpStates->Insert(*qit,poly);
452  }
453  FD_DF("LhaCompatibleStates::InitialiseConstraint(): done");
454 }
455 
456 // do the job
459  FD_DF("ExecuteTransitions():: found successors #" << mHybridReachSets.size());
460 }
461 
462 // pass on result (give away ownership)
464  std::map<Idx, HybridStateSet*>::iterator sit=mHybridReachSets.find(ev);
465  if(sit==mHybridReachSets.end()) return 0;
466  if(sit->second==0) return 0;
468  delete res->mpStates;
469  res->mpStates= sit->second;
470  sit->second=0;
471  return res;
472 }
473 
474 // dump
475 void LhaCompatibleStates::DWrite(void) const {
476  mpStates->DWrite(rLha);
477 }
478 
479 
480 
481 
482 
#define FAUDES_WRITE_CONSOLE(message)
Debug: output macro for optional redirection of all console output.
#define FD_DF(message)
Debug: optional report on user functions.
Abstract dynamics operator, i.e., some set of states, that knows where it eveolves when it next trigg...
virtual const int Cost(void)
virtual void DWrite(void) const =0
virtual void ExecuteTransitions(void)=0
virtual CompatibleStates * TakeByEvent(Idx ev)=0
virtual void DWrite(void) const
virtual DesCompatibleStates * TakeByEvent(Idx ev)
DesCompatibleStates(const Generator &gen)
std::map< Idx, StateSet * > mReachSets
virtual void ExecuteTransitions(void)
Faudes exception class.
Node record to form a tree.
CompatibleStates * mpStates
Idx RefineSequence(const std::deque< Idx > &seq)
std::map< Idx, Node * > & Children(Node *node)
bool IsLock(Idx nid) const
void DWrite(void) const
Idx & RecEvent(Node *node)
Idx & Index(Node *node)
Node related methods, hosted by Experiment for convenience.
bool IsLeave(Idx nid) const
void RefineUniformly(unsigned int depth)
Idx Find(const std::deque< Idx > &seq) const
void RefineAt(Idx idx)
std::map< Idx, Node * >::const_iterator Iterator
EventSet EnabledEvents(Idx nid) const
Node * Insert(Node *parent, Idx ev)
grow tree
Experiment(const EventSet &alph)
Idx Root(void) const
Navigate tree This interface is intended for external use.
std::map< Idx, Node * > mNodeMap
Node * mpRoot
core experiment data: have root and track all nodes by index
const faudes::EventSet & rAlphabet
reference to alphabet
void InitialStates(CompatibleStates *istates)
Idx Size(void) const
const EventSet & Alphabet(void) const
const IndexSet & Leaves() const
Node *& Parent(Node *node)
std::deque< Idx > Sequence(Idx nid) const
int Cost(void) const
Idx & Depth(Node *node)
Node * NodePtr(Idx idx) const
get node ptr by index (for API wrappers)
void SWrite(void) const
const CompatibleStates * States(Idx nid) const
Access compatible states (note: implememtation dependant data type)
Idx SuccessorNode(Idx nid, Idx ev) const
Set of states in an hybrid automata.
void DWrite(const LinearHybridAutomaton &lha)
inspect
void Insert(Idx q)
insert / erase (we take owvership of polyhedra)
Set of indices.
Definition: cfl_indexset.h:78
Idx Insert(void)
Insert new index to set.
std::map< Idx, HybridStateSet * > mHybridReachSets
const LinearHybridAutomaton & rLha
virtual void DWrite(void) const
virtual void ExecuteTransitions(void)
LhaCompatibleStates(const LinearHybridAutomaton &lha)
virtual LhaCompatibleStates * TakeByEvent(Idx ev)
Set of indices with symbolic names.
Definition: cfl_nameset.h:69
void SymbolicName(Idx index, const std::string &rName)
Set new name for existing index.
bool Insert(const Idx &rIndex)
Add an element by index.
Polyhedron in R^n.
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Iterator on transition.
Definition: cfl_transset.h:269
Generator with linear hybrid automata extensions.
const Polyhedron & InitialConstraint(Idx idx) const
Get initial constraint of state by index.
const Polyhedron & StateSpace(void) const
Get continuous statespace.
void DWrite(const Type *pContext=0) const
Write configuration data to console, debugging format.
Definition: cfl_types.cpp:225
virtual Type & Assign(const Type &rSrc)
Assign configuration data from other object.
Definition: cfl_types.cpp:77
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.
const StateSet & InitStates(void) const
Const ref to initial states.
TransSet::Iterator TransRelBegin(void) const
Iterator to Begin() of transition relation.
EventSet::Iterator AlphabetBegin(void) const
Iterator to Begin() of alphabet.
StateSet::Iterator StatesEnd(void) const
Iterator to End() of state set.
TransSet::Iterator TransRelEnd(void) const
Iterator to End() of transition relation.
StateSet::Iterator InitStatesEnd(void) const
Iterator to End() of mInitStates.
EventSet::Iterator AlphabetEnd(void) const
Iterator to End() of alphabet.
const StateSet & States(void) const
Return reference to state set.
bool Empty(void) const
Test whether if the TBaseSet is Empty.
Definition: cfl_baseset.h:1824
IndexSet StateSet
Definition: cfl_indexset.h:271
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
const std::string & Name(void) const
Return name of TBaseSet.
Definition: cfl_baseset.h:1755
Idx Size(void) const
Get Size of TBaseSet.
Definition: cfl_baseset.h:1819
void PolyFinalise(const Polyhedron &fpoly)
convert PPL polyhedron back to faudes data structures; this is required if we manipulate a polyhedron...
Definition: hyb_compute.cpp:53
void PolyIntersection(const Polyhedron &poly, Polyhedron &res)
intersection
Exhaustive experments on linear hybris automata.
libFAUDES resides within the namespace faudes.
uint32_t Idx
Type definition for index type (allways 32bit)
TNode< Idx, Idx > Node
void LhaReach(const LinearHybridAutomaton &lha, const HybridStateSet &states, std::map< Idx, HybridStateSet * > &ostates, int *pCnt)
compute sets of reachable state per successor event
An iterator over the set of edges related to one vertex is interpreted as a transition.

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