DiaDes  0.1
DIAgnosis of Discrete-Event System
CheckReachability.cc
Go to the documentation of this file.
1 
20 #include<iostream>
21 #include<vector>
22 #include<string>
23 #include<set>
24 #include<list>
25 #include<fstream>
26 #include "boost/date_time/posix_time/posix_time.hpp"
27 #include<utils/Random.hh>
28 #include<utils/Verbose.hh>
29 #include<utils/CmdInterface.hh>
30 
33 
34 using namespace std;
35 using namespace boost::posix_time;
36 
37 typedef enum { EVENT = 0, HELP = 1 } Option;
38 typedef enum { DESCOMP=0, RULES=1} FileExtension;
39 unsigned numberOfOptions = 2;
41 
42 
44 vector<string> options(numberOfOptions);
45 vector<bool> isSet(numberOfOptions,false);
46 string description="Usage: dd-check-reachability --help | model1.des_comp [model2.des_comp ... sync.rules] [--event e1 e2 ]";
47 
49 {
50  options[EVENT] = "--event";
51  options[HELP] = "--help";
52  fileExtensions[DESCOMP]= "des_comp";
53  fileExtensions[RULES] = "rules";
54 }
55 
56 
57 
58 using namespace Diades::Utils;
59 
60 
61 
69 void clean(vector<Diades::Automata::ObservableComponent *> & components,
71  vector<Diades::Automata::ComposableModel::ConstPointer> & comps)
72 {
73  if(model != nullptr)
74  {
75  delete model;
76  }
77  for(vector<Diades::Automata::ComposableModel::ConstPointer>::size_type i = 0; i < comps.size(); ++i)
78  {
79  delete comps[i];
80  comps[i]=nullptr;
81  }
82  comps.clear();
83  for(vector<Diades::Automata::ObservableComponent *>::size_type i = 0; i < components.size();
84  ++i)
85  {
86  if(components[i]!= nullptr)
87  {
88  delete components[i];
89  components[i]=nullptr;
90  }
91  }
92  components.clear();
95 }
96 
97 
98 
99 
100 
112 int main(int argc, char ** argv)
113 {
114  verbose<VbOutput>("DiaDes: check-reachability\n");
115  verbose<VbOutput>("LAAS-CNRS, 2006-2015, 7 avenue du Colonel Roche, Toulouse, France\n");
116  verbose<VbOutput>("Contact: yannick.pencole@laas.fr\n");
118  vector<unsigned> values(numberOfOptions);
119  set<string> events;
120  set<string> modelFile;
121  string ruleFile;
122 
123 
124  if(argc==1)
125  {
127  return 0;
128  }
129  int index = 1;
130  while(index < argc)
131  {
132  Option currentOption;
133  if(getOption<Option>(argv[index],options,currentOption))
134  {
135  if(isSet[currentOption])
136  {
137  printError("The option '" + options[currentOption] + "' occurs at least twice.");
138  return 1;
139  }
140  else
141  {
142  isSet[currentOption] = true;
143  }
144 
145  switch(currentOption)
146  {
147  case HELP:
148  {
149  if((index!=1) || (argc !=2))
150  {
151  printError("Incorrect use of option --help.");
152  return 1;
153  }
154  else
155  {
157  return 0;
158  }
159  }
160  case EVENT:
161  {
162  ++index;
163  getParameterList<string>(argc,argv,options,fileExtensions,
164  index,events);
165  if(events.size() == 0)
166  {
167  printError("One or more arguments wre expected after option --event.");
168  return 1;
169  }
170  break;
171  }
172 
173  default:
174  {
175  printError("Unrecognized option: " + string(argv[index]));
176  return 1;
177  break;
178  }
179 
180  }
181  }
182  else
183  {
184  // then it should be the name of a file
185  vector<string>::const_iterator it =
186  getFileExtension(string(argv[index]),fileExtensions.begin(),fileExtensions.end());
187 
188  if(it == fileExtensions.end())
189  {
190  printError("Unrecognized file extension in file name: " + string(argv[index]));
191  return 1;
192  }
193 
194 
195  FileExtension extension = DESCOMP;
196  if(*it==fileExtensions[RULES]) { extension = RULES; }
197  switch(extension)
198  {
199  case DESCOMP:
200  {
201  modelFile.insert(string(argv[index]));
202  break;
203  }
204  case RULES:
205  {
206  if(!ruleFile.empty())
207  {
208  printError("It seems that there are more than one synchronization rules file as a argument.");
209  return 1;
210  }
211  ruleFile = string(argv[index]);
212  break;
213  }
214  }
215  ++index;
216  }
217  }
218  if(modelFile.empty())
219  {
220  printError("No model, so no check.");return 1;
221  }
222  if((modelFile.size() == 1) && (!ruleFile.empty()))
223  {
224  printError("There is one synchronization rule file but no more than one component.");return 1;
225  }
226  if((modelFile.size() > 1) && (ruleFile.empty()))
227  {
228  printError("There is no synchronization rule file but it is required as there is more than one component in the model.");return 1;
229  }
230 
231  vector<Diades::Automata::ObservableComponent *> components(modelFile.size(),nullptr);
232  Diades::Automata::ComposableModel * model = nullptr;
233  vector<Diades::Automata::ComposableModel::ConstPointer> comps;
236  try
237  {
238  unsigned i = 0;
239  for(const string & name: modelFile)
240  {
241  components[i] = new Diades::Automata::ObservableComponent();
242  if(!components[i]->importOldModel(name))
243  {
244  throw(FunctionException("main", Diades::Utils::Msg("Cannot load the model file '%1%'") % name));
245  }
246  vectorComp.push_back(components[i]);
247  ++i;
248  }
249  if(!ruleFile.empty())
250  {
251  rules.loadRules(vectorComp,ruleFile);
252  }
253  }
254  catch(exception & e)
255  {
256  log<LgProcess>("The main function caught the following exception: \n\t%1%") % e.what();
257  saveLog(cerr);
258  clean(components,model,comps);
259  printError("Load of the files has failed. See log above.");
260  return 1;
261  }
262  stringstream toDot;
264  if(components.size()==1)
265  {
266  unsigned visitedTransitions = 0;
267  unsigned visitedStates = 0;
268  unsigned deadlocks = 0;
269 
270  mask = components[0]->mask();
271  // check
272  unordered_map<Diades::Automata::Event,bool> searchedEvent;
273  for(const Diades::Automata::Event & event : components[0]->events())
274  {
275  if(events.find(event.label()) != events.end())
276  {
277  searchedEvent.insert(make_pair(event,false));
278  }
279  }
280  unsigned found = 0;
281  std::list< std::pair<Diades::Automata::State,
284  visited.init(components[0]->behaviour(),false);
286  components[0]->initialStateBegin();
287  it != components[0]->initialStateEnd();
288  ++it)
289  {
290  queue.push_back(make_pair(*it, components[0]->outputTransitionBegin(*it)));
291  visited[*it] = true;
292  toDot << "\t " << *it << "\t [label=\"";
293  toDot << components[0]->getLabel(*it);
294  toDot << "\"];" << endl;
295  toDot << "\t init" << *it << "\t [label=\"\",color=white];" << endl;
296  toDot << "\t init" << *it << " -> " << *it << ";" << endl;
297 
298  ++visitedStates;
299  if(it->outDeg() == 0)
300  {
301  ++deadlocks;
302  }
303  }
304  while((found < searchedEvent.size()) && !(queue.empty()))
305  {
306  Diades::Automata::State currentState = queue.front().first;
307  if(queue.front().second == components[0]->outputTransitionEnd(currentState))
308  {
309  queue.pop_front();
310  std::cout << currentState << ": SATURATED" << std::endl;
311  }
312  else
313  {
314  Diades::Automata::Transition currentTrans = *queue.front().second;
315  ++visitedTransitions;
316  toDot << "\t" << currentState << " -> " << currentTrans.target()
317  << " [label=\"" << components[0]->getEvent(currentTrans).nickname();
318  toDot << "\"];" << endl;
319  unordered_map<Diades::Automata::Event,bool>::iterator it =
320  searchedEvent.find(components[0]->getEvent(currentTrans));
321  if(it != searchedEvent.end())
322  {
323  if(it->second == false)
324  {
325  it -> second = true;
326  ++found;
327  std::cout << "FOUND" << std::endl;
328  }
329  }
330  if(!visited[currentTrans.target()])
331  {
332  queue.push_back(make_pair(currentTrans.target(), components[0]->outputTransitionBegin(currentTrans.target())));
333  toDot << "\t " << currentTrans.target() << "\t [label=\"";
334  toDot << components[0]->getLabel(currentTrans.target());
335  toDot << "\"];" << endl;
336  visited[currentTrans.target()]=true;
337  ++visitedStates;
338  if(currentTrans.target().outDeg() == 0)
339  {
340  ++deadlocks;
341  }
342  }
343  ++queue.front().second;
344  }
345  }
346  std::cout << "REACHABILITY ANALYSIS" << std::endl;
347  for(unordered_map<Diades::Automata::Event,bool>::const_iterator it = searchedEvent.begin();
348  it != searchedEvent.end(); ++it)
349  {
350  std::cout << it->first << ": ";
351  if(it->second)
352  {
353  std::cout << "YES" << std::endl;
354  }
355  else
356  {
357  std::cout << "NO" << std::endl;
358  }
359  }
360  std::cout << "Visited States: " << ((double) visitedStates / (double) components[0]->numberOfStates() * 100.0 ) << "% (" << visitedStates << " has been visited)" << std::endl;
361  std::cout << "Visited Transitions: " << ((double) visitedTransitions / (double) components[0]->numberOfTransitions() * 100.0 ) << "% (" << visitedTransitions << " has been visited)" << std::endl;
362  std::cout << "Visited deadlocks: " << deadlocks << std::endl;
363  }
364  else
365  {
366  Diades::Automata::ComposableModel * model = nullptr;
367 
368 
369  for(unsigned i = 0 ; i < components.size(); ++i)
370  {
371  comps.push_back(new Diades::Automata::ComposableModel(*components[i],rules));
372  for(Diades::Automata::ObservableMask::EventIterator it = components[i]->mask().eventBegin();
373  it != components[i]->mask().eventEnd();
374  ++it)
375  {
377  it2 != components[i]->mask().observableEnd(*it);
378  ++it2)
379  {
380  mask.addMask(*it,*it2);
381  }
382  }
383  }
384 
385  model = new Diades::Automata::ComposableModel(comps,rules,true);
386  // check
387  }
388 
389  std::ofstream file("reachability.dot");
390 
391  // writing the header
392  file << "digraph G {" << endl;
393  file << "\tratio=fill;" << endl;
394  file << "\tpage=\"8.5,11.6\";" << endl;
395  file << "\tsize=\"7.5,10.5\";" << endl;
396  file << "\tlabel=\"Component name = reachability\";" << endl;
397  file << toDot.str() << endl;
398  // writing the end of file
399  file << "}" << endl;
400  file.close();
401 
402  clean(components,model,comps);
403  return 0;
404 }
405 
406 
407 
vector< string > options(numberOfOptions)
vector< const Component * > ComponentVector
unsigned numberOfOptions
InputIterator getFileExtension(const std::basic_string< CharType, CharTraits > &fileName, InputIterator begin, InputIterator end)
Definition: StringTools.hh:57
Diades::Graph::Edge Transition
Definition: Component.hh:46
vector< bool > isSet(numberOfOptions, false)
void init(Graph &g, SizeType capacity=0, ValueType dflt=ValueType())
Definition: NodeMap.hh:315
STL namespace.
FileExtension
Definition: abstract.cc:33
void initialiseOptions()
unordered_set< State >::const_iterator InitialStateIterator
Definition: Component.hh:70
set< Event >::const_iterator ObservableEventIterator
An observable Component defined as a automaton.
int main(int argc, char **argv)
ostream & toDot(ostream &os, const StateMachine &fsm, const PrintStateProperty &statePrinter, const PrintEventInfo &eventPrinter)
Definition: Io.hh:267
set< Event >::const_iterator EventIterator
string description
Random generation utilities.
Option
Definition: abstract.cc:32
void clean(vector< Diades::Automata::ObservableComponent *> &components, Diades::Automata::ComposableModel *model, vector< Diades::Automata::ComposableModel::ConstPointer > &comps)
Diades::Graph::OutEdgeIterator OutputTransitionIterator
Definition: Component.hh:72
ObservableEventIterator observableBegin() const
void saveLog(Logger logger, ostream &os)
Definition: Log.hh:163
EventIterator eventEnd() const
void printError(string parameter, string message)
FileExtension
void addMask(const Event &e, const Event &obs)
Diades::Graph::Node State
Definition: BeliefState.hh:36
unsigned numberOfFileExtensions
boost::format Msg
Definition: Verbose.hh:42
vector< string > fileExtensions(numberOfFileExtensions)
void printUsage(const po::options_description &desc)