cfl_determin.cpp
Go to the documentation of this file.
1/** @file cfl_determin.cpp powerset construction */
2
3/* FAU Discrete Event Systems Library (libfaudes)
4
5 Copyright (C) 2006 Bernd Opitz
6 Exclusive copyright is granted to Klaus Schmidt
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
21
22
23#include "cfl_determin.h"
24
25namespace faudes {
26
27// UniqueInit(rGen&)
28void UniqueInit(Generator& rGen) {
29 Idx inituni;
30 StateSet::Iterator lit;
32 // check number of initial states
33 if(rGen.InitStatesSize() == 1) return;
34 // introduce new initial state
35 if(rGen.StateNamesEnabled()) {
36 std::string initname=rGen.UniqueStateName("InitUni");
37 inituni = rGen.InsState(initname);
38 } else {
39 inituni = rGen.InsState();
40 }
41 FD_DF("UniqueInit: introducing new initial state: " << inituni);
42 // introduce outgoing transitions from initial state
43 FD_DF("UniqueInit: introduce outgoing transitions: ");
44 for (lit = rGen.InitStatesBegin(); lit != rGen.InitStatesEnd(); ++lit) {
45 for (tit = rGen.TransRelBegin(*lit); tit != rGen.TransRelEnd(*lit); ++tit) {
46 rGen.SetTransition(inituni, tit->Ev, tit->X2);
47 FD_DF("UniqueInit: " << inituni << "-" << tit->Ev << "-" << tit->X2);
48 }
49 }
50 // mark the new init state if there exists an originally marked init state (tm 20101206)
51 if(!(rGen.InitStates() * rGen.MarkedStates()).Empty()){
52 rGen.SetMarkedState(inituni);
53 FD_DF("UniqueInit: set marked state: " << inituni);
54 }
55 // delete old istates
56 rGen.ClearInitStates();
57 // set inituni as new initial state
58 rGen.SetInitState(inituni);
59}
60
61// UniqueInit(rGen&,rResGen&)
62void UniqueInit(const Generator& rGen, Generator& rResGen) {
63 rResGen.Assign(rGen);
64 UniqueInit(rResGen);
65}
66
67// Deterministic(rGen&, rResGen&)
68void Deterministic(const Generator& rGen, Generator& rResGen) {
69 // temporary vectors
70 std::vector<StateSet> power_states;
71 std::vector<Idx> det_states;
72 Deterministic(rGen, power_states, det_states, rResGen);
73}
74
75
76// aDeterministic(rGen&, rResGen&)
77void aDeterministic(const Generator& rGen, Generator& rResGen) {
78 // prepare result to keep original alphabet
79 Generator* pResGen = &rResGen;
80 if(&rResGen==&rGen) {
81 pResGen= rResGen.New();
82 }
83 // perform op
84 Deterministic(rGen,*pResGen);
85 // set old attributes
86 pResGen->EventAttributes(rGen.Alphabet());
87 // copy result
88 if(pResGen != &rResGen) {
89 pResGen->Move(rResGen);
90 delete pResGen;
91 }
92}
93
94
95// Deterministic(rGen&, rEntryStatesMap&, rResGen&)
96void Deterministic(const Generator& rGen, std::map<Idx,StateSet>& rEntryStatesMap,
97 Generator& rResGen) {
98 // prepare result:
99 rEntryStatesMap.clear();
100 // helpers:
101 std::vector<StateSet> power_states;
102 std::vector<Idx> det_states;
103 // call Deterministic function
104 Deterministic(rGen, power_states, det_states, rResGen);
105 // build entry states map
106 std::vector<StateSet>::size_type i;
107 for (i = 0; i < power_states.size(); ++i) {
108 rEntryStatesMap.insert(std::pair<Idx,StateSet>(det_states[i], power_states[i]));
109 }
110}
111
112
113void Deterministic(const Generator& rGen, std::vector<StateSet>& rPowerStates,
114 std::vector<Idx>& rDetStates, Generator& rResGen) {
115
116 // note: there is a demonstrative description of the multiway merge
117 // algorithm in the master thesis. (Bernd Opitz)
118
119 FD_DF("Deterministic(): core function #" << rGen.Size());
120
121 // use pointer pResGen to result rResGen
122 Generator* pResGen = &rResGen;
123 if(&rResGen== &rGen) {
124 pResGen= rResGen.New();
125 }
126
127 // prepare result
128 pResGen->Clear();
129 rPowerStates.clear();
130 rDetStates.clear();
131 // set the name
132 pResGen->Name(CollapsString("Det(" + rGen.Name() + ")"));
133 // copy alphabet
134 FD_DF("Deterministic A " << rGen.Alphabet().ToString());
135 pResGen->InjectAlphabet(rGen.Alphabet());
136 FD_DF("Deterministic B");
137
138 // bail out on empty input
139 if(rGen.InitStatesEmpty()) {
140 if(pResGen != &rResGen) {
141 pResGen->Move(rResGen);
142 delete pResGen;
143 }
144 FD_DF("Deterministic(): done (empty)");
145 return;
146 }
147
148 // helpers
149 typedef std::multimap< Idx,std::vector<StateSet>::size_type > T_HASHMAP;
150 T_HASHMAP hashmap;
151 std::vector<StateSet>::size_type current_vecindex;
152 std::pair< std::map<StateSet,Idx>::iterator,bool > result;
153 TransSet::Iterator transrel_end = rGen.TransRelEnd();
154 StateSet newset;
155 StateSet::Iterator lit;
156 const Idx max_idx = std::numeric_limits<Idx>::max();
157
158 // lock transrel to prevent iterator tracking (tmoor 201403)
159 rGen.TransRel().Lock();
160
161 // initialize rPowerStates with subset of initial states
162 Idx newstate = pResGen->InsInitState();
163 for (lit = rGen.InitStatesBegin(); lit != rGen.InitStatesEnd(); ++lit) {
164 // clear set and insert single state
165 newset.Insert(*lit);
166 // if marked state set in res generator
167 if (rGen.ExistsMarkedState(*lit)) {
168 pResGen->SetMarkedState(newstate);
169 FD_DF("Deterministic: setting as mstate: " << rGen.SStr(newstate));
170 }
171 }
172 FD_DF("Deterministic: created subset of initial states {"
173 << newset.ToString() << "} with deterministic state index "
174 << rGen.SStr(newstate));
175 // internally record newset
176 rPowerStates.push_back(newset);
177 rDetStates.push_back(newstate);
178 hashmap.insert(std::make_pair(newset.Signature(), (Idx)rPowerStates.size() - 1));
179
180 // iteration over all states
181 for (current_vecindex = 0; current_vecindex < rPowerStates.size();
182 ++current_vecindex) {
183 FD_WPC(current_vecindex,rPowerStates.size(), "Deterministic(): current/size: "<< current_vecindex << " / " << rPowerStates.size());
184 FD_DF("Deterministic: current power set: {"
185 << rPowerStates[current_vecindex].ToString() << "} -> "
186 << rDetStates[current_vecindex]);
187
188 std::vector<StateSet> newset_vec;
189 std::vector<Idx> event_vec;
190
191 // multiway merge begin
192 FD_DF("Deterministic: starting multiway merge...");
193 std::list<TransSet::Iterator> merge_iterators;
194 std::vector<Transition> trans_vec;
195
196 // add transset iterator at begin of each state's transitions
198 for (lit = rPowerStates[current_vecindex].Begin();
199 lit != rPowerStates[current_vecindex].End(); ++lit) {
200 tit = rGen.TransRelBegin(*lit);
201 if (tit != rGen.TransRelEnd(*lit)) {
202 merge_iterators.push_back(tit);
203 FD_DF("Deterministic: added merge iterator: " << rGen.SStr(tit->X1)
204 << "-" << rGen.EStr(tit->Ev) << "-" << rGen.SStr(tit->X2));
205 }
206 }
207
208 // find first iterator with lowest event
209 while (! merge_iterators.empty()) {
210 Idx currentevent = max_idx;
211 std::list<TransSet::Iterator>::iterator i;
212 std::list<TransSet::Iterator>::iterator currentit = merge_iterators.end();
213 for (i = merge_iterators.begin(); i != merge_iterators.end(); ++i) {
214 if ((*i)->Ev < currentevent) {
215 currentevent = (*i)->Ev;
216 currentit = i;
217 }
218 }
219 // currentit now holds the iterator
220 // currentevent holds the lowest event (lowest Idx)
221
222 // merge all transitions with currentevent at each iterator in a row;
223 // this is a modification of multiway merge as after projection the
224 // automaton most likely holds states with many transitions that share
225 // the same event; only merging the lowest transition and continue with
226 // search for the lowest event again would be to slow here (because
227 // of too much iterator dereferencing).
228 Idx currentstate;
229 while (currentit != merge_iterators.end()) {
230 currentstate = (*currentit)->X1;
231 TransSet::Iterator& j = *currentit;
232 while (1) {
233 // remove iterator if it reaches the end of the transition set
234 if (j == transrel_end) {
235 merge_iterators.erase(currentit++);
236 break;
237 }
238 // if current iterator is in its original state
239 else if (j->X1 == currentstate) {
240 // if the event is still the same add the transition
241 if (j->Ev == currentevent) {
242 trans_vec.push_back(*j);
243 FD_DF("Deterine: adding transition to list: "
244 << rGen.SStr(j->X1) << "-" << rGen.EStr(j->Ev) << "-"
245 << rGen.SStr(j->X2));
246 }
247 // else go to next iterator
248 else {
249 ++currentit;
250 break;
251 }
252 }
253 // if the iterator is beyond its original state remove it
254 else {
255 merge_iterators.erase(currentit++);
256 break;
257 }
258 ++j;
259 }
260 }
261 }
262
263 // partition transition vector by events. optimizable?
264 FD_DF("Deterministic: partitioning the transition vector...");
265 std::vector<Transition>::iterator tv_it;
266 StateSet newset;
267 Idx lastevent = 0;
268 for (tv_it = trans_vec.begin(); tv_it != trans_vec.end(); ++tv_it) {
269 if ((tv_it->Ev == lastevent) || (lastevent == 0)) {
270 newset.Insert(tv_it->X2);
271 lastevent = tv_it->Ev;
272 }
273 else {
274 FD_DF("Deterministic: partition: {" << newset.ToString()
275 << "} with event " << rGen.EStr(lastevent));
276 newset_vec.push_back(newset);
277 event_vec.push_back(lastevent);
278 newset.Clear();
279 newset.Insert(tv_it->X2);
280 lastevent = tv_it->Ev;
281 }
282 }
283 if (! newset.Empty()) {
284 FD_DF("Deterministic: partition: {" << newset.ToString()
285 << "} with event " << rGen.EStr(lastevent));
286 newset_vec.push_back(newset);
287 event_vec.push_back(lastevent);
288 }
289 FD_DF("Deterministic: partitioning the transition vector finished");
290 FD_DF("Deterministic: multiway merge finished");
291 // multiway merge end
292
293
294 std::vector<StateSet>::size_type nsv_index;
295 for (nsv_index = 0; nsv_index < newset_vec.size(); ++nsv_index) {
296 StateSet& currentset = newset_vec[nsv_index];
297 Idx currentevent = event_vec[nsv_index];
298 Idx tmp_x2 = 0;
299 Idx sig = currentset.Signature();
300 // test if newset signature is already known
301 std::pair<T_HASHMAP::iterator,T_HASHMAP::iterator> phit
302 = hashmap.equal_range(sig);
303 T_HASHMAP::iterator hit = phit.first;
304 for (hit = phit.first; hit != phit.second; ++hit) {
305 // test set of every matching signature for equality
306 if (currentset == rPowerStates[hit->second]) {
307 tmp_x2 = rDetStates[hit->second];
308 break;
309 }
310 }
311
312 // if new set is unique within the existing power sets
313 if (tmp_x2 == 0) {
314 // create new state in res generator
315 tmp_x2 = pResGen->InsState();
316 // insert newset in rPowerStates and get iterator,bool pair
317 rPowerStates.push_back(currentset);
318 rDetStates.push_back(tmp_x2);
319 hashmap.insert(std::make_pair(sig, (Idx)rPowerStates.size() - 1));
320 FD_DF("Deterministic: added new state "
321 << rGen.SStr(tmp_x2)
322 << " for new subset {" << currentset.ToString() << "}");
323 // set marked if one of the states in current set is marked
324 for (lit = currentset.Begin(); lit != currentset.End(); ++lit) {
325 if (rGen.ExistsMarkedState(*lit)) {
326 pResGen->SetMarkedState(tmp_x2);
327 break;
328 }
329 }
330 }
331 // introduce transition
332 pResGen->SetTransition(rDetStates[current_vecindex], currentevent, tmp_x2);
333 }
334 }
335
336
337 // fix names
338 if (rGen.StateNamesEnabled() && pResGen->StateNamesEnabled()) {
339 FD_DF("Deterministic: fixing names...");
340 // rPowerStates / rDetStates index "iterator"
341 std::vector<StateSet>::size_type i;
342 // deterministic states iterator
343 std::vector<Idx>::const_iterator dit;
344 for (i = 0; i < rPowerStates.size(); ++i) {
345 // temporary state name
346 std::string name = "{";
347 for (lit = rPowerStates[i].Begin(); lit != rPowerStates[i].End(); ++lit) {
348 if (rGen.StateName(*lit) != "") name = name + rGen.StateName(*lit) + ",";
349 else name = name + ToStringInteger(*lit) + ",";
350 }
351 name.erase(name.length() - 1);
352 name = name + "}";
353 FD_DF("Deterministic: setting state name \"" << name << "\" for index "
354 << rDetStates[i]);
355 pResGen->StateName(rDetStates[i], name);
356 }
357 }
358
359 // move pResGen to rResGen
360 if(pResGen != &rResGen) {
361 pResGen->Move(rResGen);
362 delete pResGen;
363 }
364
365 FD_DF("Deterministic(): core function: done");
366
367}
368
369
370
371} // namespace faudes
#define FD_WPC(cntnow, contdone, message)
#define FD_DF(message)
const std::string & Name(void) const
Idx Signature(void) const
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
StateSet::Iterator InitStatesBegin(void) const
const TransSet & TransRel(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
const StateSet & MarkedStates(void) const
const EventSet & Alphabet(void) const
virtual void Move(vGenerator &rGen)
virtual vGenerator & Assign(const Type &rSrc)
bool InitStatesEmpty(void) const
const StateSet & InitStates(void) const
TransSet::Iterator TransRelBegin(void) const
Idx InitStatesSize(void) const
virtual vGenerator * New(void) const
void SetInitState(Idx index)
std::string StateName(Idx index) const
TransSet::Iterator TransRelEnd(void) const
std::string EStr(Idx index) const
void SetMarkedState(Idx index)
virtual void EventAttributes(const EventSet &rEventSet)
bool StateNamesEnabled(void) const
StateSet::Iterator InitStatesEnd(void) const
Idx Size(void) const
std::string SStr(Idx index) const
virtual void Clear(void)
bool ExistsMarkedState(Idx index) const
std::string UniqueStateName(const std::string &rName) const
void InjectAlphabet(const EventSet &rNewalphabet)
void Lock(void) const
bool Empty(void) const
virtual void Clear(void)
Iterator End(void) const
Iterator Begin(void) const
void UniqueInit(Generator &rGen)
void Deterministic(const Generator &rGen, Generator &rResGen)
void aDeterministic(const Generator &rGen, Generator &rResGen)
uint32_t Idx
std::string ToStringInteger(Int number)
Definition cfl_utils.cpp:43
std::string CollapsString(const std::string &rString, unsigned int len)
Definition cfl_utils.cpp:91

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