pev_sparallel.cpp
Go to the documentation of this file.
1 /** @file pev_sparallel.cpp Sshaped parallel composition */
2 
3 /* FAU Discrete Event Systems Library (libfaudes)
4 
5  Copyright (C) 2023 Yiheng Tang
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 #include "pev_sparallel.h"
24 
25 namespace faudes {
26 
27 // generate merged event name
28 std::string MergeEventNames (const std::set<std::string>& rNames){
29  std::set<std::string>::const_iterator nameit = rNames.begin();
30  if (nameit==rNames.end()){
31  throw Exception("MergeEventNames()::","Empty set of events",0);
32  }
33  std::string result;
34  for(;nameit!=rNames.end();nameit++){
35  if (nameit!=rNames.begin()) result += "-";
36  result += *nameit;
37  }
38  return result;
39 }
40 
41 
42 // perform SFC Parallel composition
44  const pGenerator& rPGen1, const pGenerator& rPGen2,
45  std::map< std::pair<Idx,Idx>, Idx>& rCompositionMap,
46  EventSet& rMerge,
47  const EventSet& rPrivate,
48  EventPriorities& rPrios,
49  pGenerator& rPRes)
50 {
51  FD_DF("Parallel(" << &rPGen1 << "," << &rPGen2 << ")");
52 
53  // prepare result
54  Generator* pResGen = &rPRes;
55  if(&rPRes== &rPGen1 || &rPRes== &rPGen2) {
56  pResGen= rPRes.New();
57  }
58  pResGen->Clear();
59  pResGen->Name(CollapsString(rPGen1.Name()+"||"+rPGen2.Name()));
60  rCompositionMap.clear();
61 
62  // check if merging events are disjunct
63  if(!(rPGen1.Alphabet()*rPGen2.Alphabet()*rMerge).Empty()){
64  throw Exception("Parallel()","invalid input automata (they share some mergning events)",100);
65  }
66  // check if any merged event name is already utilised (consistent with the naming of merged event)
67  EventSet::Iterator eit = rPGen1.AlphabetBegin();
68  for (;eit!=rPGen1.AlphabetEnd();++eit){
69  if (!rMerge.Exists(*eit)) continue;
70  EventSet::Iterator eit2 = rPGen2.AlphabetBegin();
71  for(;eit2!=rPGen2.AlphabetEnd();eit2++){
72  if(!rMerge.Exists(*eit2)) continue;
73  std::set<std::string> evs;
74  evs.insert(rPGen1.EventName(*eit));
75  evs.insert(rPGen2.EventName(*eit2));
76  std::string newevname = MergeEventNames(evs);
77  if (rPGen1.FindEvent(newevname)!=rPGen1.AlphabetEnd()
78  ||
79  rPGen2.FindEvent(newevname)!=rPGen2.AlphabetEnd()){
80  throw Exception("Parallel()","invalid input automata (event name '"+newevname+"' is in the form of a merged event)",101);
81  }
82  }
83  }
84 
85  // create res alphabet (no merging)
86  pResGen->InsEvents(rPGen1.Alphabet());
87  pResGen->InsEvents(rPGen2.Alphabet());
88  Idx lowest = rPGen1.LowestPriority();
89 
90  // shared events
91  EventSet sharedalphabet = rPGen1.Alphabet() * rPGen2.Alphabet();
92  EventSet mergingalphabet = (rPGen1.Alphabet()+rPGen2.Alphabet())*rMerge;
93  FD_DF("Parallel: shared events: " << sharedalphabet.ToString());
94 
95  // todo stack
96  std::stack< std::pair<Idx,Idx> > todo;
97  // current pair, new pair
98  std::pair<Idx,Idx> currentstates, newstates;
99  // state
100  Idx tmpstate;
101  StateSet::Iterator lit1, lit2;
102  TransSet::Iterator tit1, tit1_end, tit2, tit2_end;
103  std::map< std::pair<Idx,Idx>, Idx>::iterator rcit;
104 
105  // push all combinations of initial states on todo stack
106  FD_DF("Parallel: adding all combinations of initial states to todo:");
107  for (lit1 = rPGen1.InitStatesBegin(); lit1 != rPGen1.InitStatesEnd(); ++lit1) {
108  for (lit2 = rPGen2.InitStatesBegin(); lit2 != rPGen2.InitStatesEnd(); ++lit2) {
109  currentstates = std::make_pair(*lit1, *lit2);
110  todo.push(currentstates);
111  tmpstate = pResGen->InsInitState();
112  rCompositionMap[currentstates] = tmpstate;
113  FD_DF("Parallel: (" << *lit1 << "|" << *lit2 << ") -> "
114  << rCompositionMap[currentstates]);
115  }
116  }
117 
118  // start algorithm
119  EventSet newMerge; // buffer a set for newly emerging merging events
120  FD_DF("Parallel: processing reachable states:");
121  while (! todo.empty()) {
122 
123  // allow for user interrupt
124  // LoopCallback();
125  // allow for user interrupt, incl progress report
126  FD_WPC(rCompositionMap.size(),rCompositionMap.size()+todo.size(),"Parallel(): processing");
127  // get next reachable state from todo stack
128  currentstates = todo.top();
129  todo.pop();
130 
131  // get current highest priority
132  Idx highest = lowest;
133  EventSet active1 = rPGen1.ActiveEventSet(currentstates.first);
134  EventSet active2 = rPGen2.ActiveEventSet(currentstates.second);
135  EventSet active = (active1 * active2) + (active1-rPGen2.Alphabet()); // iterate rPGen1 first
136  EventSet::Iterator eit = active.Begin();
137  for(;eit!=active.End();eit++){
138  if(!rPrivate.Exists(*eit)) continue;
139  if(rPGen1.Priority(*eit)>highest) highest = rPGen1.Priority(*eit);
140  }
141  active = active2-rPGen1.Alphabet();
142  eit = active.Begin();
143  for(;eit!=active.End();eit++){
144  if(!rPrivate.Exists(*eit)) continue;
145  if(rPGen2.Priority(*eit)>highest) highest = rPGen2.Priority(*eit);
146  }
147 
148 
149  FD_DF("Parallel: processing (" << currentstates.first << "|"
150  << currentstates.second << ") -> "
151  << rCompositionMap[currentstates]);
152  // iterate over all rGen1 transitions
153  // (includes execution of shared events)
154  tit1 = rPGen1.TransRelBegin(currentstates.first);
155  tit1_end = rPGen1.TransRelEnd(currentstates.first);
156  for (; tit1 != tit1_end; ++tit1) {
157  // skip if priority lower than highest
158  if (rPGen1.Priority(tit1->Ev)<highest) continue;
159  // if asynch
160  if ((!sharedalphabet.Exists(tit1->Ev) && !mergingalphabet.Exists(tit1->Ev))
161  ||
162  (mergingalphabet.Exists(tit1->Ev) && (rPGen2.ActiveEventSet(currentstates.second) * rMerge).Empty())) {
163  FD_DF("Parallel: asynch step (private non-merging or merging with cstate.second cannot merge)");
164  newstates = std::make_pair(tit1->X2, currentstates.second);
165  // add to todo list if composition state is new
166  rcit = rCompositionMap.find(newstates);
167  if (rcit == rCompositionMap.end()) {
168  todo.push(newstates);
169  tmpstate = pResGen->InsState();
170  rCompositionMap[newstates] = tmpstate;
171  FD_DF("Parallel: todo push: (" << newstates.first << "|"
172  << newstates.second << ") -> "
173  << rCompositionMap[newstates]);
174  }
175  else {
176  tmpstate = rcit->second;
177  }
178  pResGen->SetTransition(rCompositionMap[currentstates], tit1->Ev, tmpstate);
179  FD_DF("Parallel: add transition to new generator: "
180  << rCompositionMap[currentstates] << "-" << tit1->Ev << "-"
181  << tmpstate);
182  }
183  // if synch
184  else {
185  FD_DF("Parallel: synch (common event or synch through merging)");
186  // find shared transitions
187  if (sharedalphabet.Exists(tit1->Ev)){
188  FD_DF("Parallel: synch through common event");
189  tit2 = rPGen2.TransRelBegin(currentstates.second, tit1->Ev);
190  tit2_end = rPGen2.TransRelEnd(currentstates.second, tit1->Ev);
191  for (; tit2 != tit2_end; ++tit2) {
192  newstates = std::make_pair(tit1->X2, tit2->X2);
193  // add to todo list if composition state is new
194  rcit = rCompositionMap.find(newstates);
195  if (rcit == rCompositionMap.end()) {
196  todo.push(newstates);
197  tmpstate = pResGen->InsState();
198  rCompositionMap[newstates] = tmpstate;
199  FD_DF("Parallel: todo push: (" << newstates.first << "|"
200  << newstates.second << ") -> "
201  << rCompositionMap[newstates]);
202  }
203  else {
204  tmpstate = rcit->second;
205  }
206  pResGen->SetTransition(rCompositionMap[currentstates],
207  tit1->Ev, tmpstate);
208  FD_DF("Parallel: add transition to new generator: "
209  << rCompositionMap[currentstates] << "-"
210  << tit1->Ev << "-" << tmpstate);
211  }
212  }
213  else{
214  FD_DF("Parallel: synch through merging");
215  tit2 = rPGen2.TransRelBegin(currentstates.second);
216  tit2_end = rPGen2.TransRelEnd(currentstates.second);
217  for (; tit2 != tit2_end; ++tit2) {
218  if (!rMerge.Exists(tit2->Ev)) continue; // only interested in merging events
219  std::set<std::string> evs;
220  evs.insert(rPGen1.EventName(tit1->Ev));
221  evs.insert(rPGen2.EventName(tit2->Ev));
222  std::string newevname = MergeEventNames(evs); // event name of merged event
223  Idx newev;
224  if (!rPRes.ExistsEvent(newevname)){
225  newev = rPRes.InsEvent(newevname);
226  newMerge.Insert(newevname);
227  rPrios.InsPriority(newevname,2); //TMPRIO SCT-TransEvents only
228  }
229  else{
230  newev = *rPRes.FindEvent(newevname);
231  }
232  newstates = std::make_pair(tit1->X2, tit2->X2);
233  // add to todo list if composition state is new
234  rcit = rCompositionMap.find(newstates);
235  if (rcit == rCompositionMap.end()) {
236  todo.push(newstates);
237  tmpstate = pResGen->InsState();
238  rCompositionMap[newstates] = tmpstate;
239  FD_DF("Parallel: todo push: (" << newstates.first << "|"
240  << newstates.second << ") -> "
241  << rCompositionMap[newstates]);
242  }
243  else {
244  tmpstate = rcit->second;
245  }
246  pResGen->SetTransition(rCompositionMap[currentstates],
247  newev, tmpstate);
248  FD_DF("Parallel: add transition to new generator: "
249  << rCompositionMap[currentstates] << "-"
250  << tit1->Ev << "-" << tmpstate);
251  }
252 
253  }
254  }
255  }
256  // iterate over all rGen2 transitions
257  // (without execution of synch step)
258  tit2 = rPGen2.TransRelBegin(currentstates.second);
259  tit2_end = rPGen2.TransRelEnd(currentstates.second);
260  for (; tit2 != tit2_end; ++tit2) {
261  if (rPGen2.Priority(tit2->Ev)<highest) continue;
262  if ((!sharedalphabet.Exists(tit2->Ev) && !mergingalphabet.Exists(tit2->Ev))
263  ||
264  (mergingalphabet.Exists(tit2->Ev) && (rPGen1.ActiveEventSet(currentstates.first) * rMerge).Empty())) {
265  FD_DF("Parallel: exists only in rGen2");
266  newstates = std::make_pair(currentstates.first, tit2->X2);
267  // add to todo list if composition state is new
268  rcit = rCompositionMap.find(newstates);
269  if (rcit == rCompositionMap.end()) {
270  todo.push(newstates);
271  tmpstate = pResGen->InsState();
272  rCompositionMap[newstates] = tmpstate;
273  FD_DF("Parallel: todo push: (" << newstates.first << "|"
274  << newstates.second << ") -> "
275  << rCompositionMap[newstates]);
276  }
277  else {
278  tmpstate = rcit->second;
279  }
280  pResGen->SetTransition(rCompositionMap[currentstates],
281  tit2->Ev, tmpstate);
282  FD_DF("Parallel: add transition to new generator: "
283  << rCompositionMap[currentstates] << "-"
284  << tit2->Ev << "-" << tmpstate);
285  }
286  }
287  }
288 
289  // set marked states
290  for (lit1 = rPGen1.MarkedStatesBegin();
291  lit1 != rPGen1.MarkedStatesEnd(); ++lit1) {
292  for (lit2 = rPGen2.MarkedStatesBegin();
293  lit2 != rPGen2.MarkedStatesEnd(); ++lit2) {
294  currentstates = std::make_pair(*lit1, *lit2);
295  rcit = rCompositionMap.find(currentstates);
296  if (rcit != rCompositionMap.end()) {
297  pResGen->SetMarkedState(rcit->second);
298  }
299  }
300  }
301  FD_DF("Parallel: marked states: "
302  << pResGen->MarkedStatesToString());
303  // copy result
304  if(pResGen != &rPRes) {
305  rPRes = *pResGen;
306  delete pResGen;
307  }
308  // set statenames
309  if(rPGen1.StateNamesEnabled() && rPGen2.StateNamesEnabled() && rPRes.StateNamesEnabled())
310  SetComposedStateNames(rPGen1, rPGen2, rCompositionMap, rPRes);
311  else
312  rPRes.StateNamesEnabled(false);
313 
314  // push new merging events
315  rMerge.InsertSet(newMerge);
316 }
317 
319  const pGenerator& rPGen1, const pGenerator& rPGen2,
320  EventSet& rMerge,
321  const EventSet& rPrivate,
322  EventPriorities& rPrios,
323  pGenerator& rPRes){
324  std::map< std::pair<Idx,Idx>, Idx> dummy;
325  SUParallel(rPGen1,rPGen2,dummy,rMerge,rPrivate,rPrios,rPRes);
326 }
327 
328 // the special fairness merge for SFC
329 // does not do consistency check (should have been done before in SFC_Parallel)
330 // rGen12 is the parallel composition of rPGen1 and rPGen2, which should have been computed before
331 void UParallel_MergeFairness(const pGenerator& rPGen1, const pGenerator& rPGen2, const Generator& rGen12, const EventSet& rMerge, FairnessConstraints& rFairRes){
332  rFairRes.Clear();
333  // iterate over fairness of rPGen1
335  for(;fpos<rPGen1.GlobalAttribute().Fairness().Size();++fpos){
336  EventSet fair = rPGen1.GlobalAttribute().Fairness().At(fpos);
337  EventSet fairm1 = fair * rMerge; // merging events in the current fairness (of rPGen1)
338  EventSet::Iterator eit1 = fairm1.Begin();
339  for(;eit1!=fairm1.End();eit1++){
340  EventSet m2 = rPGen2.Alphabet() * rMerge; // merging events in rPgen2
341  EventSet::Iterator eit2 = m2.Begin();
342  for(;eit2!=m2.End();eit2++){
343  std::set<std::string> evs;
344  evs.insert(rPGen1.EventName(*eit1));
345  evs.insert(rPGen2.EventName(*eit2));
346  std::string newevname = MergeEventNames(evs);
347  if (!rGen12.Alphabet().Exists(newevname)) continue; // skip if this event is actually not used in the parallel composition
348  fair.Insert(newevname);
349  }
350  }
351  rFairRes.Append(fair);
352  }
353  // iterate over fairness of rPGen2
354  fpos = 0;
355  for(;fpos<rPGen2.GlobalAttribute().Fairness().Size();++fpos){
356  EventSet fair = rPGen2.GlobalAttribute().Fairness().At(fpos);
357  EventSet fairm2 = fair * rMerge; // merging events in the current fairness (of rPGen2)
358  EventSet::Iterator eit2 = fairm2.Begin();
359  for(;eit2!=fairm2.End();eit2++){
360  EventSet m1 = rPGen1.Alphabet() * rMerge; // merging events in rPgen1
361  EventSet::Iterator eit1 = m1.Begin();
362  for(;eit1!=m1.End();eit1++){
363  std::set<std::string> evs;
364  evs.insert(rPGen1.EventName(*eit1));
365  evs.insert(rPGen2.EventName(*eit2));
366  std::string newevname = MergeEventNames(evs);
367  if (!rGen12.Alphabet().Exists(newevname)) continue; // skip if this event is actually not used in the parallel composition
368  fair.Insert(newevname);
369  }
370  }
371  rFairRes.Append(fair);
372  }
373 }
374 
375 }// namspace
#define FD_WPC(cntnow, contdone, message)
#define FD_DF(message)
bool Exists(const Idx &rIndex) const
virtual void InsertSet(const NameSet &rOtherSet)
bool Insert(const Idx &rIndex)
std::vector< int >::size_type Position
TBaseSet< Transition, TransSort::X1EvX2 >::Iterator Iterator
Definition: cfl_transset.h:273
bool InsEvent(Idx index)
const TaEventSet< EventAttr > & Alphabet(void) const
void GlobalAttribute(const GlobalAttr &rAttr)
void InsPriority(const Idx idx, const Idx prio)
Idx Priority(const Idx index) const
TpGenerator * New(void) const
Idx LowestPriority(void) const
std::string ToString(const std::string &rLabel="", const Type *pContext=0) const
Definition: cfl_types.cpp:170
virtual void Append(const Type &rElem)
virtual void Clear(void)
StateSet::Iterator InitStatesBegin(void) const
bool SetTransition(Idx x1, Idx ev, Idx x2)
const EventSet & Alphabet(void) const
std::string MarkedStatesToString(void) const
EventSet ActiveEventSet(Idx x1) const
TransSet::Iterator TransRelBegin(void) const
EventSet::Iterator FindEvent(Idx index) const
void InsEvents(const EventSet &events)
EventSet::Iterator AlphabetBegin(void) const
StateSet::Iterator MarkedStatesBegin(void) const
void Name(const std::string &rName)
TransSet::Iterator TransRelEnd(void) const
bool ExistsEvent(Idx index) const
StateSet::Iterator MarkedStatesEnd(void) const
void SetMarkedState(Idx index)
bool StateNamesEnabled(void) const
StateSet::Iterator InitStatesEnd(void) const
std::string EventName(Idx index) const
EventSet::Iterator AlphabetEnd(void) const
virtual void Clear(void)
Iterator End(void) const
Definition: cfl_baseset.h:1913
Iterator Begin(void) const
Definition: cfl_baseset.h:1908
uint32_t Idx
void SetComposedStateNames(const Generator &rGen1, const Generator &rGen2, const std::map< std::pair< Idx, Idx >, Idx > &rCompositionMap, Generator &rGen12)
void UParallel_MergeFairness(const pGenerator &rPGen1, const pGenerator &rPGen2, const Generator &rGen12, const EventSet &rMerge, FairnessConstraints &rFairRes)
void SUParallel(const pGenerator &rPGen1, const pGenerator &rPGen2, std::map< std::pair< Idx, Idx >, Idx > &rCompositionMap, EventSet &rMerge, const EventSet &rPrivate, EventPriorities &rPrios, pGenerator &rPRes)
std::string MergeEventNames(const std::set< std::string > &rNames)
std::string CollapsString(const std::string &rString, unsigned int len)
Definition: cfl_utils.cpp:91

libFAUDES 2.33b --- 2025.05.07 --- c++ api documentaion by doxygen