DiaDes  0.1
DIAgnosis of Discrete-Event System
TagStates.cc
Go to the documentation of this file.
1 
49 #include <cstdlib>
50 #include<iostream>
51 #include<fstream>
52 #include<regex>
53 #include<unordered_map>
54 #include<boost/program_options.hpp>
55 
58 #include"../AutomataInterface.hh"
61 using namespace std;
62 using namespace Diades::Automata::Experimental;
63 using namespace Diades::Utils;
64 using namespace Diades::CmdInterface;
65 
66 namespace Poptions = boost::program_options;
67 
68 
69 
74 const string program("dd-tagstates");
75 const string briefcomment(": this program tags some states based on regular expressions (output file or standard output).");
76 const string detailedcomment=R"( dd-tagstates tags a set of states to be initial or final based
77 on a regular expression. Regular expression are defined as proposed in
78 http://www.cplusplus.com/reference/regex/ECMAScript/
79 
80 Example 1: set to be acceptor any states such that its label contains
81 the substring 'o.p=ko'
82 
83 dd-tagstates file.ddaut -r 'final:.*o\.p=ko.*'
84 
85 Example 2: set to be non-acceptor any states such that its label contains the substring 'o.p=ok'
86 
87 dd-tagstates file.ddaut -r 'nofinal:.*o\.p=ok.*'
88 
89 Example 3: set to be initial any states such that its label contains the substring 'init'
90 
91 dd-tagstates file.ddaut -r 'initial:.*init.*'
92 
93 Example 4: set to be not initial any states such that its label is 's1' or 's2' or 's3'
94 
95 dd-tagstates file.ddaut -r 'noinitial:s[1-3]'
96 
97 Example 5: Applying Example 5: applying Examples 1-4 in one go. Tagging works
98 from left to right, we tag first 'final:.*o\.p=ko.*' then -r 'nofinal:.*o\.p=ok.*'
99 so the order matters.
100 
101 dd-tagstates file.ddaut -r 'final:.*o\.p=ko.*' -r 'nofinal:.*o\.p=ok.*' -r 'initial:.*init.*' -r 'noinitial:s[1-3]'
102 
103 
104 Example 6: tag a set of states S as acceptors and tag other states so that any prefix of a word accepted by a state of S
105 is also an accepted word.
106 
107 dd-tagstates file.ddaut -r 'prefix-closed-final:.*o\.p=ko.*'
108 
109 Example 7: swap the tags of the set of states S: swap-final if the state is final swap to non-final, if the state is
110 final then swap to final. swap-initial if the state is initial swap to non-initial, if the state is non-initial then swap
111 to initial.
112 
113 dd-tagstates file.ddaut -r 'swap-final:.*o\.p=ko.*' 'swap-initial:.*o\.p=ok.*'
114 )";
115 
116 /*
117  * File suffixes
118  */
119 FileSuffixes suffixes({"ddaut"});
120 
128 void
129 initialiseOptions(int argc, char * argv[],
130  Poptions::options_description & desc,
131  Poptions::variables_map & vm)
132 {
133  desc.add_options()
134  ("help,h", "produce help message")
135  ("file,f", Poptions::value< string >(), "file (.ddaut format)")
136  ("regexp,r", Poptions::value< vector<string> >(),
137  R"(A set of expressions inside a set of quotes: 'tag:regexp'
138 tag can be final, initial, nofinal, noinitial.
139 Regular expression regexp are on the name of
140 the states, for details see
141 http://www.cplusplus.com/reference/regex/ECMAScript/)
142 dd-tagstates applies the tags in the order written in
143 the command line.)")
144  ("output,o", Poptions::value< string >(), "outfile name (.ddaut format)")
145  ;
146  Poptions::positional_options_description p;
147  // 1 that The command line can accept 1 file name as positional option
148  p.add("file", 1);
149  Poptions::store(Poptions::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
150  Poptions::notify(vm);
151 }
152 
153 
159 
161 
162 
163 const std::unordered_map<std::string,Tag> tagOf = {
164  {"final",final},
165  {"nofinal",nofinal},
166  {"initial",initial},
167  {"noinitial",noinitial},
168  {"prefix-closed-final",prefixclosedfinal},
169  {"swap-initial",swapinitial},
170  {"swap-final",swapfinal}
171 };
172 
174 {
175  switch(tag)
176  {
177  case final: fa.setAcceptingState(state); break;
178  case nofinal: fa.unsetAcceptingState(state); break;
179  case initial: fa.setInitial(state); break;
180  case noinitial: fa.unsetInitial(state); break;
181  case prefixclosedfinal: fa.setAcceptingState(state); break;
182  case swapfinal: fa.swapAcceptingState(state); break;
183  case swapinitial: fa.swapInitialState(state); break;
184  }
185 }
186 
187 
188 void getReachable(DdAutFA & fa,CstStMap<char> & mapping,
189  std::regex & reg,
190  DdAutStateManager & sManager,
191  std::list<DdAutFA::State> & acceptors)
192 {
193  std::list<DdAutFA::State> visitingStates;
194  std::for_each(fa.initialStateBegin(),fa.initialStateEnd(),
195  [&](DdAutFA::State state)
196  {
197  visitingStates.push_back(state);
198  if(std::regex_match(sManager.getStateProperty(fa.getStatePropertyId(state)),reg))
199  {
200  acceptors.push_back(state);
201  mapping[state]=2;
202  std::cout << sManager.getStateProperty(fa.getStatePropertyId(state)) << " is reachable and must be set acceptor\n";
203  }
204  else
205  {
206  mapping[state]=1;
207  std::cout << sManager.getStateProperty(fa.getStatePropertyId(state)) << " is reachable but may not be set acceptor\n";
208  }
209  });
210  while(!visitingStates.empty())
211  {
212  auto current = visitingStates.front();
213  visitingStates.pop_front();
215  [&](DdAutFA::Transition transition)
216  {
217  if(mapping[transition.target()] == 0)
218  {
219  visitingStates.push_back(transition.target());
220  if(std::regex_match(sManager.getStateProperty(fa.getStatePropertyId(transition.target())),reg))
221  {
222  acceptors.push_back(transition.target());
223  mapping[transition.target()]=2;
224  std::cout << sManager.getStateProperty(fa.getStatePropertyId(transition.target())) << " is reachable and must be set acceptor\n";
225  }
226  else
227  {
228  mapping[transition.target()]=1;
229  std::cout << sManager.getStateProperty(fa.getStatePropertyId(transition.target())) << " is reachable and may not be set acceptor\n";
230  }
231  }
232  });
233  }
234 }
235 
236 
237 void tagPredecessors(DdAutFA & fa,std::list<DdAutFA::State> & acceptors, CstStMap<char> & mapping)
238 {
239  std::list<DdAutFA::State> visitingStates = acceptors;
240  while(!visitingStates.empty())
241  {
242  auto current = visitingStates.front();
243  for(const auto & state : acceptors)
244  {
246  }
247 
248  visitingStates.pop_front();
250  [&](DdAutFA::Transition transition)
251  {
252  if(mapping[transition.source()] == 1)
253  {
254  mapping[transition.source()] = 2;
255  visitingStates.push_back(transition.source());
256  applyTag(fa,transition.source(),Tag::prefixclosedfinal);
257  }
258  });
259  }
260 }
261 
262 void setPrefixClosedAcceptorTag(DdAutFA & fa,DdAutStateManager & sManager,std::regex & reg)
263 {
264  CstStMap<char> mapping(fa.behaviour(),fa.numberOfStates(),0);
265  std::list<DdAutFA::State> acceptors;
266  getReachable(fa,mapping,reg,sManager,acceptors);
267  tagPredecessors(fa,acceptors,mapping);
268 }
269 
270 void tagStates(DdAutFA & fa, DdAutStateManager & sManager, const std::string & expr)
271 {
272  auto pos = expr.find_first_of(":");
273  if(pos== std::string::npos)
274  {
275  return;
276  }
277 
278  auto tagIt = tagOf.find(expr.substr(0,pos));
279  if(tagIt != tagOf.end())
280  { auto regexp = expr.substr(pos+1);
281  std::regex reg(regexp);
282  if(tagIt->second!=Tag::prefixclosedfinal)
283  {
284 
285  for(auto & stateProperty: sManager.storage())
286  {
287  if(std::regex_match(stateProperty,reg))
288  {
289  applyTag(fa,fa.getState(sManager.statePropertyId(stateProperty)),tagIt->second);
290  }
291  }
292  }
293  else
294  {
295  setPrefixClosedAcceptorTag(fa,sManager,reg);
296  }
297  }
298  }
299 
300  size_t
301  tagDdAutStates2(const string & fileName, const string & output, const std::vector<std::string> & regexp)
302  {
303  DdAutFileDescriptor descriptor;
304  DdAutEventManager eManager;
305  DdAutStateManager sManager;
306  ifstream file(fileName.c_str());
307  if(file.is_open())
308  {
309  auto loaded = descriptor.readStream(file);
310  file.close();
311  if(!loaded)
312  {
313  return printCommandLineError(Msg("Error when loading the 'ddaut' automaton file %1%") % fileName);
314  }
315  }
316  else
317  {
318  return printCommandLineError(Msg("Error when opening the 'ddaut' automaton file %1%") % fileName);
319  }
320  DdAutFA fa;
321  bool result = faFromDescriptor(descriptor, fa, sManager, eManager);
322  if(!result)
323  {
324  return printCommandLineError(Msg("Error when converting the DdAutFileDescriptor from %1% to a Finite Automaton") % fileName);
325  }
326  for(const auto & expr : regexp)
327  {
328  tagStates(fa,sManager,expr);
329  }
330 
331  if(output.empty())
332  {
333  faToDdAutFile(std::cout,{fa, sManager, eManager});
334  }
335  else
336  {
337  ofstream outfile(output.c_str());
338  if(outfile.is_open())
339  {
340  faToDdAutFile(outfile,{fa, sManager, eManager});
341  outfile.close();
342  }
343  else
344  {
345  return printCommandLineError(Msg("Error when creating the dot file %1%") % output);
346  }
347  }
349  }
350 
351 
352  size_t tagDdAutStates(const string & fileName, const string & output, const std::vector<std::string> & regexp)
353  {
354 
355  if(!output.empty())
356  {
357  if(!suffixes.match(output, "ddaut"))
358  {
359  return printCommandLineError(Msg("Expecting an output file with a name ending with .ddaut, but I read %1%") % output);
360  }
361  }
362 
363  if(suffixes.match(fileName, "ddaut"))
364  {
365  return tagDdAutStates2(fileName, output,regexp);
366  }
367  else
368  {
369  return printCommandLineError(Msg("Expecting a file with a name ending with .ddaut, but I read %1%") % fileName);
370  }
372  }
373 
380  int
381  main(int argc, char** argv)
382  {
383  std::string fileName, output;
384  std::vector<std::string> regexp;
385  try
386  {
387 
388  Poptions::options_description desc("Options");
389  Poptions::variables_map vm;
390  initialiseOptions(argc, argv, desc, vm);
391  if(vm.count("help"))
392  {
394  }
395  if(vm.count("file"))
396  {
397  fileName = vm["file"].as<std::string> ();
398  }
399  if(vm.count("output"))
400  {
401  output = vm["output"].as<std::string>();
402  }
403  if(vm.count("regexp"))
404  {
405  regexp = vm["regexp"].as<std::vector<std::string>>();
406  }
407  }
408  catch(Poptions::required_option & e)
409  {
410  return printCommandLineError(e.what());
411  }
412  catch(Poptions::error & e)
413  {
414  return printCommandLineError(e.what());
415  }
416  if(regexp.empty())
417  {
418  return printCommandLineError(Msg("Expecting at least one regular expression but I got nothing, so I do nothing."));
419  }
420  return tagDdAutStates(fileName, output,regexp);
421  }
422 
423 
const string briefcomment(": this program tags some states based on regular expressions (output file or standard output).")
FileSuffixes suffixes({"ddaut"})
Diades::Graph::ConstNodeMap< Type > CstStMap
Tag
Definition: TagStates.cc:160
void tagPredecessors(DdAutFA &fa, std::list< DdAutFA::State > &acceptors, CstStMap< char > &mapping)
Definition: TagStates.cc:237
StatePropertyManager< DdAutStateLabel, DdAutStateId > DdAutStateManager
Definition: DdAutFile.hh:63
StatePropertyId statePropertyId(const StateProperty &stateProperty)
const size_t ERROR_UNHANDLED_EXCEPTION
Definition: CmdInterface.hh:35
size_t printCommandLineError(const string &msg)
Definition: CmdInterface.cc:98
bool faFromDescriptor(const DdAutFileDescriptor &descriptor, DdAutFA &fa, DdAutStateManager &sManager, DdAutEventManager &eManager)
STL namespace.
vector< string > options(numberOfOptions)
void initialiseOptions(int argc, char *argv[], Poptions::options_description &desc, Poptions::variables_map &vm)
Definition: TagStates.cc:129
OutputTransitionIterator outputTransitionBegin(State s) const
InitialStateIterator initialStateEnd() const
InputTransitionIterator inputTransitionBegin(State s) const
bool faToDdAutFile(ostream &stream, const ConstManagedDdAutFA &mFa)
void setPrefixClosedAcceptorTag(DdAutFA &fa, DdAutStateManager &sManager, std::regex &reg)
Definition: TagStates.cc:262
bool match(const std::string &fileName, const std::string &suffix) const
Definition: CmdInterface.cc:54
int main(int argc, char **argv)
Definition: TagStates.cc:381
size_t tagDdAutStates2(const string &fileName, const string &output, const std::vector< std::string > &regexp)
Definition: TagStates.cc:301
FiniteAutomaton< DdAutStateId, DdAutEventId > DdAutFA
Definition: DdAutFile.hh:47
std::pair< AcceptingStateIterator, bool > setAcceptingState(State state)
string tag(SpecialisedActiveDiagnoser::Tag tag)
OutputTransitionIterator outputTransitionEnd(State s) const
void tagStates(DdAutFA &fa, DdAutStateManager &sManager, const std::string &expr)
Definition: TagStates.cc:270
InputTransitionIterator inputTransitionEnd(State s) const
Definition: Run.cc:83
const string detailedcomment
Definition: TagStates.cc:76
void applyTag(DdAutFA &fa, DdAutFA::State state, Tag tag)
Definition: TagStates.cc:173
const string program("dd-tagstates")
InitialStateIterator initialStateBegin() const
EventManager< DdAutEventLabel, DdAutEventId > DdAutEventManager
Definition: DdAutFile.hh:68
size_t tagDdAutStates(const string &fileName, const string &output, const std::vector< std::string > &regexp)
Definition: TagStates.cc:352
const std::unordered_map< std::string, Tag > tagOf
Definition: TagStates.cc:163
void getReachable(DdAutFA &fa, CstStMap< char > &mapping, std::regex &reg, DdAutStateManager &sManager, std::list< DdAutFA::State > &acceptors)
Definition: TagStates.cc:188
StateMachine< DdAutStateId, DdAutEventId > DdAutFsm
Definition: DdAutFile.hh:42
boost::format Msg
Definition: Verbose.hh:42
const StatePropertyId & getStatePropertyId(State state) const
const std::vector< Info > & storage() const
Definition: InfoManager.hh:408
const StateProperty & getStateProperty(StatePropertyId id) const
AcceptingStateIterator unsetAcceptingState(State state)
void swapAcceptingState(State state)
swap the status of the state as accepting/non-accepting
State getState(const StatePropertyId &sProperty) const
void swapInitialState(State state)
swap the status of the state as initial/non-initial
virtual bool readStream(std::istream &stream)
void printUsage(const po::options_description &desc)