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
25namespace faudes {
26
27// generate merged event name
28std::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
331void 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)
const std::string & Name(void) const
bool Exists(const Idx &rIndex) const
virtual void InsertSet(const NameSet &rOtherSet)
bool Insert(const Idx &rIndex)
std::vector< int >::size_type Position
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
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
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
Iterator Begin(void) const
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.33k --- 2025.09.16 --- c++ api documentaion by doxygen