omg_rabinaut.h
Go to the documentation of this file.
1/** @file omg_rabinaut.h Class RabinAutomaton */
2
3
4/* FAU Discrete Event Systems Library (libfaudes)
5
6 Copyright (C) 2025 Thomas Moor
7 Exclusive copyright is granted to Klaus Schmidt
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public
20 License along with this library; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23#ifndef FAUDES_OMG_RABINAUT_H
24#define FAUDES_OMG_RABINAUT_H
25
26#include "corefaudes.h"
27#include "omg_rabinacc.h"
28
29namespace faudes {
30
31
32/**
33 * Generator with Rabin acceptance conditiom.
34 *
35 * @section SecRabinAut Overview
36 *
37 * The TrGenerator is a variant of the TcGenerator to add an interface for a Rabin acceptance condition.
38 * For convenience, the configuration with the minimum attributes is been typedef-ed as RabinAutomaton.
39 *
40 * Technically, the construct is based on the global attribute class faudes::RabinAcceptance
41 * derived from faudes::AttributeVoid. Hence TrGenerator expects an event attribute template parameter
42 * with the minimum interface defined in RabinAcceptance.
43 *
44 * The current implementation provides the absolute minimum member access, i.e., methods to get and
45 * the acceptance condition. A future implementation may be more elaborate at this end.
46 *
47 *
48 * @ingroup GeneratorClasses
49 */
50
51template <class GlobalAttr, class StateAttr, class EventAttr, class TransAttr>
52 class FAUDES_TAPI TrGenerator : public TcGenerator<GlobalAttr, StateAttr, EventAttr, TransAttr> {
53 public:
54
55
56 /**
57 * Creates an emtpy RabinAutomaton object
58 */
59 TrGenerator(void);
60
61 /**
62 * RabinAutomaton from a std Generator. Copy constructor
63 *
64 * @param rOtherGen
65 */
66 TrGenerator(const vGenerator& rOtherGen);
67
68 /**
69 * RabinAutomaton from RabinAutomaton. Copy constructor
70 *
71 * @param rOtherGen
72 */
73 TrGenerator(const TrGenerator& rOtherGen);
74
75 /**
76 * Construct from file
77 *
78 * @param rFileName
79 * Filename
80 *
81 * @exception Exception
82 * If opening/reading fails an Exception object is thrown (id 1, 50, 51)
83 */
84 TrGenerator(const std::string& rFileName);
85
86 /**
87 * Construct on heap
88 *
89 * @return
90 * new Generator
91 */
92 TrGenerator* New(void) const;
93
94 /**
95 * Construct on stack
96 *
97 * @return
98 * new Generator
99 */
100 TrGenerator NewRGen(void) const;
101
102 /**
103 * Construct copy on heap
104 *
105 * @return
106 * new Generator
107 */
108 TrGenerator* Copy(void) const;
109
110 /**
111 * Type test.
112 *
113 * Uses C++ dynamic cast to test whether the specified object
114 * casts to a RabinAutomaton.
115 *
116 * NOT IMPLEMENTED
117 *
118 * @param pOther
119 * poinetr to object to test
120 *
121 * @return
122 * TpGenerator reference if dynamic cast succeeds, else NULL
123 */
124 virtual const Type* Cast(const Type* pOther) const {
125 return dynamic_cast< const TrGenerator* > (pOther); };
126
127
128 /**
129 * Assignment operator (uses Assign)
130 *
131 * Note: you must reimplement this operator in derived
132 * classes in order to handle internal pointers correctly
133 *
134 * @param rOtherGen
135 * Other generator
136 */
137 TrGenerator& operator= (const TrGenerator& rOtherGen);
138
139 /**
140 * Assignment method
141 *
142 * Note: you must reimplement this method in derived
143 * classes in order to handle internal pointers correctly
144 *
145 * @param rSource
146 * Other generator
147 */
148 virtual TrGenerator& Assign(const Type& rSource);
149
150 /**
151 * Set Rabin acceptance Condition
152 *
153 * @param rRabAcc
154 * Acceptance conditiomn to set
155 *
156 */
157 void RabinAcceptance(const faudes::RabinAcceptance& rRabAcc);
158
159 /**
160 * Get Rabin acceptance condition
161 *
162 *
163 */
164 const faudes::RabinAcceptance& RabinAcceptance(void) const;
165
166 /**
167 * Get Rabin acceotance condition
168 *
169 */
171
172 /**
173 * Set Rabin acceptance condition from marked states
174 *
175 * This methods interprets the specified states as Buechi acceptance
176 * condition and constructs an equivalient Rabin avvecptance condition.
177 */
178 void RabinAcceptance(const StateSet& rMarking);
179
180 /**
181 * Pretty print Rabin acceotance condition
182 *
183 * not yet implemanted
184 *
185 */
186 void RabinAcceptanceWrite(void) const;
187
188 /**
189 * Restrict states
190 *
191 * Cleans mpStates, mInitStates, mMarkedStates, mpTransrel, and mpStateSymboltable.
192 * We reimplement this method to also care about the acceptance condition.
193 *
194 * @param rStates
195 * StateSet containing valid states
196 */
197 virtual void RestrictStates(const StateSet& rStates);
198
199
200 /**
201 * Writes generator to dot input format.
202 *
203 * The dot file format is specified by the graphiz package; see http://www.graphviz.org. The package
204 * includes the dot command line tool to generate a graphical representation of the generators graph.
205 * See also Generator::GrphWrite(). *
206 * This functions sets the re-indexing to minimal indices.
207 *
208 * @param rFileName
209 * Name of file to save result
210 */
211 virtual void DotWrite(const std::string& rFileName) const;
212
213 protected:
214
215 /** need to reimplement to care about Additional members */
216 void DoAssign(const TrGenerator& rSrc);
217
218
219
220}; // end class TpGenerator
221
222
223/**
224 * Convenience typedef for std prioritised generator
225 */
227
228
229
230/*
231***************************************************************************
232***************************************************************************
233***************************************************************************
234
235Implementation pGenerator
236
237***************************************************************************
238***************************************************************************
239***************************************************************************
240*/
241
242/* convenience access to relevant scopes */
243#define THIS TrGenerator<GlobalAttr, StateAttr, EventAttr, TransAttr>
244#define BASE TcGenerator<GlobalAttr, StateAttr, EventAttr, TransAttr>
245#define TEMP template <class GlobalAttr, class StateAttr, class EventAttr, class TransAttr>
246
247
248// TrGenerator(void)
249TEMP THIS::TrGenerator(void) : BASE() {
250 FD_DG("TrGenerator(" << this << ")::TrGenerator()");
251}
252
253// TrGenerator(rOtherGen)
254TEMP THIS::TrGenerator(const TrGenerator& rOtherGen) : BASE(rOtherGen) {
255 FD_DG("TrGenerator(" << this << ")::TrGenerator(rOtherGen)");
256}
257
258// TrGenerator(rOtherGen)
259TEMP THIS::TrGenerator(const vGenerator& rOtherGen) : BASE(rOtherGen) {
260 FD_DG("TrGenerator(" << this << ")::TrGenerator(rOtherGen)");
261}
262
263// TrGenerator(rFilename)
264TEMP THIS::TrGenerator(const std::string& rFileName) : BASE(rFileName) {
265 FD_DG("TrGenerator(" << this << ")::TrGenerator(rFilename) : done");
266}
267
268// full assign of matching type (not virtual)
269TEMP void THIS::DoAssign(const TrGenerator& rSrc) {
270 FD_DG("TrGenerator(" << this << ")::operator = " << &rOtherGen);
271 // recursive call base, incl virtual clear
272 BASE::DoAssign(rSrc);
273}
274
275// operator=
276TEMP THIS& THIS::operator= (const TrGenerator& rSrc) {
277 FD_DG("TrGenerator(" << this << ")::operator = " << &rSrc);
278 DoAssign(rSrc);
279 return *this;
280}
281
282// copy from other faudes type
283TEMP THIS& THIS::Assign(const Type& rSrc) {
284 // bail out on match
285 if(&rSrc==static_cast<const Type*>(this))
286 return *this;
287 // dot if we can
288 const THIS* pgen=dynamic_cast<const THIS*>(&rSrc);
289 if(pgen!=nullptr) {
290 DoAssign(*pgen);
291 return *this;
292 }
293 // pass on to base
294 FD_DG("TrGenerator(" << this << ")::Assign([type] " << &rSrc << "): call base");
295 BASE::Assign(rSrc);
296 return *this;
297}
298
299// New
300TEMP THIS* THIS::New(void) const {
301 // allocate
302 THIS* res = new THIS;
303 // fix base data
304 res->EventSymbolTablep(BASE::mpEventSymbolTable);
305 res->mStateNamesEnabled=BASE::mStateNamesEnabled;
306 res->mReindexOnWrite=BASE::mReindexOnWrite;
307 return res;
308}
309
310// Copy
311TEMP THIS* THIS::Copy(void) const {
312 // allocate
313 THIS* res = new THIS(*this);
314 // done
315 return res;
316}
317
318// NewPGen
319TEMP THIS THIS::NewRGen(void) const {
320 // call base (fixes by assignment constructor)
321 THIS res= BASE::NewCGen();
322 return res;
323}
324
325// Member access, set
326TEMP void THIS::RabinAcceptance(const faudes::RabinAcceptance& rRabAcc) {
327 BASE::GlobalAttribute(rRabAcc);
328}
329
330// Member access, get by ref
331TEMP RabinAcceptance& THIS::RabinAcceptance(void) {
332 return *BASE::GlobalAttributep();
333}
334
335// Member access, get by const ref
336TEMP const RabinAcceptance& THIS::RabinAcceptance(void) const {
337 return BASE::GlobalAttribute();
338}
339
340// Member access, set
341TEMP void THIS::RabinAcceptance(const StateSet& rMarking) {
343 RabinPair rpair;
344 rpair.ISet()=THIS::States();
345 rpair.RSet()=rMarking;
346 RabinAcceptance().Insert(rpair);
347}
348
349// pretty print
350TEMP void THIS::RabinAcceptanceWrite(void) const {
351 this->RabinAcceptance().Write(this);
352}
353
354// reimplememt
355TEMP void THIS::RestrictStates(const StateSet& rStates) {
356 BASE::RestrictStates(rStates);
357 this->RabinAcceptance().RestrictStates(rStates);
358}
359
360
361// DotWrite(rFileName), second version, using HTML style lables inspired by ltldstar
362TEMP void THIS::DotWrite(const std::string& rFileName) const {
363 FD_DG("RabinAutomaton(" << this << ")::DotWrite(" << rFileName << ")");
364 // prepare
365 if(BASE::ReindexOnWrite()) BASE::SetMinStateIndexMap();
366 TransSetX1X2Ev trx1x2ev(BASE::TransRel());
367 StateSet::Iterator lit;
369 // list of colors (pairs light vs. solid for I-Set and R-Set)
370 std::vector<std::string> ColorPalette;
371 ColorPalette.push_back("lightblue"); // X11 light blue
372 ColorPalette.push_back("darkblue"); // X11 dark blue
373 ColorPalette.push_back("#ffcc80"); // my light orange
374 ColorPalette.push_back("#ff9900"); // my dark orange
375 ColorPalette.push_back("#b0ffb0"); // my light green
376 ColorPalette.push_back("#307030"); // my dark green
377 ColorPalette.push_back("#ff9090"); // my light red
378 ColorPalette.push_back("#a00202"); // my dark red
379 ColorPalette.push_back("black"); // have black for std marking
380 if(2*THIS::RabinAcceptance().Size()>ColorPalette.size()-1) {
381 FD_DG("RabinAutomaton(" << this << ")::DotWrite(...): to many Rabin pairs");
382 BASE::DotWrite(rFileName);
383 return;
384 }
385 // do dot write
386 try {
387 std::ofstream stream;
388 stream.exceptions(std::ios::badbit|std::ios::failbit);
389
390 // header
391 stream.open(rFileName.c_str());
392 stream << "// dot output generated by libFAUDES RabinAutomaton" << std::endl;
393 stream << "digraph \"" << BASE::Name() << "\" {" << std::endl;
394 stream << " rankdir=LR" << std::endl;
395 //stream << " bgcolor=\"transparent\"" << std::endl;
396 stream << " node [shape=rectangle, style=rounded];" << std::endl;
397 stream << std::endl;
398
399 // initial state(s)
400 stream << " // initial states" << std::endl;
401 int i=0;
402 for (lit = BASE::InitStatesBegin(); lit != BASE::InitStatesEnd(); ++lit) {
403 std::string xname= BASE::StateName(*lit);
404 if(xname=="") xname=ToStringInteger(static_cast<long int>(BASE::MinStateIndex(*lit)));
405 stream << " dot_dummyinit_" << i << " [shape=none, label=\"\" ];" << std::endl;
406 stream << " dot_dummyinit_" << i << " -> \"" << xname << "\";" << std::endl;
407 i++;
408 }
409 stream << std::endl;
410
411 // figure marked states
412 StateSet marked;
413 RabinAcceptance::CIterator rit;
414 for(rit=THIS::RabinAcceptance().Begin();rit!=THIS::RabinAcceptance().End();++rit) {
415 marked = marked + rit->ISet();
416 marked = marked + rit->RSet();
417 }
418 marked.InsertSet(this->MarkedStates());
419
420 // uncolored states - output
421 stream << " // plain states" << std::endl;
422 for (lit = BASE::pStates->Begin(); lit != BASE::pStates->End(); ++lit) {
423 if(marked.Exists(*lit)) continue;
424 std::string xname=BASE::StateName(*lit);
425 if(xname=="") xname=ToStringInteger(BASE::MinStateIndex(*lit));
426 stream << " \"" << xname << "\";" << std::endl;
427 }
428 stream << std::endl;
429
430 // colored states
431 stream << " // colored states" << std::endl;
432 for (lit = marked.Begin(); lit != marked.End(); ++lit) {
433 std::string xname=BASE::StateName(*lit);
434 if(xname=="") xname=ToStringInteger(static_cast<long int>(BASE::MinStateIndex(*lit)));
435 stream << " \"" << xname << "\"";
436 // figure the colors by testing each rabin pair
437 RabinAcceptance::CIterator rit;
438 std::vector<int> colvec;
439 int col=0;
440 for(rit=THIS::RabinAcceptance().Begin();rit!=THIS::RabinAcceptance().End();++rit) {
441 if(rit->ISet().Exists(*lit)) colvec.push_back(col);
442 if(rit->RSet().Exists(*lit)) colvec.push_back(col+1);
443 col+=2;
444 }
445 // add traditional marking (black is at the end of our palette)
446 if(this->ExistsMarkedState(*lit))
447 colvec.push_back(ColorPalette.size()-1);
448 // begin HTML label
449 stream << " [label=<<TABLE BORDER=\"0\"><TR>";
450 // add state name to table
451 stream << "<TD>" << xname << "</TD>";
452 // add hspace to table
453 stream << "<TD WIDTH=\"5\"></TD>";
454 // assembling td elements per color
455 size_t i;
456 for(i=0;i<colvec.size();++i) {
457 stream << "<TD BGCOLOR=\"" << ColorPalette.at(colvec.at(i)) << "\" BORDER=\"0\" WIDTH=\"10\"></TD>";
458 }
459 // finalize table
460 stream << "</TR></TABLE>>";
461 stream << "];" << std::endl;
462 }
463
464 // transrel
465 stream << " // transition relation" << std::endl;
466 std::string elabel;
467 for(tit = trx1x2ev.Begin(); tit != trx1x2ev.End();) {
468 // accumulate label
469 if(!elabel.empty()) elabel = elabel + ", ";
470 if(elabel.length()>9) elabel = elabel + "\n";
471 elabel=elabel + BASE::EventName(tit->Ev);
472 Idx x1=tit->X1;
473 Idx x2=tit->X2;
474 bool flush=false;
475 // next transition
476 ++tit;
477 if(tit==trx1x2ev.End())
478 flush =true;
479 else
480 flush=((tit->X1 != x1) || (tit->X2 != x2));
481 // write out
482 if(flush) {
483 std::string x1name= BASE::StateName(x1);
484 if(x1name=="") x1name=ToStringInteger(BASE::MinStateIndex(x1));
485 std::string x2name= BASE::StateName(x2);
486 if(x2name=="") x2name=ToStringInteger(BASE::MinStateIndex(x2));
487 stream << " \"" << x1name << "\" -> \"" << x2name
488 << "\" [label=\"" << elabel << "\"];" << std::endl;
489 elabel="";
490 }
491 }
492
493 // finalize
494 stream << "}" << std::endl;
495 stream.close();
496 }
497 catch (std::ios::failure&) {
498 throw Exception("TaGenerator::DotWrite",
499 "Exception opening/writing dotfile \""+rFileName+"\"", 3);
500 }
501 BASE::ClearMinStateIndexMap();
502}
503
504
505#undef TEMP
506#undef BASE
507#undef THIS
508
509
510
511} // namespace faudes
512#endif // _H
#define TEMP
#define BASE
#define THIS
#define FD_DG(message)
#define FAUDES_TAPI
void RestrictStates(const StateSet &rDomain)
StateSet & RSet(void)
StateSet & ISet(void)
virtual void Insert(const T &rElem)
Iterator Begin(void) const
Iterator End(void) const
virtual const Type * Cast(const Type *pOther) const
void Write(const Type *pContext=0) const
virtual void Clear(void)
bool Exists(const T &rElem) const
Iterator End(void) const
virtual void InsertSet(const TBaseSet &rOtherSet)
Iterator Begin(void) const
uint32_t Idx
TrGenerator< RabinAcceptance, AttributeVoid, AttributeCFlags, AttributeVoid > RabinAutomaton
std::string ToStringInteger(Int number)
Definition cfl_utils.cpp:43

libFAUDES 2.33k --- 2025.09.16 --- c++ api documentaion by doxygen