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 copy on heap
96 *
97 * @return
98 * new Generator
99 */
100 TrGenerator* NewCpy(void) const;
101
102 /**
103 * Type test.
104 *
105 * Uses C++ dynamic cast to test whether the specified object
106 * casts to a RabinAutomaton.
107 *
108 * NOT IMPLEMENTED
109 *
110 * @param pOther
111 * poinetr to object to test
112 *
113 * @return
114 * TpGenerator reference if dynamic cast succeeds, else NULL
115 */
116 virtual const Type* Cast(const Type* pOther) const {
117 return dynamic_cast< const TrGenerator* > (pOther); };
118
119
120 /**
121 * Copyment operator (uses Copy)
122 *
123 * Note: you must reimplement this operator in derived
124 * classes in order to handle internal pointers correctly
125 *
126 * @param rOtherGen
127 * Other generator
128 */
129 TrGenerator& operator= (const TrGenerator& rOtherGen);
130
131 /**
132 * Copyment method
133 *
134 * Note: you must reimplement this method in derived
135 * classes in order to handle internal pointers correctly
136 *
137 * @param rSource
138 * Other generator
139 */
140 virtual TrGenerator& Copy(const Type& rSource);
141
142 /**
143 * Set Rabin acceptance Condition
144 *
145 * @param rRabAcc
146 * Acceptance conditiomn to set
147 *
148 */
149 void RabinAcceptance(const faudes::RabinAcceptance& rRabAcc);
150
151 /**
152 * Get Rabin acceptance condition
153 *
154 *
155 */
156 const faudes::RabinAcceptance& RabinAcceptance(void) const;
157
158 /**
159 * Get Rabin acceotance condition
160 *
161 */
163
164 /**
165 * Set Rabin acceptance condition from marked states
166 *
167 * This methods interprets the specified states as Buechi acceptance
168 * condition and constructs an equivalient Rabin avvecptance condition.
169 */
170 void RabinAcceptance(const StateSet& rMarking);
171
172 /**
173 * Pretty print Rabin acceotance condition
174 *
175 * not yet implemanted
176 *
177 */
178 void RabinAcceptanceWrite(void) const;
179
180 /**
181 * Restrict states
182 *
183 * Cleans mpStates, mInitStates, mMarkedStates, mpTransrel, and mpStateSymboltable.
184 * We reimplement this method to also care about the acceptance condition.
185 *
186 * @param rStates
187 * StateSet containing valid states
188 */
189 virtual void RestrictStates(const StateSet& rStates);
190
191
192 /**
193 * Writes generator to dot input format.
194 *
195 * The dot file format is specified by the graphiz package; see http://www.graphviz.org. The package
196 * includes the dot command line tool to generate a graphical representation of the generators graph.
197 * See also Generator::GrphWrite(). *
198 * This functions sets the re-indexing to minimal indices.
199 *
200 * @param rFileName
201 * Name of file to save result
202 */
203 virtual void DotWrite(const std::string& rFileName) const;
204
205 protected:
206
207 /** need to reimplement to care about Additional members */
208 void DoCopy(const TrGenerator& rSrc);
209
210
211
212}; // end class TpGenerator
213
214
215/**
216 * Convenience typedef for std prioritised generator
217 */
219
220
221
222/*
223***************************************************************************
224***************************************************************************
225***************************************************************************
226
227Implementation pGenerator
228
229***************************************************************************
230***************************************************************************
231***************************************************************************
232*/
233
234/* convenience access to relevant scopes */
235#define THIS TrGenerator<GlobalAttr, StateAttr, EventAttr, TransAttr>
236#define BASE TcGenerator<GlobalAttr, StateAttr, EventAttr, TransAttr>
237#define TEMP template <class GlobalAttr, class StateAttr, class EventAttr, class TransAttr>
238
239
240// TrGenerator(void)
241TEMP THIS::TrGenerator(void) : BASE() {
242 FD_DG("TrGenerator(" << this << ")::TrGenerator()");
243}
244
245// TrGenerator(rOtherGen)
246TEMP THIS::TrGenerator(const TrGenerator& rOtherGen) : BASE(rOtherGen) {
247 FD_DG("TrGenerator(" << this << ")::TrGenerator(rOtherGen)");
248}
249
250// TrGenerator(rOtherGen)
251TEMP THIS::TrGenerator(const vGenerator& rOtherGen) : BASE(rOtherGen) {
252 FD_DG("TrGenerator(" << this << ")::TrGenerator(rOtherGen)");
253}
254
255// TrGenerator(rFilename)
256TEMP THIS::TrGenerator(const std::string& rFileName) : BASE(rFileName) {
257 FD_DG("TrGenerator(" << this << ")::TrGenerator(rFilename) : done");
258}
259
260// full assign of matching type (not virtual)
261TEMP void THIS::DoCopy(const TrGenerator& rSrc) {
262 FD_DG("TrGenerator(" << this << ")::operator = " << &rOtherGen);
263 // recursive call base, incl virtual clear
264 BASE::DoCopy(rSrc);
265}
266
267// operator=
268TEMP THIS& THIS::operator= (const TrGenerator& rSrc) {
269 FD_DG("TrGenerator(" << this << ")::operator = " << &rSrc);
270 DoCopy(rSrc);
271 return *this;
272}
273
274// copy from other faudes type
275TEMP THIS& THIS::Copy(const Type& rSrc) {
276 // bail out on match
277 if(&rSrc==static_cast<const Type*>(this))
278 return *this;
279 // dot if we can
280 const THIS* pgen=dynamic_cast<const THIS*>(&rSrc);
281 if(pgen!=nullptr) {
282 DoCopy(*pgen);
283 return *this;
284 }
285 // pass on to base
286 FD_DG("TrGenerator(" << this << ")::Copy([type] " << &rSrc << "): call base");
287 BASE::Copy(rSrc);
288 return *this;
289}
290
291// New
292TEMP THIS* THIS::New(void) const {
293 // allocate
294 THIS* res = new THIS;
295 // fix base data
296 res->EventSymbolTablep(BASE::mpEventSymbolTable);
297 res->mStateNamesEnabled=BASE::mStateNamesEnabled;
298 res->mReindexOnWrite=BASE::mReindexOnWrite;
299 return res;
300}
301
302// Copy
303TEMP THIS* THIS::NewCpy(void) const {
304 // allocate
305 THIS* res = new THIS(*this);
306 // done
307 return res;
308}
309
310// Member access, set
311TEMP void THIS::RabinAcceptance(const faudes::RabinAcceptance& rRabAcc) {
312 BASE::GlobalAttribute(rRabAcc);
313}
314
315// Member access, get by ref
316TEMP RabinAcceptance& THIS::RabinAcceptance(void) {
317 return *BASE::GlobalAttributep();
318}
319
320// Member access, get by const ref
321TEMP const RabinAcceptance& THIS::RabinAcceptance(void) const {
322 return BASE::GlobalAttribute();
323}
324
325// Member access, set
326TEMP void THIS::RabinAcceptance(const StateSet& rMarking) {
328 RabinPair rpair;
329 rpair.ISet()=THIS::States();
330 rpair.RSet()=rMarking;
331 RabinAcceptance().Insert(rpair);
332}
333
334// pretty print
335TEMP void THIS::RabinAcceptanceWrite(void) const {
336 this->RabinAcceptance().Write(this);
337}
338
339// reimplememt
340TEMP void THIS::RestrictStates(const StateSet& rStates) {
341 BASE::RestrictStates(rStates);
342 this->RabinAcceptance().RestrictStates(rStates);
343}
344
345
346// DotWrite(rFileName), second version, using HTML style lables inspired by ltldstar
347TEMP void THIS::DotWrite(const std::string& rFileName) const {
348 FD_DG("RabinAutomaton(" << this << ")::DotWrite(" << rFileName << ")");
349 // prepare
350 if(BASE::ReindexOnWrite()) BASE::SetMinStateIndexMap();
351 TransSetX1X2Ev trx1x2ev(BASE::TransRel());
352 StateSet::Iterator lit;
354 // list of colors (pairs light vs. solid for I-Set and R-Set)
355 std::vector<std::string> ColorPalette;
356 ColorPalette.push_back("lightblue"); // X11 light blue
357 ColorPalette.push_back("darkblue"); // X11 dark blue
358 ColorPalette.push_back("#ffcc80"); // my light orange
359 ColorPalette.push_back("#ff9900"); // my dark orange
360 ColorPalette.push_back("#b0ffb0"); // my light green
361 ColorPalette.push_back("#307030"); // my dark green
362 ColorPalette.push_back("#ff9090"); // my light red
363 ColorPalette.push_back("#a00202"); // my dark red
364 ColorPalette.push_back("black"); // have black for std marking
365 if(2*THIS::RabinAcceptance().Size()>ColorPalette.size()-1) {
366 FD_DG("RabinAutomaton(" << this << ")::DotWrite(...): to many Rabin pairs");
367 BASE::DotWrite(rFileName);
368 return;
369 }
370 // do dot write
371 try {
372 std::ofstream stream;
373 stream.exceptions(std::ios::badbit|std::ios::failbit);
374
375 // header
376 stream.open(rFileName.c_str());
377 stream << "// dot output generated by libFAUDES RabinAutomaton" << std::endl;
378 stream << "digraph \"" << BASE::Name() << "\" {" << std::endl;
379 stream << " rankdir=LR" << std::endl;
380 //stream << " bgcolor=\"transparent\"" << std::endl;
381 stream << " node [shape=rectangle, style=rounded];" << std::endl;
382 stream << std::endl;
383
384 // initial state(s)
385 stream << " // initial states" << std::endl;
386 int i=0;
387 for (lit = BASE::InitStatesBegin(); lit != BASE::InitStatesEnd(); ++lit) {
388 std::string xname= BASE::StateName(*lit);
389 if(xname=="") xname=ToStringInteger(static_cast<long int>(BASE::MinStateIndex(*lit)));
390 stream << " dot_dummyinit_" << i << " [shape=none, label=\"\" ];" << std::endl;
391 stream << " dot_dummyinit_" << i << " -> \"" << xname << "\";" << std::endl;
392 i++;
393 }
394 stream << std::endl;
395
396 // figure marked states
397 StateSet marked;
398 RabinAcceptance::CIterator rit;
399 for(rit=THIS::RabinAcceptance().Begin();rit!=THIS::RabinAcceptance().End();++rit) {
400 marked = marked + rit->ISet();
401 marked = marked + rit->RSet();
402 }
403 marked.InsertSet(this->MarkedStates());
404
405 // uncolored states - output
406 stream << " // plain states" << std::endl;
407 for (lit = BASE::pStates->Begin(); lit != BASE::pStates->End(); ++lit) {
408 if(marked.Exists(*lit)) continue;
409 std::string xname=BASE::StateName(*lit);
410 if(xname=="") xname=ToStringInteger(BASE::MinStateIndex(*lit));
411 stream << " \"" << xname << "\";" << std::endl;
412 }
413 stream << std::endl;
414
415 // colored states
416 stream << " // colored states" << std::endl;
417 for (lit = marked.Begin(); lit != marked.End(); ++lit) {
418 std::string xname=BASE::StateName(*lit);
419 if(xname=="") xname=ToStringInteger(static_cast<long int>(BASE::MinStateIndex(*lit)));
420 stream << " \"" << xname << "\"";
421 // figure the colors by testing each rabin pair
422 RabinAcceptance::CIterator rit;
423 std::vector<int> colvec;
424 int col=0;
425 for(rit=THIS::RabinAcceptance().Begin();rit!=THIS::RabinAcceptance().End();++rit) {
426 if(rit->ISet().Exists(*lit)) colvec.push_back(col);
427 if(rit->RSet().Exists(*lit)) colvec.push_back(col+1);
428 col+=2;
429 }
430 // add traditional marking (black is at the end of our palette)
431 if(this->ExistsMarkedState(*lit))
432 colvec.push_back(ColorPalette.size()-1);
433 // begin HTML label
434 stream << " [label=<<TABLE BORDER=\"0\"><TR>";
435 // add state name to table
436 stream << "<TD>" << xname << "</TD>";
437 // add hspace to table
438 stream << "<TD WIDTH=\"5\"></TD>";
439 // assembling td elements per color
440 size_t i;
441 for(i=0;i<colvec.size();++i) {
442 stream << "<TD BGCOLOR=\"" << ColorPalette.at(colvec.at(i)) << "\" BORDER=\"0\" WIDTH=\"10\"></TD>";
443 }
444 // finalize table
445 stream << "</TR></TABLE>>";
446 stream << "];" << std::endl;
447 }
448
449 // transrel
450 stream << " // transition relation" << std::endl;
451 std::string elabel;
452 for(tit = trx1x2ev.Begin(); tit != trx1x2ev.End();) {
453 // accumulate label
454 if(!elabel.empty()) elabel = elabel + ", ";
455 if(elabel.length()>9) elabel = elabel + "\n";
456 elabel=elabel + BASE::EventName(tit->Ev);
457 Idx x1=tit->X1;
458 Idx x2=tit->X2;
459 bool flush=false;
460 // next transition
461 ++tit;
462 if(tit==trx1x2ev.End())
463 flush =true;
464 else
465 flush=((tit->X1 != x1) || (tit->X2 != x2));
466 // write out
467 if(flush) {
468 std::string x1name= BASE::StateName(x1);
469 if(x1name=="") x1name=ToStringInteger(BASE::MinStateIndex(x1));
470 std::string x2name= BASE::StateName(x2);
471 if(x2name=="") x2name=ToStringInteger(BASE::MinStateIndex(x2));
472 stream << " \"" << x1name << "\" -> \"" << x2name
473 << "\" [label=\"" << elabel << "\"];" << std::endl;
474 elabel="";
475 }
476 }
477
478 // finalize
479 stream << "}" << std::endl;
480 stream.close();
481 }
482 catch (std::ios::failure&) {
483 throw Exception("TaGenerator::DotWrite",
484 "Exception opening/writing dotfile \""+rFileName+"\"", 3);
485 }
486 BASE::ClearMinStateIndexMap();
487}
488
489
490#undef TEMP
491#undef BASE
492#undef THIS
493
494
495
496} // namespace faudes
497#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.34e --- 2026.03.16 --- c++ api documentaion by doxygen