DiaDes  0.1
DIAgnosis of Discrete-Event System
Diagnoser.cc
Go to the documentation of this file.
1 #include <fstream>
2 #include <sstream>
3 #include <unordered_set>
4 
8 
9 #include "CmdInterface.hh"
43 using namespace std;
44 using namespace Diades::Automata;
45 using namespace Diades::CmdInterface;
46 
48 
49 unsigned numberOfOptions = 8;
51 
52 
54 vector<string> options(numberOfOptions);
55 vector<bool> isSet(numberOfOptions,false);
56 
57 string description="DiaDes: Diagnoser computation\nLAAS-CNRS, 2006-2012, 7 avenue du Colonel Roche, Toulouse, France\nContact: yannick.pencole@laas.fr\n\nUsage: diagnoser\n\t [--with-silent-closure]\n\t [--no-failures | --failures evt1 [evt2 ...]]\n\t [--observables obs1 [obs2 ...]]\n\t [--hd filename1]\n\t [--dot filename2]\n\tinfile.des_comp \n\n\nCompute an explicit representation of the diagnoser from the model \ninfile.des_comp and saves it into modelName.diagnoser (diades format). \nThe diagnoser can be extended with the silent closure or not. \nIf --no-failures is set, it returns a state observer. If --observables \n(resp. --failures) is set, then only the listed events are considered as observable \n(resp. faulty). The tag --hd exports the diagnoser is HyDiag format, the tag --dot \nexports the diagnoser in graphviz format, the tag --cpp exports the diagnoser \nin standalone and compilable C++ file. The option --help displays this message";
58 
59 
61 {
62  options[NOFAILURES] = "--no-failures";
63  options[FAILURES] = "--failures";
64  options[OBSERVABLES] = "--observables";
65  options[HDFILE] = "--hd";
66  options[DOTFILE] = "--dot";
67  options[CPPFILE] = "--cpp";
68  options[WITHSILENTCLOSURE] = "--with-silent-closure";
69  options[HELP] = "--help";
70  fileExtensions[0] = "des_comp";
71 }
72 
77 bool getFailuresFromFileModel(const string & infileName, unordered_set<Event> & failures, string & log);
78 
79 
80 
81 /*******************************************************************************************/
82 
95 int main(int argc, char * argv[])
96 {
97  verbose<VbOutput>("DiaDes: Diagnoser computation\n");
98  verbose<VbOutput>("LAAS-CNRS, 2006-2012, 7 avenue du Colonel Roche, Toulouse, France\n");
99  verbose<VbOutput>("Contact: yannick.pencole@laas.fr\n");
101  vector<unsigned> values(numberOfOptions);
102  vector< set<string> > events(numberOfOptions);
103  string infileName;
104  string dotfileName;
105  string hdfileName;
106  string cppfileName;
107  int index = 1;
108  unordered_set<Event> failures;
109  unordered_set<Event> observables;
110 
111  if(argc < 2)
112  {
114  }
115  else
116  {
117  while(index < argc)
118  {
119  Option currentOption;
120  if(getOption<Option>(argv[index],options,currentOption))
121  {
122  if(isSet[currentOption])
123  {
124  printCommandLineError("The option '" + options[currentOption] + "' occurs at least twice.");
125  }
126  else
127  {
128  isSet[currentOption] = true;
129  }
130 
131 
132  switch(currentOption)
133  {
134  case NOFAILURES:
135  {
136  ++index;
137  if(isSet[FAILURES])
138  {
139  printCommandLineError("The options failures/no-failures are incompatible with each other.");
140  }
141  break;
142  }
143  case FAILURES:
144  {
145  ++index;
146  if(isSet[NOFAILURES])
147  {
148  printCommandLineError("The options failures/no-failures are incompatible with each other.");
149  }
150  else
151  {
152  getParameterList<string>(argc,argv,options,fileExtensions,
153  index,events[currentOption]);
154  if(events[currentOption].empty())
155  {
156  printCommandLineError("No parameter after the option " + options[currentOption]);
157  }
158  else
159  {
160  for(const string & obs : events[currentOption])
161  {
162  failures.insert(EventFactory::factory()->getEvent(obs));
163  }
164  }
165  }
166  break;
167  }
168  case OBSERVABLES:
169  {
170  ++index;
171 
172  getParameterList<string>(argc,argv,options,fileExtensions,
173  index,events[currentOption]);
174  if(events[currentOption].empty())
175  {
176  printCommandLineError("No parameter after the option " + options[currentOption]);
177  }
178  else
179  {
180  for(const string & obs : events[currentOption])
181  {
182  observables.insert(EventFactory::factory()->getEvent(obs));
183  }
184  }
185  break;
186  }
187  case HDFILE:
188  {
189  ++index;
190  set<string> files;
191  getParameterList<string>(argc,argv,options,fileExtensions,
192  index,files);
193  if(files.size() != 1)
194  {
195  printCommandLineError("One and only one argument was expected after option --hd.");
196  }
197  hdfileName=*(files.begin());
198  break;
199  }
200  case DOTFILE:
201  {
202  ++index;
203  set<string> files;
204  getParameterList<string>(argc,argv,options,fileExtensions,
205  index,files);
206  if(files.size() != 1)
207  {
208  printCommandLineError("One and only one argument was expected after option --dot.");
209  }
210  dotfileName=*(files.begin());
211  break;
212  }
213  case CPPFILE:
214  {
215  ++index;
216  set<string> files;
217  getParameterList<string>(argc,argv,options,fileExtensions,
218  index,files);
219  if(files.size() != 1)
220  {
221  printCommandLineError("One and only one argument was expected after option --cpp.");
222  }
223  cppfileName=*(files.begin());
224  break;
225  }
226  case WITHSILENTCLOSURE:
227  {
228  ++index;
229  break;
230  }
231  case HELP:
232  {
233  ++index;
235  break;
236  }
237  default:
238  {
239  printCommandLineError("Unrecognized option: " + string(argv[index]));
240  break;
241  }
242  }
243  }
244  else
245  {
246  // then it should be the model file
247  if(infileName.empty())
248  {
249  getParameter<string>(argc,argv,index,infileName);
250  if(!fileSuffixOk(infileName,"des_comp"))
251  {
252  printCommandLineError("The model file is not a component model file.");
253  }
254  }
255  else
256  {
257  printCommandLineError("It seems that there are more than one model file as a argument.");
258  }
259  }
260  }
261 
262 
263  if(infileName.empty())
264  {
265  printCommandLineError("No model, so no computation.");
266  }
267 
268  verbose<VbOutput>("Model loading... ");
270  try
271  {
272  if(!modl->importDesCompModel(infileName))
273  {
274  throw(Failure("main"));
275  }
276  }
277  catch(exception & e)
278  {
279  log<LgProcess>("The main function caught the following exception: \n\t%1%") % e.what();
280  saveLog(cerr);
281  printCommandLineError("Load of the file " + infileName + " has failed. See log above.");
282  }
283 
284  { verbose<VbOutput>("%1% success.\n") % modl->name(); }
285 
286  if(!isSet[NOFAILURES] && !isSet[FAILURES])
287  {
288  // the option noFailure is off and the no failure is declared as a parameter
289  // this is the default -> take the failures declared in the lafmodel
290  // @todo change this as I do not want to maintain lafmodel anymore
291  string log;
292  getFailuresFromFileModel(infileName, failures,log);
293  }
294 
295 
296  if(isSet[OBSERVABLES])
297  {
298  // the observable mask of the component must be changed as it is probably not the default one
299  ObservableMask newMask;
300  for(unordered_set<Event>::const_iterator obsIt = observables.begin();
301  obsIt != observables.end(); ++obsIt)
302  {
303  newMask.addMask(*obsIt,*obsIt);
304  }
305  modl->setMask(newMask);
306  }
307 
308  verbose<VbOutput>("Computation of the diagnoser with the following parameters: \n");
309 
310 
311  for (unordered_set<Event>::const_iterator i=failures.begin(); i!=failures.end(); ++i)
312  {
313  verbose<VbOutput>("Failure: %1%\n") % *i;
314  }
315  for (ObservableMask::ObservableEventIterator i= modl->mask().observableBegin();
316  i!=modl->mask().observableEnd();
317  ++i)
318  {
319  verbose<VbOutput>("Observable: %1%\n") % *i;
320  }
321 
322  //create a deterministic diagnoser
323  {
324  verbose<VbOutput>("Processing, please wait...");
325  }
326  ClassicalDiagnoser * diag = new ClassicalDiagnoser(*modl,failures,isSet[WITHSILENTCLOSURE]);
327  {
328  verbose<VbOutput>("Done.\n");
329  verbose<VbOutput>("Number of states: %1%\nNumber of transitions: %2%")
330  % diag->numberOfStates()
331  % diag->numberOfTransitions();
332  }
333 
334  if(isSet[HDFILE])
335  {
336  verbose<VbOutput>("Export in Hydiag format: ");
337  string exportHdLog;
338  if(!diag->diagnoser2hd(hdfileName,exportHdLog))
339  {
340  string msg = exportHdLog + "\nExport failure";
342  }
343  verbose<VbOutput>("%1% Done.\n") % hdfileName;
344  }
345 
346 
347 
348  if(isSet[DOTFILE])
349  {
350  verbose<VbOutput>("Export in dot format: ");
351  string exportDotLog;
352  if(!diag->diagnoser2dot(dotfileName,exportDotLog))
353  {
354  string msg = exportDotLog + "\nExport failure";
356  }
357  verbose<VbOutput>("%1% Done.\n") % hdfileName;
358  }
359 
360  if(isSet[CPPFILE])
361  {
362  {
363  verbose<VbOutput>("Export in c++ format: %1%.hh and %1%.cc") % cppfileName;
364  }
365  generateCppCode(*diag,cppfileName);
366  verbose<VbOutput>("Done.\n");
367  }
368  {
369  verbose<VbOutput>("Save the diagnoser in %1%.diagnoser.\n") % diag->name();
370  }
371 
372 
373  delete diag;
374  delete modl;
375  }
376 }
377 
378 
379 /*******************************************************************************************/
380 
381 
386 bool getFailuresFromFileModel(const string & infileName, unordered_set<Event> & failures, string & log)
387 {
388  bool result = true;
389  string goodSuffix = fileExtensions[0];
390  stringstream logStream;
391  if(infileName.size() <= goodSuffix.size())
392  {
393  logStream << "Error: incorrect input file name, it should be something like 'filename" << fileExtensions[0] << "' but it is " << infileName << ".";
394  result =false;
395  }
396  else
397  {
398  string suffix = infileName.substr(infileName.size()-goodSuffix.size(),infileName.size()-1);
399  if(suffix != goodSuffix)
400  {
401  logStream << "Error: incorrect input file name, it should be something like 'filename" << fileExtensions[0] << "' but it is " << infileName << ".";
402  result =false;
403  }
404  else
405  {
406  ifstream file(infileName.c_str());
407  if(!file)
408  {
409  result =false;
410  logStream << "Error: the file '" << infileName << "' does not exist.";
411  }
412 
413  if(result)
414  {
416  string fakeName;
417  getline(file,fakeName);
418  result = !file.eof();
419  if(!result)
420  {
421  logStream << "Error: the file '" << infileName << "' seems to be empty.";
422  }
423  else
424  {
426  unsigned number;
427  file >> number;
428  if(file.eof())
429  {
430  logStream << "Error: Impossible to get the number of states in the file '"<< infileName << "'.";
431  }
432  result = !file.eof();
433  unsigned i = 0;
434  while(result && (i < number))
435  {
436  string label;
437  file >> label;
438  if(file.eof())
439  {
440  logStream << "Error: Impossible to get state number " << i << " in file '" << infileName << "'.";
441  }
442  result = !file.eof();
443  ++i;
444  }
445 
446  if(result)
447  {
448  file >> number;
449  result = !file.eof();
450  if(!result)
451  {
452  logStream << "Error: Impossible to get the number of fault events in file '" << infileName << "'.";
453  }
454  i = 0;
455  while(result && (i < number))
456  {
457  string label;
458  file >> label;
459  if(file.eof())
460  {
461  logStream << "Error: Impossible to get fault event number " << i << "in file '" << infileName << "'.";
462  }
463  failures.insert(EventFactory::factory()->getEvent(fakeName + "." + label));
464  result = !file.eof();
465  ++i;
466  }
467  }
468  }
469  }
470  file.close();
471  }
472  }
473  if(!result)
474  {
475  log = "In getFailuresFromFileModel method, \n" + logStream.str();
476  }
477  return result;
478 }
479 
480 
481 
Some utilities to deal with the command line.
vector< bool > isSet(numberOfOptions, false)
unsigned numberOfOptions
Definition: Diagnoser.cc:49
size_t printCommandLineError(const string &msg)
Definition: CmdInterface.cc:98
unsigned numberOfFileExtensions
Definition: Diagnoser.cc:50
STL namespace.
string description
Definition: Diagnoser.cc:57
vector< string > options(numberOfOptions)
void initialiseOptions()
Definition: Diagnoser.cc:60
set< Event >::const_iterator ObservableEventIterator
An observable Component defined as a automaton.
Option
Definition: abstract.cc:32
bool fileSuffixOk(const string &modelFile, const string &suffix)
void saveLog(Logger logger, ostream &os)
Definition: Log.hh:163
vector< string > fileExtensions(numberOfFileExtensions)
Option
Definition: Diagnoser.cc:47
int main(int argc, char *argv[])
Definition: Diagnoser.cc:95
void generateCppCode(const ClassicalDiagnoser &diagnoser, const string &filename)
void addMask(const Event &e, const Event &obs)
Log log(Logger logger, const string &msg)
Definition: Log.hh:124
bool getFailuresFromFileModel(const string &infileName, unordered_set< Event > &failures, string &log)
Definition: Diagnoser.cc:386
void printUsage(const po::options_description &desc)