Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 70.4% 157 / 0 / 223
Functions: -% 0 / 1 / 1
Branches: 61.6% 69 / 0 / 112

OMCompiler/Compiler/FrontEnd/InstStateMachineUtil.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package InstStateMachineUtil
37 " file: InstStateMachineUtil.mo
38 package: InstStateMachineUtil
39 description: Model instantiation
40
41 This module contains utility functions for the instantiation of Modelica state machines."
42
43 public import DAE;
44
45 protected import Absyn;
46 protected import AvlTreePathFunction;
47 protected import Config;
48 protected import Flags;
49 protected import List;
50 protected import ComponentReference;
51 protected import ComponentReferenceBasics;
52 protected import HashTable;
53 protected import HashTableSM1;
54 protected import HashTableCG;
55 protected import HashTable3;
56 protected import HashSet;
57 protected import Util;
58 protected import Array;
59 protected import DAEUtil;
60 protected import InnerOuter;
61 protected import Expression;
62 protected import Debug;
63 protected import PrefixUtil;
64 protected import DAEDump;
65 protected import SCode;
66
67 public uniontype SMNode
68 record SMNODE "Collecting information about a state/mode"
69 //DAE.Ident ident;
70 DAE.ComponentRef componentRef;
71 Boolean isInitial;
72 HashSet.HashSet edges "relations to other modes due to in- and out-going transitions";
73 end SMNODE;
74 end SMNode;
75
76 public uniontype FlatSMGroup
77 record FLAT_SM_GROUP "Collecting information about a group of state components forming a flat state machine"
78 DAE.ComponentRef initState;
79 array<DAE.ComponentRef> states;
80 end FLAT_SM_GROUP;
81 end FlatSMGroup;
82
83 public uniontype AdjacencyTable
84 record ADJACENCY_TABLE
85 HashTable.HashTable cref2index "Map cref to corresponding index in adjacency matrix";
86 array<array<Boolean>> adjacency "Adjacency matrix showing which modes are connected by transitions";
87 end ADJACENCY_TABLE;
88 end AdjacencyTable;
89
90 // Table having crefs as keys and corresponding SMNODE as value
91 type SMNodeTable = HashTableSM1.HashTable;
92
93 // Table mapping crefs of SMNodes to corresponding crefs of FlatSMGroup
94 type SMNodeToFlatSMGroupTable = HashTableCG.HashTable;
95
96 constant String SMS_PRE = "smOf" "prefix for flat State Machine names";
97
98 protected
99 constant Boolean DEBUG_SMDUMP = false "enable verbose stdout debug information during elaboration";
100
101 public function createSMNodeToFlatSMGroupTable "
102 Author: BTH
103 Create table that associates a state instance with its governing flat state machine.
104 "
105 input DAE.DAElist inDae;
106 output SMNodeToFlatSMGroupTable smNodeToFlatSMGroup;
107 protected
108 list<DAE.Element> elementLst;
109
110 SMNodeTable smNodeTable;
111 Integer nStates;
112 AdjacencyTable iTable, transClosure;
113 list<DAE.ComponentRef> initialStates;
114 list<FlatSMGroup> flatSMGroup;
115 algorithm
116
2/2
✓ Branch 1 taken 1443 times.
✓ Branch 2 taken 158439 times.
159882 if intLt(Flags.getConfigEnum(Flags.LANGUAGE_STANDARD), 33) then
117 1443 smNodeToFlatSMGroup := HashTableCG.emptyHashTableSized(1);
118 1443 return;
119 end if;
120
121 158439 DAE.DAE(elementLst=elementLst) := inDae;
122 158439 smNodeTable := getSMNodeTable(elementLst);
123 158439 nStates := BaseHashTable.hashTableCurrentSize(smNodeTable);
124
125
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 158432 times.
158439 if nStates > 0 then
126 7 smNodeToFlatSMGroup := HashTableCG.emptyHashTable();
127
128 if DEBUG_SMDUMP then print("***** InstStateMachineUtil.createSMNodeToFlatSMGroupTable: START ***** \n"); end if;
129 if DEBUG_SMDUMP then print("***** State machine node table: ***** \n"); end if;
130 if DEBUG_SMDUMP then BaseHashTable.dumpHashTable(smNodeTable); end if;
131
132 if DEBUG_SMDUMP then print("***** Adjacency Matrix: ***** \n"); end if;
133 7 iTable := createAdjacencyTable(smNodeTable, nStates);
134 if DEBUG_SMDUMP then printAdjacencyTable(iTable, nStates); end if;
135
136 if DEBUG_SMDUMP then print("***** Transitive Closure: ***** \n"); end if;
137 7 transClosure := transitiveClosure(iTable, nStates);
138 if DEBUG_SMDUMP then printAdjacencyTable(transClosure, nStates); end if;
139
140 if DEBUG_SMDUMP then print("***** Initial States: ***** \n"); end if;
141 7 initialStates := extractInitialStates(smNodeTable);
142 if DEBUG_SMDUMP then print( stringDelimitList(List.map(initialStates, ComponentReferenceBasics.printComponentRefStr), ", ") + "\n"); end if;
143
144 if DEBUG_SMDUMP then print("***** Flat State Machine Groups: ***** \n"); end if;
145 7 flatSMGroup := extractFlatSMGroup(initialStates, transClosure, nStates);
146 if DEBUG_SMDUMP then print(stringDelimitList(List.map(flatSMGroup,dumpFlatSMGroupStr), "\n") + "\n"); end if;
147
148 if DEBUG_SMDUMP then print("***** SM Node cref to SM Group cref mapping: ***** \n"); end if;
149 7 smNodeToFlatSMGroup := List.fold(flatSMGroup, relateNodesToGroup, smNodeToFlatSMGroup);
150 if DEBUG_SMDUMP then BaseHashTable.dumpHashTable(smNodeToFlatSMGroup); end if;
151
152 if DEBUG_SMDUMP then print("***** InstStateMachineUtil.createSMNodeToFlatSMGroupTable: END ***** \n"); end if;
153 else
154 158432 smNodeToFlatSMGroup := HashTableCG.emptyHashTableSized(1);
155 end if;
156
157 end createSMNodeToFlatSMGroupTable;
158
159 public function wrapSMCompsInFlatSMs "
160 Author: BTH
161 Wrap state machine components into corresponding flat state machine containers.
162 "
163 input InnerOuter.InstHierarchy inIH;
164 input DAE.DAElist inDae1;
165 input DAE.DAElist inDae2;
166 input SMNodeToFlatSMGroupTable smNodeToFlatSMGroup;
167 input list<DAE.ComponentRef> smInitialCrefs "every smInitialCrefs corresponds to a flat state machine group";
168 output DAE.DAElist outDae1;
169 output DAE.DAElist outDae2;
170 protected
171 list<DAE.Element> elementLst1, elementLst2, smCompsLst, otherLst1, otherLst2, smTransitionsLst, flatSmLst, flatSMsAndMergingEqns;
172 algorithm
173 //print("InstStateMachineUtil.wrapSMCompsInFlatSMs: smInitialCrefs: " + stringDelimitList(List.map(smInitialCrefs, ComponentReference.crefStr), ",") + "\n");
174 //print("InstStateMachineUtil.wrapSMCompsInFlatSMs: smNodeToFlatSMGroup:\n"); BaseHashTable.dumpHashTable(smNodeToFlatSMGroup);
175
176 159882 DAE.DAE(elementLst=elementLst1) := inDae1;
177 // extract SM_COMPs
178 159882 (smCompsLst, otherLst1) := List.extractOnTrue(elementLst1, isSMComp);
179
180 159882 DAE.DAE(elementLst=elementLst2) := inDae2;
181 // extract transition and initialState statements
182 159882 (smTransitionsLst, otherLst2) := List.extractOnTrue(elementLst2, isSMStatement2);
183
184 // Create list of FLAT_SM(..). Every FLAT_SM contains the components that constitute that flat state machine
185 //flatSmLst := List.map2(smInitialCrefs, createFlatSM, smCompsLst, smNodeToFlatSMGroup);
186 159882 flatSmLst := List.map2(smInitialCrefs, createFlatSM, listAppend(smCompsLst, smTransitionsLst), smNodeToFlatSMGroup);
187 // Merge variable definitions in flat state machine and create elements list containing FLAT_SMs and merging equations
188 159882 flatSMsAndMergingEqns := List.fold1(flatSmLst, mergeVariableDefinitions, inIH, {});
189
190 159882 outDae1 := DAE.DAE(listAppend(flatSMsAndMergingEqns, otherLst1));
191 159882 outDae2 := DAE.DAE(otherLst2);
192 end wrapSMCompsInFlatSMs;
193
194
195
196 protected function mergeVariableDefinitions "
197 Author: BTH
198 Create fresh equations for merging outer output variable definitions
199 "
200 input DAE.Element inFlatSM;
201 input InnerOuter.InstHierarchy inIH;
202 input list<DAE.Element> inStartElementLst;
203 output list<DAE.Element> outElementLst;
204 protected
205 HashTableCG.HashTable outerOutputCrefToSMCompCref "Table to map outer outputs to corresponding state";
206 HashTableCG.HashTable outerOutputCrefToInnerCref "Table to map outer output to corresponding inners";
207 HashTable3.HashTable innerCrefToOuterOutputCrefs "Kind of \"inverse\" of outerOutputCrefToInnerCref";
208 List<tuple<DAE.ComponentRef, DAE.ComponentRef>> hashEntries_outerOutputCrefToInnerCref;
209 List<tuple<DAE.ComponentRef, list<DAE.ComponentRef>>> innerCrefToOuterOutputCrefs_der = {} "Extracted part in which at least one of the output crefs appears in a der(..)";
210 List<tuple<DAE.ComponentRef, list<DAE.ComponentRef>>> innerCrefToOuterOutputCrefs_nonDer = {} "The non-der(..) rest";
211 List<DAE.ComponentRef> uniqueHashValues, crefs, derCrefsAcc = {}, outerOutputCrefs;
212 HashSet.HashSet derCrefsSet;
213 AvlTreePathFunction.Tree emptyTree;
214 list<DAE.Element> mergeEqns, mergeEqns_der, aliasEqns_der;
215 Integer nOfHits;
216 Boolean hasDer;
217 // FLAT_SM
218 DAE.Ident ident;
219 list<DAE.Element> dAElist "The states/modes within the the flat state machine";
220 algorithm
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 DAE.FLAT_SM(ident=ident, dAElist=dAElist) := inFlatSM;
222
223 // Create table that maps outer outputs to corresponding state
224 8 outerOutputCrefToSMCompCref := List.fold(dAElist, collectOuterOutputs, HashTableCG.emptyHashTable());
225 // print("InstStateMachineUtil.mergeVariableDefinitions OuterToSTATE:\n"); BaseHashTable.dumpHashTable(outerOutputCrefToSMCompCref);
226
227 // Create table that maps outer outputs crefs to corresponding inner crefs
228 8 outerOutputCrefToInnerCref := List.fold1(BaseHashTable.hashTableKeyList(outerOutputCrefToSMCompCref), matchOuterWithInner, inIH, HashTableCG.emptyHashTable());
229 // print("InstStateMachineUtil.mergeVariableDefinitions OuterToINNER:\n"); BaseHashTable.dumpHashTable(outerOutputCrefToInnerCref);
230
231 // Create table that maps inner crefs from above to a list of corresponding outer crefs
232 8 hashEntries_outerOutputCrefToInnerCref := BaseHashTable.hashTableList(outerOutputCrefToInnerCref);
233 8 uniqueHashValues := List.unique(BaseHashTable.hashTableValueList(outerOutputCrefToInnerCref));
234 // print("InstStateMachineUtil.mergeVariableDefinitions uniqueHashValues: (" + stringDelimitList(List.map(uniqueHashValues, ComponentReference.crefStr), ",") + ")\n");
235 8 innerCrefToOuterOutputCrefs := List.fold1(uniqueHashValues, collectCorrespondingKeys, hashEntries_outerOutputCrefToInnerCref, HashTable3.emptyHashTable());
236 // print("InstStateMachineUtil.mergeVariableDefinitions: innerCrefToOuterOutputCrefs:\n"); BaseHashTable.dumpHashTable(innerCrefToOuterOutputCrefs);
237
238 // Substitute occurrences of previous(outerCref) by previous(innerCref)
239 emptyTree := AvlTreePathFunction.Tree.EMPTY();
240 8 (DAE.DAE(dAElist), _, _) := DAEUtil.traverseDAE(DAE.DAE(dAElist), emptyTree, traverserHelperSubsOuterByInnerExp, outerOutputCrefToInnerCref);
241
242
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if Flags.getConfigBool(Flags.CT_STATE_MACHINES) then
243 // == HACK Let's deal with continuous-time ==
244 ✗ crefs := BaseHashTable.hashTableKeyList(outerOutputCrefToSMCompCref);
245 ✗ for cref in crefs loop
246 nOfHits := 0;
247 // traverse dae expressions and search for der(cref) occurances
248 ✗ (_, _, (_,(_, nOfHits))) := DAEUtil.traverseDAE(DAE.DAE(dAElist), emptyTree, Expression.traverseSubexpressionsHelper, (traversingCountDer, (cref, 0)));
249 ✗ if nOfHits > 0 then
250 derCrefsAcc := cref :: derCrefsAcc;
251 end if;
252 end for;
253 // print("InstStateMachineUtil.mergeVariableDefinitions derCrefsAcc:\n" + stringDelimitList(List.map(derCrefsAcc, ComponentReference.crefStr), ", ") + "\n");
254 ✗ derCrefsSet := HashSet.emptyHashSetSized(listLength(derCrefsAcc));
255 ✗ derCrefsSet := List.fold(derCrefsAcc, BaseHashSet.add, derCrefsSet);
256 // Split the mapping from inner crefs to outer output crefs in a "continuous" part and the rest
257 ✗ for hashEntry in BaseHashTable.hashTableList(innerCrefToOuterOutputCrefs) loop
258 ✗ (_, outerOutputCrefs) := hashEntry;
259 ✗ hasDer := List.any(outerOutputCrefs, function BaseHashSet.has(hashSet=derCrefsSet));
260 ✗ if hasDer then
261 innerCrefToOuterOutputCrefs_der := hashEntry :: innerCrefToOuterOutputCrefs_der;
262 else
263 innerCrefToOuterOutputCrefs_nonDer := hashEntry :: innerCrefToOuterOutputCrefs_nonDer;
264 end if;
265 end for;
266 // Create aliases between inner and outer of 'der' entries, e.g., a tuple (x -> {a.x, b.x}) will be transformed to alias equations {x = a.x, x = b.x}
267 ✗ aliasEqns_der := List.flatten( List.map(innerCrefToOuterOutputCrefs_der, freshAliasEqn_der) );
268 // Create merging equations for 'der' entries
269 ✗ mergeEqns_der := listAppend(List.map(innerCrefToOuterOutputCrefs_der, freshMergingEqn_der), aliasEqns_der);
270 // Create merging equations for 'nonDer' entries
271 ✗ mergeEqns := listAppend(List.map(innerCrefToOuterOutputCrefs_nonDer, freshMergingEqn), mergeEqns_der);
272 else
273 // FIXME add support for outers that don't have "inner outer" or "inner" at closest instance level (requires to introduce a fresh intermediate variable)
274 8 mergeEqns := List.map(BaseHashTable.hashTableList(innerCrefToOuterOutputCrefs), freshMergingEqn);
275 end if;
276
277 // add processed flat state machine and corresponding merging equations to the dae element list
278 //outElementLst := listAppend(outElementLst, {DAE.FLAT_SM(ident=ident, dAElist=listAppend(dAElist, mergeEqns))}); // put merge equations in FLAT_SM element
279 16 outElementLst := listAppend(inStartElementLst, DAE.FLAT_SM(ident=ident, dAElist=dAElist) :: mergeEqns); // put equations after FLAT_SM element
280 end mergeVariableDefinitions;
281
282 protected function freshAliasEqn_der "
283 Author: BTH
284 Helper function to mergeVariableDefinition.
285 Create a fresh alias equation between inners and their corresponding outer output variable defintions
286 "
287 input tuple<DAE.ComponentRef, list<DAE.ComponentRef>> inInnerCrefToOuterOutputCrefs "tuple relating the inner cref to respective outer crefs";
288 output list<DAE.Element> outEqns;
289 protected
290 DAE.ComponentRef innerCref;
291 List<DAE.ComponentRef> outerCrefs;
292 DAE.Type ty;
293 algorithm
294 ✗ (innerCref, outerCrefs) := inInnerCrefToOuterOutputCrefs;
295 // FIXME use instead 'ty := ComponentReference.crefTypeConsiderSubs(innerCref);'?
296 ✗ ty := ComponentReference.crefLastType(innerCref);
297 // Alias equations
298 ✗ outEqns := list(DAE.EQUATION(DAE.CREF(innerCref, ty), DAE.CREF(outerCref, ty), DAE.emptyElementSource) for outerCref in outerCrefs);
299 end freshAliasEqn_der;
300
301 protected function freshMergingEqn_der "
302 Author: BTH
303 Helper function to mergeVariableDefinition.
304 Create a fresh equation for merging outer output variable defintions of equations involving der(..)
305 "
306 input tuple<DAE.ComponentRef, list<DAE.ComponentRef>> inInnerCrefToOuterOutputCrefs "tuple relating the inner cref to respective outer crefs";
307 output DAE.Element outEqn;
308 protected
309 DAE.ComponentRef innerCref;
310 List<DAE.ComponentRef> outerCrefs, outerCrefsStripped, outerCrefDers;
311 DAE.Type ty;
312 DAE.Exp exp;
313 algorithm
314 ✗ (innerCref, outerCrefs) := inInnerCrefToOuterOutputCrefs;
315
316 // FIXME use instead 'ty := ComponentReference.crefTypeConsiderSubs(innerCref);'?
317 ✗ ty := ComponentReference.crefLastType(innerCref);
318 ✗ outerCrefsStripped := List.map(outerCrefs, ComponentReference.crefStripLastIdent);
319
320 // FIXME this variables are generated in StateMachineFlatten.addStateActivationAndReset(..) which is UGLY
321 ✗ outerCrefDers := List.map(outerCrefs, function ComponentReference.appendStringLastIdent(inString = "_der$"));
322
323 // der(x)
324 ✗ exp := DAE.CALL(Absyn.IDENT("der"), {DAE.CREF(innerCref, ty)}, DAE.callAttrBuiltinReal);
325 // der(x) = ...
326 ✗ outEqn := DAE.EQUATION(exp, mergingRhs_der(outerCrefDers, innerCref, ty), DAE.emptyElementSource);
327 end freshMergingEqn_der;
328
329 protected function mergingRhs_der "
330 Author: BTH
331 Helper function to freshMergingEqn_der.
332 Create RHS expression of merging equation.
333 "
334 input List<DAE.ComponentRef> inOuterCrefs "List of the crefs of the outer variables";
335 input DAE.ComponentRef inInnerCref;
336 input DAE.Type ty "type of inner cref (inner cref type expected to the same as outer crefs type)";
337 output DAE.Exp res;
338 protected
339 DAE.CallAttributes callAttributes = DAE.CALL_ATTR(ty,false,true,false,false,DAE.NO_INLINE(),DAE.NO_TAIL(),DAE.NoReturn.RETURNS);
340 algorithm
341 res := match inOuterCrefs
342 local
343 DAE.ComponentRef outerCref, crefState;
344 List<DAE.ComponentRef> rest;
345 DAE.Exp outerCrefExp, crefStateExp, ifExp, expCond, expElse;
346 case outerCref::{}
347 algorithm
348 ✗ outerCrefExp := DAE.CREF(outerCref, ty);
349 ✗ crefState := ComponentReference.crefStripLastIdent(outerCref);
350 ✗ crefStateExp := DAE.CREF(crefState, ty);
351 ✗ expCond := DAE.CALL(Absyn.IDENT("activeState"), {crefStateExp}, callAttributes);
352 expElse := DAE.RCONST(0);
353 ✗ ifExp := DAE.IFEXP(expCond, outerCrefExp, expElse);
354 then ifExp;
355 case outerCref::rest
356 algorithm
357 ✗ outerCrefExp := DAE.CREF(outerCref, ty);
358 ✗ crefState := ComponentReference.crefStripLastIdent(outerCref);
359 ✗ crefStateExp := DAE.CREF(crefState, ty);
360 ✗ expCond := DAE.CALL(Absyn.IDENT("activeState"), {crefStateExp}, callAttributes);
361 ✗ expElse := mergingRhs_der(rest, inInnerCref, ty);
362 ✗ ifExp := DAE.IFEXP(expCond, outerCrefExp, expElse);
363 then ifExp;
364 end match;
365
366 end mergingRhs_der;
367
368 protected function traversingCountDer "
369 Author: BTH
370 Helper function to traverse subexpressions
371 Counts occurances of 'der(cref)'
372 "
373 input DAE.Exp inExp;
374 input tuple<DAE.ComponentRef, Integer> inCref_HitCount "tuple of x and counter for hits of der(x)";
375 output DAE.Exp outExp;
376 output tuple<DAE.ComponentRef, Integer> outCref_HitCount;
377 protected
378 DAE.ComponentRef cref;
379 Integer hitCount;
380 algorithm
381 ✗ (cref, hitCount) := inCref_HitCount;
382 (outExp,outCref_HitCount) := match inExp
383 local
384 DAE.ComponentRef componentRef;
385 list<DAE.Exp> expLst;
386 case DAE.CALL(path=Absyn.IDENT("der"), expLst={DAE.CREF(componentRef=componentRef)})
387 guard ComponentReferenceBasics.crefEqual(componentRef, cref)
388 ✗ then (inExp, (cref, hitCount + 1));
389 else (inExp,inCref_HitCount);
390 end match;
391 end traversingCountDer;
392
393 protected function freshMergingEqn "
394 Author: BTH
395 Helper function to mergeVariableDefinition.
396 Create a fresh equation for merging outer output variable defintions
397 "
398 input tuple<DAE.ComponentRef, list<DAE.ComponentRef>> inInnerCrefToOuterOutputCrefs "tuple relating the inner cref to respective outer crefs";
399 output DAE.Element outEqn;
400 protected
401 DAE.ComponentRef innerCref;
402 List<DAE.ComponentRef> outerCrefs, outerCrefsStripped;
403 DAE.Type ty;
404 algorithm
405 4 (innerCref, outerCrefs) := inInnerCrefToOuterOutputCrefs;
406
407 // FIXME BTH use instead 'ty := ComponentReference.crefTypeConsiderSubs(innerCref);'?
408 4 ty := ComponentReference.crefLastType(innerCref);
409 4 outerCrefsStripped := List.map(outerCrefs, ComponentReference.crefStripLastIdent);
410
411 4 outEqn := DAE.EQUATION(DAE.CREF(innerCref, ty), mergingRhs(outerCrefs, innerCref, ty), DAE.emptyElementSource);
412 end freshMergingEqn;
413
414 protected function mergingRhs "
415 Author: BTH
416 Helper function to freshMergingEqn.
417 Create RHS expression of merging equation.
418 "
419 input List<DAE.ComponentRef> inOuterCrefs "List of the crefs of the outer variables";
420 input DAE.ComponentRef inInnerCref;
421 input DAE.Type ty "type of inner cref (inner cref type expected to the same as outer crefs type)";
422 output DAE.Exp res;
423 protected
424 DAE.CallAttributes callAttributes = DAE.CALL_ATTR(ty,false,true,false,false,DAE.NO_INLINE(),DAE.NO_TAIL(),DAE.NoReturn.RETURNS);
425 algorithm
426 res := match inOuterCrefs
427 local
428 DAE.ComponentRef outerCref, crefState;
429 List<DAE.ComponentRef> rest;
430 DAE.Exp outerCrefExp, innerCrefExp, crefStateExp, ifExp, expCond, expElse;
431 case outerCref::{}
432 algorithm
433 4 outerCrefExp := DAE.CREF(outerCref, ty);
434 4 innerCrefExp := DAE.CREF(inInnerCref, ty);
435 4 crefState := ComponentReference.crefStripLastIdent(outerCref);
436 4 crefStateExp := DAE.CREF(crefState, ty);
437 4 expCond := DAE.CALL(Absyn.IDENT("activeState"), {crefStateExp}, callAttributes);
438 4 expElse := DAE.CALL(Absyn.IDENT("previous"), {innerCrefExp}, callAttributes);
439 4 ifExp := DAE.IFEXP(expCond, outerCrefExp, expElse);
440 then ifExp;
441 case outerCref::rest
442 algorithm
443 3 outerCrefExp := DAE.CREF(outerCref, ty);
444 3 crefState := ComponentReference.crefStripLastIdent(outerCref);
445 3 crefStateExp := DAE.CREF(crefState, ty);
446 3 expCond := DAE.CALL(Absyn.IDENT("activeState"), {crefStateExp}, callAttributes);
447 3 expElse := mergingRhs(rest, inInnerCref, ty);
448 3 ifExp := DAE.IFEXP(expCond, outerCrefExp, expElse);
449 then ifExp;
450 end match;
451
452 end mergingRhs;
453
454 protected function collectCorrespondingKeys "
455 Author: BTH
456 Helper function to mergeVariableDefinitions"
457 input DAE.ComponentRef inInnerCref;
458 input list<tuple<DAE.ComponentRef, DAE.ComponentRef>> inHashEntries;
459 input HashTable3.HashTable inInnerCrefToOuterOutputCrefs;
460 output HashTable3.HashTable outInnerCrefToOuterOutputCrefs = inInnerCrefToOuterOutputCrefs;
461 protected
462 list<DAE.ComponentRef> outerRefs;
463 algorithm
464 4 outerRefs := List.filterMap1(inHashEntries, crefEqualTuple22, inInnerCref);
465 4 outInnerCrefToOuterOutputCrefs := BaseHashTable.addUnique((inInnerCref, outerRefs), outInnerCrefToOuterOutputCrefs);
466 end collectCorrespondingKeys;
467
468 protected function crefEqualTuple22 "
469 Helper function to collect collectCorrespondingKeys"
470 input tuple<DAE.ComponentRef, DAE.ComponentRef> inHashEntry;
471 input DAE.ComponentRef inCref;
472 output DAE.ComponentRef outCref;
473 protected
474 Boolean isEqual;
475 DAE.ComponentRef tuple22;
476 algorithm
477 10 tuple22 := Util.tuple22(inHashEntry);
478 10 isEqual := ComponentReferenceBasics.crefEqual(tuple22, inCref);
479
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7 times.
10 if (not isEqual) then fail(); end if;
480 7 outCref := Util.tuple21(inHashEntry);
481 end crefEqualTuple22;
482
483
484 protected function traverserHelperSubsOuterByInnerExp "
485 Author: BTH
486 Substitute outer variables in previous(x) by corresponding 'inner'.
487 Helper function to mergeVariableDefinitions"
488 input DAE.Exp inExp;
489 input HashTableCG.HashTable inOuterToInner;
490 output DAE.Exp outExp;
491 output HashTableCG.HashTable outOuterToInner;
492 algorithm
493 107 (outExp, outOuterToInner) := Expression.traverseExpBottomUp(inExp, traverserHelperSubsOuterByInner, inOuterToInner);
494 end traverserHelperSubsOuterByInnerExp;
495
496 protected function traverserHelperSubsOuterByInner "
497 Author: BTH
498 Helper function to traverserHelperSubsOuterByInnerExp"
499 input DAE.Exp inExp;
500 input HashTableCG.HashTable inOuterToInner;
501 output DAE.Exp outExp;
502 output HashTableCG.HashTable outOuterToInner;
503 algorithm
504 (outExp,outOuterToInner) := match inExp
505 local
506 DAE.ComponentRef componentRef;
507 DAE.Type ty;
508 DAE.CallAttributes attr;
509 // Substitute outer variables in previous(x) by corresponding 'inner:
510 case DAE.CALL(Absyn.IDENT("previous"), {DAE.CREF(componentRef, ty)}, attr)
511 18 guard BaseHashTable.hasKey(componentRef, inOuterToInner) then
512 (DAE.CALL(Absyn.IDENT("previous"), {DAE.CREF(BaseHashTable.get(componentRef, inOuterToInner), ty)}, attr), inOuterToInner);
513 else (inExp,inOuterToInner);
514 end match;
515 end traverserHelperSubsOuterByInner;
516
517 protected function matchOuterWithInner "
518 Author: BTH
519 Helper function to mergeVariableDefinitions
520 "
521 input DAE.ComponentRef inOuterCref;
522 input InnerOuter.InstHierarchy inIH;
523 input HashTableCG.HashTable inOuterCrefToInnerCref;
524 output HashTableCG.HashTable outOuterCrefToInnerCref = inOuterCrefToInnerCref;
525 protected
526 DAE.ComponentRef crefIdent, crefFound, strippedCref1, strippedCref2;
527 algorithm
528 7 crefIdent := ComponentReferenceBasics.crefLastCref(inOuterCref);
529
530 // inOuterCref is supposed to be "outer" or "inner outer" and we want to move one level up the instance hierachy for starting the search for the corresponding inner
531 7 strippedCref1 := ComponentReference.crefStripLastIdent(inOuterCref);
532 // Go up one instance level, append identifier and try again. If already at top level, try to find identifier at top level
533
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
7 strippedCref2 := if ComponentReference.crefDepth(strippedCref1) >= 2 then
534 ComponentReference.joinCrefs( ComponentReference.crefStripLastIdent(strippedCref1), crefIdent)
535 else crefIdent;
536 // now use strippedCref2 for starting the search in the instance hierarchy
537 7 crefFound := findInner(strippedCref2, crefIdent, inIH);
538
539 7 outOuterCrefToInnerCref := BaseHashTable.addUnique((inOuterCref, crefFound), outOuterCrefToInnerCref);
540 end matchOuterWithInner;
541
542 protected function findInner "
543 Author: BTH
544 Helper function to matchOuterWithInner
545 "
546 input DAE.ComponentRef inCrefTest;
547 input DAE.ComponentRef inCrefIdent;
548 input InnerOuter.InstHierarchy inIH;
549 output DAE.ComponentRef outCrefFound;
550 protected
551 DAE.ComponentRef strippedCref1, strippedCref2;
552 InnerOuter.InstHierarchyHashTable ht;
553 algorithm
554 7 InnerOuter.TOP_INSTANCE(ht=ht) := listHead(inIH);
555 try
556 7 InnerOuter.get(inCrefTest, ht);
557 outCrefFound := inCrefTest;
558 else
559 ✗ strippedCref1 := ComponentReference.crefStripLastIdent(inCrefTest);
560 // Go up one instance level, append identifier and try again. If already at top level, try to find identifier at top level
561 ✗ strippedCref2 := if ComponentReference.crefDepth(strippedCref1) >= 2 then
562 ComponentReference.joinCrefs( ComponentReference.crefStripLastIdent(strippedCref1), inCrefIdent)
563 else inCrefIdent;
564 ✗ outCrefFound := findInner(strippedCref2, inCrefIdent, inIH);
565 end try;
566 end findInner;
567
568 protected function collectOuterOutputs "
569 Author: BTH
570 Helper function to mergeVariableDefinitions.
571 "
572 input DAE.Element inElem;
573 input HashTableCG.HashTable inOuterAcc;
574 output HashTableCG.HashTable outOuterAcc = inOuterAcc;
575 protected
576 list<DAE.Element> outerOutputs;
577 list<DAE.ComponentRef> outerOutputCrefs;
578 list<tuple<HashTableCG.Key,HashTableCG.Value>> outerOutputCrefToSMCompCref;
579 // SM_COMP
580 DAE.ComponentRef componentRef;
581 list<DAE.Element> dAElist "a component with subelements";
582 algorithm
583 outOuterAcc := match inElem
584 case DAE.SM_COMP(componentRef=componentRef, dAElist=dAElist)
585 algorithm
586 19 outerOutputs := List.filterOnTrue(dAElist, isOuterOutput);
587 19 outerOutputCrefs := List.map(outerOutputs, DAEUtil.varCref);
588 19 outerOutputCrefToSMCompCref := List.map(outerOutputCrefs, function Util.makeTuple(inValue2=componentRef));
589 19 then List.fold(outerOutputCrefToSMCompCref, BaseHashTable.addUnique, outOuterAcc);
590 else inOuterAcc;
591 end match;
592 end collectOuterOutputs;
593
594 protected function isOuterOutput "
595 Author: BTH
596 Helper function to collectOuterOutputs.
597 "
598 input DAE.Element inElem;
599 output Boolean outB;
600 algorithm
601 outB := match inElem
602 local
603 DAE.VarDirection direction;
604 Absyn.InnerOuter innerOuter;
605 case DAE.VAR(direction=DAE.OUTPUT(), innerOuter=Absyn.OUTER()) then true;
606 case DAE.VAR(direction=DAE.OUTPUT(), innerOuter=Absyn.INNER_OUTER()) then true;
607 else false;
608 end match;
609 end isOuterOutput;
610
611 protected function createFlatSM "
612 Author: BTH
613 Helper function to wrapSMCompsInFlatSMs.
614 "
615 input DAE.ComponentRef smInitialCref;
616 input list<DAE.Element> smElemsLst;
617 input SMNodeToFlatSMGroupTable smNodeToFlatSMGroup;
618 output DAE.Element flatSM;
619 protected
620 list<DAE.Element> smElemsInFlatSM;
621 algorithm
622 8 smElemsInFlatSM := List.filter2OnTrue(smElemsLst, isInFlatSM, smInitialCref, smNodeToFlatSMGroup);
623 8 flatSM := DAE.FLAT_SM(ComponentReferenceBasics.printComponentRefStr(smInitialCref), smElemsInFlatSM);
624 end createFlatSM;
625
626 protected function isInFlatSM "
627 Author: BTH
628 Check if SM_COMP, transition or initialState (first argument) is part of the flat state machine which corresponds to smInitialCref.
629 "
630 input DAE.Element inElement;
631 input DAE.ComponentRef smInitialCref;
632 input SMNodeToFlatSMGroupTable smNodeToFlatSMGroup "Table which maps the cref of an SM_COMP to the cref of its corresponding flat state machine group";
633 output Boolean outResult;
634 protected
635 DAE.ComponentRef crefCorrespondingFlatSMGroup;
636 algorithm
637 crefCorrespondingFlatSMGroup := match inElement
638 local
639 DAE.ComponentRef cref1;
640 case DAE.SM_COMP(componentRef=cref1) guard BaseHashTable.hasKey(cref1, smNodeToFlatSMGroup)
641 25 then BaseHashTable.get(cref1, smNodeToFlatSMGroup);
642 case DAE.NORETCALL(exp=DAE.CALL(path=Absyn.IDENT("transition"),
643 expLst=DAE.CREF(componentRef=cref1)::_)) guard BaseHashTable.hasKey(cref1, smNodeToFlatSMGroup)
644 // Note that it suffices to check for the "from" state, since the "to" state must be in the same FlatSMGroup
645 21 then BaseHashTable.get(cref1, smNodeToFlatSMGroup);
646 case DAE.NORETCALL(exp=DAE.CALL(path=Absyn.IDENT("initialState"),
647 expLst={DAE.CREF(componentRef=cref1)})) guard BaseHashTable.hasKey(cref1, smNodeToFlatSMGroup)
648 10 then BaseHashTable.get(cref1, smNodeToFlatSMGroup);
649 else
650 algorithm
651 ✗ true := Flags.isSet(Flags.FAILTRACE);
652 ✗ Debug.traceln("- InstStateMachineUtil.isInFlatSM failed: Hash table lookup failed for " + DAEDump.dumpElementsStr({inElement}));
653 ✗ BaseHashTable.dumpHashTableStatistics(smNodeToFlatSMGroup);
654 ✗ then fail();
655 end match;
656
657 56 outResult := ComponentReferenceBasics.crefEqual(crefCorrespondingFlatSMGroup, smInitialCref);
658 end isInFlatSM;
659
660 protected function isSMComp "
661 Author: BTH
662 Check if element is a SM_COMP.
663 "
664 input DAE.Element inElement;
665 output Boolean outResult;
666 algorithm
667 outResult := match inElement
668 case DAE.SM_COMP(_,_) then true;
669 else false;
670 end match;
671 end isSMComp;
672
673 protected function relateNodesToGroup "
674 Author: BTH
675 Relate crefs of SMNodes with cref of the FlatSMGroup that it belongs to.
676 "
677 input FlatSMGroup flatSMGroup;
678 input SMNodeToFlatSMGroupTable inNodeToGroup;
679 output SMNodeToFlatSMGroupTable outNodeToGroup = inNodeToGroup;
680 protected
681 array<tuple<DAE.ComponentRef, DAE.ComponentRef>> nodeGroup;
682 // FLAT_SM_GROUP
683 DAE.ComponentRef initState;
684 array<DAE.ComponentRef> states;
685 algorithm
686 8 FLAT_SM_GROUP(initState, states) := flatSMGroup;
687 8 nodeGroup := Array.map(states, function Util.makeTuple(inValue2=initState));
688 8 outNodeToGroup := Array.fold(nodeGroup, BaseHashTable.add, outNodeToGroup);
689 end relateNodesToGroup;
690
691 protected function extractFlatSMGroup "
692 Author: BTH
693 For each initial state extract the (flat) state machine group that is defined by the
694 transitive closure associated with that initial state."
695 input list<DAE.ComponentRef> initialStates;
696 input AdjacencyTable iTable;
697 input Integer nStates "Number of states";
698 output list<FlatSMGroup> flatSMGroup;
699 protected
700 HashTable.HashTable cref2index;
701 array<array<Boolean>> adjacency;
702 list<tuple<DAE.ComponentRef, Integer>> entries;
703 array<DAE.ComponentRef> i2cref;
704 DAE.ComponentRef cref;
705 list<DAE.ComponentRef> members;
706 array<DAE.ComponentRef> membersArr;
707 HashSet.HashSet memberSet;
708 Integer n,i,j;
709 algorithm
710 7 ADJACENCY_TABLE(cref2index, adjacency) := iTable;
711 7 n := BaseHashTable.hashTableCurrentSize(cref2index);
712 // sanity check:
713
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(n == nStates, "Value of nStates needs to be equal to number of modes within state table argument.");
714
715 7 entries := BaseHashTable.hashTableList(cref2index);
716 7 entries := List.sort(entries, crefIndexCmp);
717 //i2cref := arrayCreate(n, ComponentReference.makeDummyCref());
718 7 i2cref := listArray(List.map(entries, Util.tuple21));
719
720 flatSMGroup := {};
721
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 7 times.
15 for cref in initialStates loop
722 8 i := BaseHashTable.get(cref, cref2index);
723 members := {};
724
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
33 for j in 1:n loop
725
2/2
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 6 times.
25 if arrayGet(arrayGet(adjacency,i),j) then
726 19 members := arrayGet(i2cref,j)::members;
727 end if;
728 end for;
729
730 // Ensure uniquenes of entries
731 8 memberSet := HashSet.emptyHashSetSized(listLength(members));
732 8 memberSet := List.fold(members, BaseHashSet.add, memberSet);
733
734 // Ensure that initialState comes first in array
735 8 memberSet := BaseHashSet.delete(cref, memberSet);
736 16 membersArr := listArray(cref :: BaseHashSet.hashSetList(memberSet));
737
738 8 flatSMGroup := FLAT_SM_GROUP(cref, membersArr)::flatSMGroup;
739 end for;
740
741 end extractFlatSMGroup;
742
743
744 public function dumpFlatSMGroupStr "
745 Author: BTH
746 Dump flat state machine group to string"
747 input FlatSMGroup flatA;
748 output String flatStr;
749 protected
750 list<DAE.ComponentRef> crefs;
751 String initialStateStr, statesStr;
752 list<String> statesStrs;
753 // FLAT_SM_GROUP fields
754 DAE.ComponentRef initState;
755 array<DAE.ComponentRef> states;
756 algorithm
757 ✗ FLAT_SM_GROUP(initState=initState, states=states) := flatA;
758 ✗ initialStateStr := ComponentReferenceBasics.printComponentRefStr(initState);
759 ✗ crefs := arrayList(states);
760 ✗ statesStrs := List.map(crefs, ComponentReferenceBasics.printComponentRefStr);
761 ✗ statesStr := stringDelimitList(statesStrs, ", ");
762
763 ✗ flatStr := initialStateStr+"( states("+statesStr+"))";
764 end dumpFlatSMGroupStr;
765
766
767 protected function extractInitialStates "
768 Author: BTH
769 Return crefs of states declared as 'initialState'. "
770 input SMNodeTable smNodeTable;
771 output list<DAE.ComponentRef> initialStates;
772 protected
773 list<tuple<DAE.ComponentRef, SMNode>> entries;
774 tuple<DAE.ComponentRef, SMNode> e;
775 DAE.ComponentRef cref;
776 SMNode smNode;
777 Boolean isInitial;
778 algorithm
779 7 entries := BaseHashTable.hashTableList(smNodeTable);
780 initialStates := {};
781
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 7 times.
26 for e in entries loop
782 19 (cref, smNode) := e;
783 19 SMNODE(isInitial=isInitial) := smNode;
784
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 11 times.
19 if isInitial then
785 initialStates := cref::initialStates;
786 end if;
787 end for;
788 end extractInitialStates;
789
790 protected function transitiveClosure "
791 Author: BTH
792 Compute the transitive closure over the transition relation between states.
793 This allows to group states that are part of the same (flat) state machine.
794 The function uses the Warshall's algorithm for that task, c.f.
795 http://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm
796 or the more succinct (and potentially more readable) description
797 http://de.wikipedia.org/wiki/Warshall-Algorithmus
798 "
799 input AdjacencyTable iTable;
800 input Integer nStates "Number of states";
801 output AdjacencyTable transClosure;
802 protected
803 HashTable.HashTable cref2index;
804 array<array<Boolean>> adjacency;
805 Integer n,k,i,j;
806 algorithm
807 7 ADJACENCY_TABLE(cref2index, adjacency) := iTable;
808 7 n := BaseHashTable.hashTableCurrentSize(cref2index);
809 // sanity check:
810
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(n == nStates, "Value of nStates needs to be equal to number of states within state table argument.");
811
812 // Warshall's algorithm for computing the transitive closure
813
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
26 for k in 1:n loop
814 65 for i in 1:n loop
815
2/2
✓ Branch 2 taken 47 times.
✓ Branch 3 taken 18 times.
65 if arrayGet(arrayGet(adjacency,i),k) then
816 175 for j in 1:n loop
817
2/2
✓ Branch 2 taken 125 times.
✓ Branch 3 taken 50 times.
175 if arrayGet(arrayGet(adjacency,k),j) then
818 125 arrayUpdate(arrayGet(adjacency,i), j, true);
819 end if;
820 end for;
821 end if;
822 end for;
823 end for;
824
825 7 transClosure := ADJACENCY_TABLE(cref2index, adjacency);
826 end transitiveClosure;
827
828 protected function createAdjacencyTable "
829 Author: BTH
830 Create adjacency table showing which modes are connected by transitions."
831 input SMNodeTable smNodes;
832 input Integer nStates "Number of states";
833 output AdjacencyTable iTable;
834 protected
835 HashTable.HashTable cref2index "Map cref to corresponding index in adjacency matrix";
836 array<array<Boolean>> adjacency "Adjacency matrix showing which states are connected by transitions";
837 Integer n,m,i,j,k;
838 DAE.ComponentRef cref;
839 HashSet.HashSet edges;
840 array<DAE.ComponentRef> crefs1,crefs2;
841 algorithm
842 7 crefs1 := listArray(BaseHashTable.hashTableKeyList(smNodes));
843 n := arrayLength(crefs1);
844 7 cref2index := HashTable.emptyHashTableSized(n);
845
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 assert(n == nStates, "Value of nStates needs to be equal to number of modes within mode table argument.");
846
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 7 times.
26 adjacency := listArray(list(arrayCreate(n, false) for i in 1:n));
847
848
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
26 for i in 1:n loop
849 19 cref2index := BaseHashTable.addNoUpdCheck((crefs1[i], i), cref2index);
850 end for;
851
852
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
26 for i in 1:n loop
853 19 SMNODE(edges=edges) := BaseHashTable.get(crefs1[i], smNodes);
854 19 crefs2 := listArray(BaseHashSet.hashSetList(edges));
855 m := arrayLength(crefs2);
856
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
62 for j in 1:m loop
857 43 cref := crefs2[j];
858 43 k := BaseHashTable.get(cref, cref2index);
859 43 arrayUpdate(arrayGet(adjacency,i), k, true);
860 end for;
861 end for;
862
863 7 iTable := ADJACENCY_TABLE(cref2index, adjacency);
864 end createAdjacencyTable;
865
866 protected function printAdjacencyTable "
867 Author: BTH
868 Print adjacency table."
869 input AdjacencyTable iTable;
870 input Integer nStates "Number of states";
871 protected
872 HashTable.HashTable cref2index;
873 array<array<Boolean>> adjacency;
874 list<tuple<DAE.ComponentRef, Integer>> entries;
875 tuple<DAE.ComponentRef, Integer> entry;
876 DAE.ComponentRef cref;
877 Integer n,i,j,padn;
878 String str,pads;
879 Boolean b;
880 algorithm
881 ✗ ADJACENCY_TABLE(cref2index, adjacency) := iTable;
882 ✗ entries := BaseHashTable.hashTableList(cref2index);
883
884 // sanity check:
885 ✗ n := listLength(entries);
886 ✗ assert(n == nStates, "Value of nStates needs to be equal to number of modes within state table argument.");
887
888 ✗ entries := List.sort(entries, crefIndexCmp);
889 ✗ for entry in entries loop
890 ✗ (cref, i) := entry;
891 ✗ print( ComponentReferenceBasics.printComponentRefStr(cref) + ": " + intString(i) + "\n" );
892 end for;
893
894 pads := " ";
895 padn := 8;
896 // Print table header
897 ✗ str := Util.stringPadRight("i", padn, pads);
898 ✗ for i in 1:n loop
899 ✗ str := str + Util.stringPadLeft(intString(i)+",", padn, pads);
900 end for;
901 ✗ print(str + "\n");
902 // print adjacency matrix rows
903 ✗ for i in 1:n loop
904 ✗ str := Util.stringPadRight(intString(i), padn, pads);
905 ✗ for j in 1:n loop
906 ✗ b := arrayGet(arrayGet(adjacency,i),j);
907 ✗ str := str + Util.stringPadLeft(boolString(b)+",", padn, pads);
908 end for;
909 ✗ print(str + "\n");
910 end for;
911 end printAdjacencyTable;
912
913 protected function crefIndexCmp "
914 Author: BTH
915 Compare the indices assigned to two crefs (helper function for sorting)"
916 input tuple<DAE.ComponentRef, Integer> inElement1;
917 input tuple<DAE.ComponentRef, Integer> inElement2;
918 output Boolean inRes;
919 protected
920 Integer i1, i2;
921 algorithm
922 14 (_, i1) := inElement1;
923 14 (_, i2) := inElement2;
924 14 inRes := i1 > i2;
925 end crefIndexCmp;
926
927 public function getSMNodeTable "
928 Author: BTH
929 Traverse the equations, search for 'transition' and 'initialState' operators,
930 extract the state arguments from them and collect them in the table."
931 input list<DAE.Element> elementLst;
932 output SMNodeTable smNodeTable;
933 protected
934 list<DAE.Element> elementLst2;
935 algorithm
936
6/6
✓ Branch 1 taken 24509 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 24533 times.
✓ Branch 4 taken 158439 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 158439 times.
182972 elementLst2 := list(e for e guard isSMStatement2(e) in elementLst);
937
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 158432 times.
158439 if not listEmpty(elementLst2) then
938 7 smNodeTable := List.fold(elementLst2, extractSMStates2, HashTableSM1.emptyHashTable());
939 else
940 158432 smNodeTable := HashTableSM1.emptyHashTableSized(1);
941 end if;
942 end getSMNodeTable;
943
944 protected function isSMStatement "
945 Author: BTH
946 Return true if element is a state machine statement, otherwise false"
947 input SCode.Equation inElement;
948 output Boolean outIsSMStatement;
949 algorithm
950 outIsSMStatement := match inElement
951 local
952 String name;
953
954 case SCode.EQ_NORETCALL(exp = Absyn.CALL(function_ =
955 Absyn.CREF_IDENT(name = name)))
956
7/10
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 1 time.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 24 times.
25 then (name == "transition" or name == "initialState") and
957 Config.synchronousFeaturesAllowed();
958
959 else false;
960 end match;
961 end isSMStatement;
962
963 protected function isSMStatement2 "
964 Author: BTH
965 Return true if element is a state machine statement, otherwise false"
966 input DAE.Element inElement;
967 output Boolean outIsSMStatement;
968 algorithm
969 outIsSMStatement := match inElement
970 local
971 String name;
972
973 case DAE.NORETCALL(exp = DAE.CALL(path = Absyn.IDENT(name)))
974
6/10
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 16 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 48 times.
48 then (name == "transition" or name == "initialState") and
975 Config.synchronousFeaturesAllowed();
976
977 else false;
978 end match;
979 end isSMStatement2;
980
981 protected function extractSMStates2 "
982 Author: BTH
983 Helper function to getSMNodeTable"
984 input DAE.Element inElement;
985 input SMNodeTable inTable;
986 output SMNodeTable outTable = inTable;
987 algorithm
988
989 outTable := match inElement
990 local
991 SMNode smnode1, smnode2;
992 DAE.ComponentRef cref1, cref2;
993 Boolean isInitial1, isInitial2;
994 HashSet.HashSet edges1, edges2;
995 case DAE.NORETCALL(exp=DAE.CALL(path=Absyn.IDENT("transition"),
996 expLst=DAE.CREF(componentRef=cref1)::DAE.CREF(componentRef=cref2)::_))
997 algorithm
998 //print("InstStateMachineUtil.extractSMStates: transition("+ComponentReference.crefStr(cref1)+", "+ComponentReference.crefStr(cref2)+")\n");
999
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
16 smnode1 := if BaseHashTable.hasKey(cref1, outTable)
1000 then BaseHashTable.get(cref1, outTable)
1001 else SMNODE(cref1, false, HashSet.emptyHashSet());
1002 16 SMNODE(_,isInitial1,edges1) := smnode1;
1003 16 edges1 := BaseHashSet.add(cref1, edges1);
1004 16 edges1 := BaseHashSet.add(cref2, edges1);
1005
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
28 smnode1 := SMNODE(cref1, isInitial1, edges1);
1006 16 outTable := BaseHashTable.add((cref1, smnode1), outTable);
1007
1008
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 11 times.
16 smnode2 := if BaseHashTable.hasKey(cref2, outTable)
1009 then BaseHashTable.get(cref2, outTable)
1010 else SMNODE(cref2, false, HashSet.emptyHashSet());
1011 16 SMNODE(_,isInitial2,edges2) := smnode2;
1012 16 edges2 := BaseHashSet.add(cref1, edges2);
1013 16 edges2 := BaseHashSet.add(cref2, edges2);
1014
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
29 smnode2 := SMNODE(cref2, isInitial2, edges2);
1015 16 outTable := BaseHashTable.add((cref2, smnode2), outTable);
1016 then outTable;
1017 case DAE.NORETCALL(exp=DAE.CALL(path=Absyn.IDENT("initialState"),
1018 expLst={DAE.CREF(componentRef=cref1)}))
1019 algorithm
1020 //print("InstStateMachineUtil.extractSMStates: initialState("+ComponentReference.crefStr(cref1)+")\n");
1021
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
8 smnode1 := if BaseHashTable.hasKey(cref1, outTable)
1022 then BaseHashTable.get(cref1, outTable)
1023 else SMNODE(cref1, true, HashSet.emptyHashSet());
1024 8 SMNODE(_,_,edges1) := smnode1;
1025 8 edges1 := BaseHashSet.add(cref1, edges1);
1026 8 smnode1 := SMNODE(cref1,true,edges1);
1027 8 outTable := BaseHashTable.add((cref1, smnode1), outTable);
1028 then outTable;
1029 end match;
1030
1031 end extractSMStates2;
1032
1033
1034
1035 public function getSMStatesInContext "
1036 Author: BTH
1037 Return list of states defined in current context (by checking 'transtion' and 'initialState' operators)"
1038 input list<SCode.Equation> eqns;
1039 input DAE.Prefix inPrefix;
1040 output list<DAE.ComponentRef> states "Initial and non-initial states";
1041 output list<DAE.ComponentRef> initialStates "Only initial states";
1042 protected
1043 list<SCode.Equation> eqns1;
1044 list<list<Absyn.ComponentRef>> statesLL;
1045 list<Absyn.ComponentRef> initialStatesCR, statesCR;
1046 algorithm
1047
6/6
✓ Branch 1 taken 18911 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 18935 times.
✓ Branch 4 taken 178259 times.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 178259 times.
197194 eqns1 := list(eq for eq guard isSMStatement(eq) in eqns);
1048 // Extract initial states
1049 178259 initialStatesCR := List.filterMap(eqns1, extractInitialSMStates);
1050 178259 initialStates := List.map(initialStatesCR, ComponentReference.toExpCref);
1051 // prefix the names
1052 178259 initialStates := List.map1(initialStates, prefixCrefNoContext2, inPrefix);
1053 // 01.06.2015 Strange. I get a compile error if using below instead of above AND removing prefixCrefNoContext2(..) function definitions
1054 // initialStates := List.map(initialStates, function PrefixUtil.prefixCrefNoContext(inPre=inPrefix));
1055
1056 // Extract states (initial as well as non-initial)
1057 178259 statesLL := List.map(eqns1, extractSMStates);
1058 178259 statesCR := List.flatten(statesLL);
1059 178259 states := List.map(statesCR, ComponentReference.toExpCref);
1060 // prefix the names
1061 178259 states := List.map(states, function PrefixUtil.prefixCrefNoContext(inPre=inPrefix));
1062 end getSMStatesInContext;
1063
1064 protected function prefixCrefNoContext2 "
1065 Helper function to getSMStatesInContext.
1066 Swapped order of inputs of PrefixUtil.prefixCrefNoContext(..) in order to use it with map1"
1067 input DAE.ComponentRef inCref;
1068 input DAE.Prefix inPre;
1069 output DAE.ComponentRef outCref;
1070 algorithm
1071 8 outCref := PrefixUtil.prefixCrefNoContext(inPre, inCref);
1072 end prefixCrefNoContext2;
1073
1074
1075 protected function extractInitialSMStates "
1076 Author: BTH
1077 Helper function to getSMStatesInContext.
1078 Return state instance componenent refs used as arguments in operator 'initialState'.
1079 "
1080 input SCode.Equation inElement;
1081 output Absyn.ComponentRef outElement;
1082 algorithm
1083 outElement := match inElement
1084 local
1085 Absyn.ComponentRef cref1;
1086 case SCode.EQ_NORETCALL(exp=Absyn.CALL(function_=
1087 Absyn.CREF_IDENT(name="initialState"),
1088 functionArgs = Absyn.FUNCTIONARGS(args =
1089 {Absyn.CREF(componentRef = cref1)}
1090 )))
1091 then cref1;
1092 end match;
1093 end extractInitialSMStates;
1094
1095 protected function extractSMStates "
1096 Author: BTH
1097 Helper function to getSMStatesInContext.
1098 Return list of state instance componenent refs used as arguments in operators 'transtion' or 'initialState'.
1099 "
1100 input SCode.Equation inElement;
1101 output list<Absyn.ComponentRef> outElement;
1102 algorithm
1103 outElement := match inElement
1104 local
1105 Absyn.ComponentRef cref1, cref2;
1106 case SCode.EQ_NORETCALL(exp=Absyn.CALL(function_=
1107 Absyn.CREF_IDENT(name="transition"),
1108 functionArgs = Absyn.FUNCTIONARGS(args =
1109 {Absyn.CREF(componentRef = cref1),
1110 Absyn.CREF(componentRef = cref2),_}
1111 )))
1112 then {cref1, cref2};
1113 case SCode.EQ_NORETCALL(exp=Absyn.CALL(function_=
1114 Absyn.CREF_IDENT(name="initialState"),
1115 functionArgs = Absyn.FUNCTIONARGS(args =
1116 {Absyn.CREF(componentRef = cref1)}
1117 )))
1118 then {cref1};
1119 else {};
1120 end match;
1121 end extractSMStates;
1122
1123 annotation(__OpenModelica_Interface="frontend");
1124 end InstStateMachineUtil;
1125