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 
25 namespace faudes {
26 
27 // UniqueInit(rGen&)
28 void 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&)
62 void UniqueInit(const Generator& rGen, Generator& rResGen) {
63  rResGen.Assign(rGen);
64  UniqueInit(rResGen);
65 }
66 
67 // Deterministic(rGen&, rResGen&)
68 void 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&)
77 void 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&)
96 void 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 
113 void 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
197  TransSet::Iterator tit;
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)
Application callback: optional write progress report to console or application, incl count
#define FD_DF(message)
Debug: optional report on user functions.
powersetset construction
Set of indices.
Definition: cfl_indexset.h:78
Idx Signature(void) const
Compute an Idx type signature for a Set.
Idx Insert(void)
Insert new index to set.
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Iterator on transition.
Definition: cfl_transset.h:269
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
Write configuration data to a string.
Definition: cfl_types.cpp:169
Base class of all FAUDES generators.
StateSet::Iterator InitStatesBegin(void) const
Iterator to Begin() of mInitStates.
const TransSet & TransRel(void) const
Return reference to transition relation.
bool SetTransition(Idx x1, Idx ev, Idx x2)
Add a transition to generator by indices.
const StateSet & MarkedStates(void) const
Return const ref of marked states.
void ClearInitStates(void)
Clear all mInitStates.
const EventSet & Alphabet(void) const
Return const reference to alphabet.
virtual void Move(vGenerator &rGen)
Destructive copy to other vGenerator.
virtual vGenerator & Assign(const Type &rSrc)
Copy from other faudes type.
bool InitStatesEmpty(void) const
Check if set of initial states are empty.
const StateSet & InitStates(void) const
Const ref to initial states.
TransSet::Iterator TransRelBegin(void) const
Iterator to Begin() of transition relation.
Idx InitStatesSize(void) const
Get number of initial states.
virtual vGenerator * New(void) const
Construct on heap.
void SetInitState(Idx index)
Set an existing state as initial state by index.
std::string StateName(Idx index) const
State name lookup.
void Name(const std::string &rName)
Set the generator's name.
TransSet::Iterator TransRelEnd(void) const
Iterator to End() of transition relation.
std::string EStr(Idx index) const
Pretty printable event name for index (eg for debugging).
Idx InsState(void)
Add new anonymous state to generator.
void SetMarkedState(Idx index)
Set an existing state as marked state by index.
Idx InsInitState(void)
Create new anonymous state and set as initial state.
virtual void EventAttributes(const EventSet &rEventSet)
Set attributes for existing events.
bool StateNamesEnabled(void) const
Whether libFAUEDS functions are requested to generate state names.
StateSet::Iterator InitStatesEnd(void) const
Iterator to End() of mInitStates.
Idx Size(void) const
Get generator size (number of states)
std::string SStr(Idx index) const
Return pretty printable state name for index (eg for debugging)
virtual void Clear(void)
Clear generator data.
bool ExistsMarkedState(Idx index) const
Test existence of state in mMarkedStates.
std::string UniqueStateName(const std::string &rName) const
Create a new unique symbolic state name.
void InjectAlphabet(const EventSet &rNewalphabet)
Set mpAlphabet without consistency check.
void Lock(void) const
Detach and lock any further reallocation.
Definition: cfl_baseset.h:1462
bool Empty(void) const
Test whether if the TBaseSet is Empty.
Definition: cfl_baseset.h:1824
virtual void Clear(void)
Clear all set.
Definition: cfl_baseset.h:1902
Iterator End(void) const
Iterator to the end of set.
Definition: cfl_baseset.h:1896
Iterator Begin(void) const
Iterator to the begin of set.
Definition: cfl_baseset.h:1891
void UniqueInit(Generator &rGen)
Make initial states unique.
void Deterministic(const Generator &rGen, Generator &rResGen)
Make generator deterministic.
void aDeterministic(const Generator &rGen, Generator &rResGen)
Make generator deterministic.
libFAUDES resides within the namespace faudes.
uint32_t Idx
Type definition for index type (allways 32bit)
std::string CollapsString(const std::string &rString, unsigned int len)
Limit length of string, return head and tail of string.
Definition: cfl_helper.cpp:91
std::string ToStringInteger(Int number)
integer to string
Definition: cfl_helper.cpp:43

libFAUDES 2.32b --- 2024.03.01 --- c++ api documentaion by doxygen