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 |