OMCompiler/Compiler/NBackEnd/Modules/2_Pre/NBFunctionAlias.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 NBFunctionAlias | ||
| 37 | "file: NBFunctionAlias.mo | ||
| 38 | package: NBFunctionAlias | ||
| 39 | description: This file contains the functions for the function alias encapsulation module. | ||
| 40 | " | ||
| 41 | public | ||
| 42 | import Module = NBModule; | ||
| 43 | protected | ||
| 44 | // OF imports | ||
| 45 | import Absyn; | ||
| 46 | import AbsynUtil; | ||
| 47 | import DAE; | ||
| 48 | |||
| 49 | // NF imports | ||
| 50 | import Call = NFCall; | ||
| 51 | import NFPrefixes; | ||
| 52 | import ComponentRef = NFComponentRef; | ||
| 53 | import Dimension = NFDimension; | ||
| 54 | import Expression = NFExpression; | ||
| 55 | import Operator = NFOperator; | ||
| 56 | import NFFunction.Function; | ||
| 57 | import Statement = NFStatement; | ||
| 58 | import SimplifyExp = NFSimplifyExp; | ||
| 59 | import Subscript = NFSubscript; | ||
| 60 | import Type = NFType; | ||
| 61 | import Variable = NFVariable; | ||
| 62 | |||
| 63 | // Backend imports | ||
| 64 | import BackendDAE = NBackendDAE; | ||
| 65 | import BEquation = NBEquation; | ||
| 66 | import Inline = NBInline; | ||
| 67 | import NBEquation.{Equation, EquationPointers, EqData, EquationAttributes, EquationKind, Iterator}; | ||
| 68 | import Partition = NBPartition; | ||
| 69 | import Partitioning = NBPartitioning; | ||
| 70 | import NBPartitioning.BClock; | ||
| 71 | import Slice = NBSlice; | ||
| 72 | import BVariable = NBVariable; | ||
| 73 | import NBVariable.{VariablePointer, VariablePointers, VarData}; | ||
| 74 | |||
| 75 | // Util imports | ||
| 76 | import List; | ||
| 77 | import StringUtil; | ||
| 78 | import UnorderedMap; | ||
| 79 | public | ||
| 80 | function main | ||
| 81 | "Wrapper function for any function alias introduction function. This will be | ||
| 82 | called during simulation and gets the corresponding subfunction from | ||
| 83 | Config." | ||
| 84 | extends Module.wrapper; | ||
| 85 | input Partition.Kind kind; | ||
| 86 | protected | ||
| 87 | Module.aliasInterface func; | ||
| 88 | algorithm | ||
| 89 | 193 | func := getModule(); | |
| 90 | |||
| 91 | bdae := match bdae | ||
| 92 | local | ||
| 93 | VarData varData "Data containing variable pointers"; | ||
| 94 | EqData eqData "Data containing equation pointers"; | ||
| 95 | |||
| 96 | case BackendDAE.MAIN(varData = varData, eqData = eqData) | ||
| 97 | algorithm | ||
| 98 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 193 times.
|
193 | (varData, eqData) := func(varData, eqData, kind); |
| 99 | 193 | bdae.varData := varData; | |
| 100 | 193 | bdae.eqData := eqData; | |
| 101 | then bdae; | ||
| 102 | |||
| 103 | case BackendDAE.HESSIAN(varData = varData, eqData = eqData) | ||
| 104 | algorithm | ||
| 105 | ✗ | (varData, eqData) := func(varData, eqData, kind); | |
| 106 | ✗ | bdae.varData := varData; | |
| 107 | ✗ | bdae.eqData := eqData; | |
| 108 | then bdae; | ||
| 109 | |||
| 110 | else algorithm | ||
| 111 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."}); | |
| 112 | ✗ | then fail(); | |
| 113 | end match; | ||
| 114 | end main; | ||
| 115 | |||
| 116 | function getModule | ||
| 117 | "Returns the module function that was chosen by the user." | ||
| 118 | output Module.functionAliasInterface func; | ||
| 119 | protected | ||
| 120 | String flag = "default"; | ||
| 121 | algorithm | ||
| 122 | func := match flag | ||
| 123 | case "default" then functionAliasDefault; | ||
| 124 | /* ... New function alias modules have to be added here */ | ||
| 125 | else fail(); | ||
| 126 | end match; | ||
| 127 | end getModule; | ||
| 128 | |||
| 129 | function introduceSlicedStateAlias | ||
| 130 | "introduces alias for variables that are only partially states to ensure variables are either a state in their entirety or not a state at all. | ||
| 131 | to be used in DetectStates, just before the der() calls are resolved. | ||
| 132 | 1. collect all crefs in der() calls that do not fully access the variable | ||
| 133 | 2. check if any variable is not fully a state by combining all their sliced der() calls | ||
| 134 | 3. replace all variables that are not fully states by alias variables and create equations" | ||
| 135 | extends Module.functionAliasInterface; | ||
| 136 | protected | ||
| 137 | UnorderedMap<Call_Id, Call_Aux> aux_map = UnorderedMap.new<Call_Aux>(Call_Id.hash, Call_Id.isEqual); | ||
| 138 | list<Pointer<Variable>> new_vars_cont = {}, new_vars_recd = {}; | ||
| 139 | list<Pointer<Equation>> new_eqns_cont = {}; | ||
| 140 | algorithm | ||
| 141 | () := match (eqData, varData) | ||
| 142 | local | ||
| 143 | UnorderedMap<ComponentRef,Indices> map = UnorderedMap.new<Indices>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 144 | UnorderedSet<ComponentRef> set; | ||
| 145 | Pointer<Integer> aux_index = Pointer.create(1); | ||
| 146 | |||
| 147 | case (EqData.EQ_DATA_SIM(), VarData.VAR_DATA_SIM()) algorithm | ||
| 148 | // first collect all state slices | ||
| 149 | 190 | EquationPointers.map(eqData.simulation, function collectSlicedStatesAliasEquation(map = map)); | |
| 150 | 190 | set := getSlicedStatesSet(map); | |
| 151 | |||
| 152 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 190 times.
|
190 | if not UnorderedSet.isEmpty(set) then |
| 153 | // replace all state slices of variables that are only partially states | ||
| 154 | ✗ | eqData.simulation := EquationPointers.map(eqData.simulation, function introduceSlicedStateAliasEquation(set = set, map = aux_map, aux_index = aux_index)); | |
| 155 | |||
| 156 | // create new state slice variables and corresponding equations for the alias | ||
| 157 | ✗ | (_, new_vars_cont, _, new_vars_recd, _, new_eqns_cont, _) := | |
| 158 | resolveAux(aux_map, eqData.uniqueIndex, false, {}, new_vars_cont, {}, new_vars_recd, {}, new_eqns_cont, {}); | ||
| 159 | end if; | ||
| 160 | then (); | ||
| 161 | else (); | ||
| 162 | end match; | ||
| 163 | |||
| 164 | // add the new variables and equations (should only be continuous, states are still considered algebraic) | ||
| 165 | 190 | varData := VarData.addTypedList(varData, new_vars_cont, VarData.VarType.ALGEBRAIC); | |
| 166 | 190 | varData := VarData.addTypedList(varData, new_vars_recd, VarData.VarType.RECORD); | |
| 167 | 190 | eqData := EqData.addTypedList(eqData, new_eqns_cont, EqData.EqType.CONTINUOUS, false); | |
| 168 | |||
| 169 | // update record children | ||
| 170 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
|
190 | for var in new_vars_recd loop |
| 171 | ✗ | BackendDAE.lowerRecordChildren(var, VarData.getVariables(varData)); | |
| 172 | end for; | ||
| 173 | |||
| 174 | // dump if flag is set | ||
| 175 |
1/2✓ Branch 1 taken 190 times.
✗ Branch 2 not taken.
|
190 | if Flags.isSet(Flags.DUMP_CSE) then |
| 176 | ✗ | print(aliasListToString(UnorderedMap.toList(aux_map), Call_Id.toString, Call_Aux.toString, "Sliced State")); | |
| 177 | end if; | ||
| 178 | end introduceSlicedStateAlias; | ||
| 179 | |||
| 180 | uniontype Call_Id | ||
| 181 | "key for UnorderedMap. | ||
| 182 | used to uniquely identify a function call" | ||
| 183 | record CALL_ID | ||
| 184 | Expression call; | ||
| 185 | Iterator iter; | ||
| 186 | // ToDo: instead of skipping when and if, one could collect these conditions | ||
| 187 | // and create the function call equations with them. | ||
| 188 | // Note: update hashing, isEqual and take into account that there can be | ||
| 189 | // elseif/elsewhen which need to be chained | ||
| 190 | // Option<Expression> when_condition | ||
| 191 | // Option<Expression> if_condition | ||
| 192 | end CALL_ID; | ||
| 193 | |||
| 194 | function toString | ||
| 195 | input Call_Id id; | ||
| 196 | output String str; | ||
| 197 | algorithm | ||
| 198 |
2/2✓ Branch 1 taken 127 times.
✓ Branch 2 taken 2036 times.
|
2163 | str := if not Iterator.isEmpty(id.iter) then " [" + Iterator.toString(id.iter) + "]" else ""; |
| 199 | 2163 | str := Expression.toString(id.call) + str; | |
| 200 | end toString; | ||
| 201 | |||
| 202 | function hash | ||
| 203 | "just hashes the id based on its string representation" | ||
| 204 | input Call_Id id; | ||
| 205 | output Integer hash; | ||
| 206 | algorithm | ||
| 207 | 2163 | hash := stringHashDjb2(toString(id)); | |
| 208 | end hash; | ||
| 209 | |||
| 210 | function isEqual | ||
| 211 | input Call_Id id1; | ||
| 212 | input Call_Id id2; | ||
| 213 | output Boolean b; | ||
| 214 | algorithm | ||
| 215 |
2/4✓ Branch 1 taken 845 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 845 times.
|
845 | b := Expression.isEqual(id1.call, id2.call) and Iterator.isEqual(id1.iter, id2.iter); |
| 216 | end isEqual; | ||
| 217 | end Call_Id; | ||
| 218 | |||
| 219 | uniontype Call_Aux | ||
| 220 | "value for UnorderedMap. | ||
| 221 | represents the auxilliary variable that will be created and has | ||
| 222 | the equation kind for auxilliary equation." | ||
| 223 | record CALL_AUX | ||
| 224 | Expression replacer; | ||
| 225 | EquationKind kind; | ||
| 226 | Boolean parsed; | ||
| 227 | end CALL_AUX; | ||
| 228 | |||
| 229 | function toString | ||
| 230 | input Call_Aux aux; | ||
| 231 | output String str = Expression.toString(aux.replacer); | ||
| 232 | end toString; | ||
| 233 | |||
| 234 | function getVars | ||
| 235 | input Call_Aux aux; | ||
| 236 | output list<Pointer<Variable>> vars = getVarsExp(aux.replacer); | ||
| 237 | protected | ||
| 238 | function getVarsExp | ||
| 239 | input Expression exp; | ||
| 240 | output list<Pointer<Variable>> vars; | ||
| 241 | algorithm | ||
| 242 | vars := match exp | ||
| 243 | case Expression.CREF(cref = ComponentRef.WILD()) then {}; | ||
| 244 | 607 | case Expression.CREF() then {BVariable.getVarPointer(exp.cref, sourceInfo())}; | |
| 245 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 time.
|
3 | case Expression.TUPLE() then List.flatten(list(getVarsExp(elem) for elem in exp.elements)); |
| 246 | else algorithm | ||
| 247 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because function alias auxilliary has a return type that currently cannot be parsed: " + Expression.toString(exp)}); | |
| 248 | ✗ | then fail(); | |
| 249 | end match; | ||
| 250 | end getVarsExp; | ||
| 251 | end getVars; | ||
| 252 | |||
| 253 | function createName | ||
| 254 | input Type ty; | ||
| 255 | input Iterator iter; | ||
| 256 | input Pointer<Integer> aux_index; | ||
| 257 | input String aux_name; | ||
| 258 | input Boolean init; | ||
| 259 | output ComponentRef name; | ||
| 260 | protected | ||
| 261 | Type new_ty = ty; | ||
| 262 | list<Subscript> subs; | ||
| 263 | algorithm | ||
| 264 |
2/2✓ Branch 1 taken 43 times.
✓ Branch 2 taken 564 times.
|
607 | if not Iterator.isEmpty(iter) then |
| 265 | 43 | new_ty := Type.liftArrayRightList(ty, Iterator.dimensions(iter)); | |
| 266 | 43 | (_, name) := BVariable.makeAuxVar(aux_name, Pointer.access(aux_index), new_ty, init); | |
| 267 | // add iterators to subscripts of auxilliary variable. fill with WHOLE if necessary | ||
| 268 | 43 | subs := Iterator.normalizedSubscripts(iter); | |
| 269 | 43 | subs := Subscript.fillWithWholeLeft(subs, Type.dimensionCount(new_ty)); | |
| 270 | 43 | name := ComponentRef.mergeSubscripts(subs, name, true, true); | |
| 271 | else | ||
| 272 | 564 | (_, name) := BVariable.makeAuxVar(aux_name, Pointer.access(aux_index), new_ty, init); | |
| 273 | end if; | ||
| 274 | 607 | Pointer.update(aux_index, Pointer.access(aux_index) + 1); | |
| 275 | end createName; | ||
| 276 | end Call_Aux; | ||
| 277 | |||
| 278 | protected | ||
| 279 | function functionAliasTplString | ||
| 280 | input tuple<String, String> tpl; | ||
| 281 | input Integer max_length; | ||
| 282 | output String str; | ||
| 283 | algorithm | ||
| 284 | ✗ | str := Util.tuple21(tpl) + " " + StringUtil.repeat(".", max_length - stringLength(Util.tuple21(tpl))) + " " + Util.tuple22(tpl); | |
| 285 | end functionAliasTplString; | ||
| 286 | |||
| 287 | function functionAliasDefault | ||
| 288 | extends Module.functionAliasInterface; | ||
| 289 | protected | ||
| 290 | UnorderedMap<Call_Id, Call_Aux> map = UnorderedMap.new<Call_Aux>(Call_Id.hash, Call_Id.isEqual); | ||
| 291 | VariablePointers variables = VarData.getVariables(varData); | ||
| 292 | UnorderedSet<VariablePointer> set = UnorderedSet.new(BVariable.hash, BVariable.equalName) "new iterators"; | ||
| 293 | UnorderedMap<BClock, ComponentRef> clock_map = UnorderedMap.new<ComponentRef>(BClock.hash, BClock.isEqual), infer_map = UnorderedMap.new<ComponentRef>(BClock.hash, BClock.isEqual); | ||
| 294 | Pointer<Integer> aux_index = Pointer.create(1); | ||
| 295 | list<Pointer<Variable>> new_vars_disc = {}, new_vars_cont = {}, new_vars_init = {}, new_vars_recd = {}, new_vars_clck = {}, new_vars_infr = {}; | ||
| 296 | list<Pointer<Equation>> new_eqns_disc = {}, new_eqns_cont = {}, new_eqns_init = {}, new_eqns_clck = {}, new_eqns_infr = {}; | ||
| 297 | list<tuple<Call_Id, Call_Aux>> debug_lst_sim = {}, debug_lst_ini, sim_aliases = {}; | ||
| 298 | algorithm | ||
| 299 | () := match (eqData, varData) | ||
| 300 | case (EqData.EQ_DATA_SIM(), VarData.VAR_DATA_SIM()) algorithm | ||
| 301 | // first collect all new functions from simulation equations | ||
| 302 | 386 | eqData.simulation := EquationPointers.map(eqData.simulation, | |
| 303 | function introduceFunctionAliasEquation(map = map, variables = variables, set = set, aux_index = aux_index, eqn_index = eqData.uniqueIndex, init = false)); | ||
| 304 | |||
| 305 | // also collect all new functions from removed equations | ||
| 306 | 386 | eqData.removed := EquationPointers.map(eqData.removed, | |
| 307 | function introduceFunctionAliasEquation(map = map, variables = variables, set = set, aux_index = aux_index, eqn_index = eqData.uniqueIndex, init = false)); | ||
| 308 | |||
| 309 | // create new simulation variables and corresponding equations for the function alias | ||
| 310 | 193 | (new_vars_disc, new_vars_cont, new_vars_init, new_vars_recd, new_eqns_disc, new_eqns_cont, new_eqns_init) := | |
| 311 | resolveAux(map, eqData.uniqueIndex, false, new_vars_disc, new_vars_cont, new_vars_init, new_vars_recd, new_eqns_disc, new_eqns_cont, new_eqns_init); | ||
| 312 | |||
| 313 | 193 | sim_aliases := UnorderedMap.toList(map); | |
| 314 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 193 times.
|
193 | if Flags.isSet(Flags.DUMP_CSE) then |
| 315 | debug_lst_sim := sim_aliases; | ||
| 316 | end if; | ||
| 317 | |||
| 318 | // afterwards collect all functions from initial equations | ||
| 319 | 386 | eqData.initials := EquationPointers.map(eqData.initials, | |
| 320 | function introduceFunctionAliasEquation(map = map, variables = variables, set = set, aux_index = aux_index, eqn_index = eqData.uniqueIndex, init = true)); | ||
| 321 | |||
| 322 | // add parameter function alias | ||
| 323 | 386 | varData.parameters := VariablePointers.mapPtr(varData.parameters, | |
| 324 | function BVariable.mapExp(funcExp = function introduceFunctionAlias(map = map, aux_index = aux_index, iter = Iterator.EMPTY(), init = true), | ||
| 325 | mapFunc = Expression.fakeMap)); | ||
| 326 | |||
| 327 | // create new initialization variables and corresponding equations for the function alias | ||
| 328 | 193 | (new_vars_disc, new_vars_cont, new_vars_init, new_vars_recd, new_eqns_disc, new_eqns_cont, new_eqns_init) := | |
| 329 | resolveAux(map, eqData.uniqueIndex, true, new_vars_disc, new_vars_cont, new_vars_init, new_vars_recd, new_eqns_disc, new_eqns_cont, new_eqns_init); | ||
| 330 | |||
| 331 | // create clock alias equations | ||
| 332 | 193 | (new_eqns_clck, new_eqns_infr, new_vars_clck, new_vars_infr, clock_map, infer_map) := addClockedAlias(eqData.simulation, eqData.uniqueIndex); | |
| 333 | then (); | ||
| 334 | else (); | ||
| 335 | end match; | ||
| 336 | |||
| 337 | // add the new variables and equations. | ||
| 338 | // Note: inferred clocks are handled as unknowns to properly partition them | ||
| 339 | 193 | varData := VarData.addTypedList(varData, new_vars_cont, VarData.VarType.ALGEBRAIC); | |
| 340 | 193 | varData := VarData.addTypedList(varData, new_vars_disc, VarData.VarType.DISCRETE); | |
| 341 | 193 | varData := VarData.addTypedList(varData, new_vars_init, VarData.VarType.PARAMETER); | |
| 342 | 193 | varData := VarData.addTypedList(varData, new_vars_recd, VarData.VarType.RECORD); | |
| 343 | 193 | varData := VarData.addTypedList(varData, new_vars_clck, VarData.VarType.CLOCK); | |
| 344 | 193 | varData := VarData.addTypedList(varData, new_vars_infr, VarData.VarType.DISCRETE); | |
| 345 | 193 | varData := VarData.addTypedList(varData, UnorderedSet.toList(set), VarData.VarType.ITERATOR); | |
| 346 | 193 | eqData := EqData.addTypedList(eqData, new_eqns_cont, EqData.EqType.CONTINUOUS, false); | |
| 347 | 193 | eqData := EqData.addTypedList(eqData, new_eqns_disc, EqData.EqType.DISCRETE, false); | |
| 348 | 193 | eqData := EqData.addTypedList(eqData, new_eqns_init, EqData.EqType.INITIAL, false); | |
| 349 | 193 | eqData := EqData.addTypedList(eqData, new_eqns_clck, EqData.EqType.CLOCKED, false); | |
| 350 | 193 | eqData := EqData.addTypedList(eqData, new_eqns_infr, EqData.EqType.DISCRETE, false); | |
| 351 | |||
| 352 | // update record children | ||
| 353 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 193 times.
|
241 | for var in new_vars_recd loop |
| 354 | 48 | BackendDAE.lowerRecordChildren(var, VarData.getVariables(varData)); | |
| 355 | end for; | ||
| 356 | |||
| 357 | // the record children exist now, so the auxiliary variables can get their start values | ||
| 358 |
2/2✓ Branch 0 taken 376 times.
✓ Branch 1 taken 193 times.
|
569 | for tpl in sim_aliases loop |
| 359 | 376 | addAuxStartValue(Util.tuple21(tpl), Util.tuple22(tpl)); | |
| 360 | end for; | ||
| 361 | |||
| 362 | // dump if flag is set | ||
| 363 |
1/2✓ Branch 1 taken 193 times.
✗ Branch 2 not taken.
|
193 | if Flags.isSet(Flags.DUMP_CSE) then |
| 364 | // remove sim vars from final map to see whats exclusively initial | ||
| 365 | ✗ | for tpl in debug_lst_sim loop | |
| 366 | ✗ | UnorderedMap.remove(Util.tuple21(tpl), map); | |
| 367 | end for; | ||
| 368 | ✗ | debug_lst_ini := UnorderedMap.toList(map); | |
| 369 | ✗ | print(aliasListToString(debug_lst_sim, Call_Id.toString, Call_Aux.toString, "Simulation Function")); | |
| 370 | ✗ | print(aliasListToString(debug_lst_ini, Call_Id.toString, Call_Aux.toString, "Initial Function")); | |
| 371 | ✗ | print(aliasListToString(UnorderedMap.toList(clock_map), BClock.toString, ComponentRef.toString, "Clocked Function")); | |
| 372 | ✗ | print(aliasListToString(UnorderedMap.toList(infer_map), BClock.toString, ComponentRef.toString, "Inferred Clocked Function")); | |
| 373 | end if; | ||
| 374 | end functionAliasDefault; | ||
| 375 | |||
| 376 | function addAuxStartValue | ||
| 377 | "The continuous outputs of a function call start at the call itself. The arguments are replaced by their | ||
| 378 | start values in the initialization, so a changed start value of an argument also changes the start value here. | ||
| 379 | Without it the outputs start at zero, which can make the Jacobian singular at the start (e.g. for products). | ||
| 380 | Only calls that can safely be evaluated at the start values are used." | ||
| 381 | input Call_Id id; | ||
| 382 | input Call_Aux aux; | ||
| 383 | algorithm | ||
| 384 |
5/6✓ Branch 0 taken 374 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 344 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 30 times.
|
376 | if aux.kind == EquationKind.CONTINUOUS and (Iterator.isEmpty(id.iter) or hasPlainIterators(id.iter)) then |
| 385 | () := match (id.call, aux.replacer) | ||
| 386 | local | ||
| 387 | Integer i = 0; | ||
| 388 | Expression replacer, call_exp; | ||
| 389 | list<Expression> elements; | ||
| 390 | |||
| 391 | case (call_exp as Expression.CALL(call = Call.TYPED_CALL()), replacer as Expression.CREF(cref = ComponentRef.CREF())) | ||
| 392 | guard(isStartUsefulFunction(Call.typedFunction(call_exp.call))) algorithm | ||
| 393 | 133 | setAuxStartValue(BVariable.getVarPointer(replacer.cref, sourceInfo()), iterateStart(id.call, id.iter)); | |
| 394 | then (); | ||
| 395 | |||
| 396 | case (call_exp as Expression.CALL(call = Call.TYPED_CALL()), Expression.TUPLE(elements = elements)) | ||
| 397 | guard(isStartUsefulFunction(Call.typedFunction(call_exp.call))) algorithm | ||
| 398 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
|
3 | for elem in elements loop |
| 399 | 2 | i := i + 1; | |
| 400 | () := match elem | ||
| 401 | case Expression.CREF(cref = ComponentRef.CREF()) | ||
| 402 | algorithm | ||
| 403 | 2 | setAuxStartValue(BVariable.getVarPointer(elem.cref, sourceInfo()), iterateStart(Expression.tupleElement(id.call, i), id.iter)); | |
| 404 | then (); | ||
| 405 | else (); | ||
| 406 | end match; | ||
| 407 | end for; | ||
| 408 | then (); | ||
| 409 | |||
| 410 | else (); | ||
| 411 | end match; | ||
| 412 | end if; | ||
| 413 | end addAuxStartValue; | ||
| 414 | |||
| 415 | function hasPlainIterators | ||
| 416 | "true if all iterators are plain ranges (no mapped array iterators)" | ||
| 417 | input Iterator iter; | ||
| 418 | output Boolean b; | ||
| 419 | protected | ||
| 420 | list<Option<Iterator>> maps; | ||
| 421 | algorithm | ||
| 422 | 30 | (_, _, maps) := Iterator.getFrames(iter); | |
| 423 | b := true; | ||
| 424 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 30 times.
|
66 | for map in maps loop |
| 425 |
3/8✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 36 times.
|
36 | b := b and isNone(map); |
| 426 | end for; | ||
| 427 | end hasPlainIterators; | ||
| 428 | |||
| 429 | function iterateStart | ||
| 430 | "The start value of the full variable of a call inside of a for equation. The dimensions of the | ||
| 431 | call result come first, then the iterators: {{call[k] for i1 in r1, i2 in r2} for k in 1:n}. | ||
| 432 | Only scalar and vector results, EMPTY() otherwise." | ||
| 433 | input output Expression exp; | ||
| 434 | input Iterator iter; | ||
| 435 | protected | ||
| 436 | list<Dimension> dims; | ||
| 437 | list<Expression> elements; | ||
| 438 | Integer n; | ||
| 439 | algorithm | ||
| 440 |
2/2✓ Branch 1 taken 128 times.
✓ Branch 2 taken 7 times.
|
135 | if not Iterator.isEmpty(iter) then |
| 441 | 7 | dims := Type.arrayDims(Expression.typeOf(exp)); | |
| 442 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
|
7 | if listEmpty(dims) then |
| 443 | 4 | exp := iterateScalarStart(exp, iter); | |
| 444 | elseif listLength(dims) == 1 and Dimension.isKnown(listHead(dims)) then | ||
| 445 | 3 | n := Dimension.size(listHead(dims)); | |
| 446 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
|
11 | elements := list(iterateScalarStart(Expression.applySubscripts({Subscript.INDEX(Expression.INTEGER(k))}, exp), iter) for k in 1:n); |
| 447 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | exp := if List.any(elements, Expression.isEmpty) then Expression.EMPTY(Expression.typeOf(exp)) |
| 448 | else Expression.makeExpArray(listArray(elements), Expression.typeOf(listHead(elements))); | ||
| 449 | else | ||
| 450 | ✗ | exp := Expression.EMPTY(Expression.typeOf(exp)); | |
| 451 | end if; | ||
| 452 | end if; | ||
| 453 | end iterateStart; | ||
| 454 | |||
| 455 | function iterateScalarStart | ||
| 456 | "{{exp for i2 in r2} for i1 in r1} for the iterators {i1, i2}, unrolled with literal iterator values | ||
| 457 | (the element crefs have to be simulation variables). EMPTY() for non constant or too big ranges." | ||
| 458 | input output Expression exp; | ||
| 459 | input Iterator iter; | ||
| 460 | protected | ||
| 461 | constant Integer max_size = 1000; | ||
| 462 | list<ComponentRef> names; | ||
| 463 | list<Expression> ranges; | ||
| 464 | list<Integer> values; | ||
| 465 | list<Expression> elements; | ||
| 466 | Integer size = 1; | ||
| 467 | Type ty; | ||
| 468 | algorithm | ||
| 469 | 8 | (names, ranges, _) := Iterator.getFrames(iter); | |
| 470 |
2/2✓ Branch 2 taken 8 times.
✓ Branch 3 taken 8 times.
|
16 | for tpl in listReverse(List.zip(names, ranges)) loop |
| 471 | 8 | values := rangeValues(Util.tuple22(tpl)); | |
| 472 | 8 | size := size * listLength(values); | |
| 473 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
|
8 | if listEmpty(values) or size > max_size then |
| 474 | ✗ | exp := Expression.EMPTY(Expression.typeOf(exp)); | |
| 475 | ✗ | return; | |
| 476 | end if; | ||
| 477 |
4/4✓ Branch 0 taken 24 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 8 times.
|
32 | elements := list(SimplifyExp.simplify(Expression.replaceIterator(exp, ComponentRef.node(Util.tuple21(tpl)), Expression.INTEGER(v))) for v in values); |
| 478 | 8 | ty := Type.liftArrayLeft(Expression.typeOf(exp), Dimension.fromInteger(listLength(values))); | |
| 479 | 8 | exp := Expression.makeArray(ty, listArray(elements)); | |
| 480 | end for; | ||
| 481 | end iterateScalarStart; | ||
| 482 | |||
| 483 | function rangeValues | ||
| 484 | "the values of a constant integer range, empty otherwise" | ||
| 485 | input Expression range; | ||
| 486 | output list<Integer> values = {}; | ||
| 487 | algorithm | ||
| 488 | values := match range | ||
| 489 | local | ||
| 490 | Integer start, step, stop; | ||
| 491 | case Expression.RANGE(start = Expression.INTEGER(start), step = NONE(), stop = Expression.INTEGER(stop)) | ||
| 492 | 8 | then List.intRange2(start, stop); | |
| 493 | case Expression.RANGE(start = Expression.INTEGER(start), step = SOME(Expression.INTEGER(step)), stop = Expression.INTEGER(stop)) | ||
| 494 | ✗ | guard(step <> 0) then list(i for i in start:step:stop); | |
| 495 | else {}; | ||
| 496 | end match; | ||
| 497 | end rangeValues; | ||
| 498 | |||
| 499 | function setAuxStartValue | ||
| 500 | "sets the start value of a real variable (or all real children of a record) to the expression" | ||
| 501 | input Pointer<Variable> var_ptr; | ||
| 502 | input Expression exp; | ||
| 503 | protected | ||
| 504 | list<Pointer<Variable>> children = BVariable.getRecordChildren(var_ptr); | ||
| 505 | Variable var; | ||
| 506 | algorithm | ||
| 507 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 108 times.
|
135 | if listEmpty(children) then |
| 508 | 108 | var := Pointer.access(var_ptr); | |
| 509 | // keep a start value inherited from the function output declaration. | ||
| 510 | // arrays (e.g. the outputs of calls in for equations) need a start value of the same size | ||
| 511 |
8/14✓ Branch 3 taken 108 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 108 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 108 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 29 times.
✓ Branch 13 taken 79 times.
✓ Branch 17 taken 29 times.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✓ Branch 21 taken 108 times.
✓ Branch 24 taken 108 times.
✗ Branch 25 not taken.
|
108 | if Type.isReal(Type.arrayElementType(Variable.typeOf(var))) and not BVariable.isRecord(var_ptr) |
| 512 | and not Expression.isEmpty(exp) | ||
| 513 | and (not BVariable.isArray(var_ptr) or Type.isEqual(Variable.typeOf(var), Expression.typeOf(exp))) | ||
| 514 | and isNone(BVariable.getStartAttribute(var_ptr)) then | ||
| 515 | 108 | Pointer.update(var_ptr, BVariable.setStartAttribute(var, exp)); | |
| 516 | end if; | ||
| 517 | else | ||
| 518 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 27 times.
|
82 | for child in children loop |
| 519 | 55 | var := Pointer.access(child); | |
| 520 |
6/10✓ Branch 2 taken 54 times.
✓ Branch 3 taken 1 time.
✓ Branch 5 taken 54 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 54 times.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 54 times.
✓ Branch 15 taken 54 times.
✗ Branch 16 not taken.
|
55 | if Type.isReal(Variable.typeOf(var)) and not BVariable.isArray(child) and not BVariable.isRecord(child) |
| 521 | and isNone(BVariable.getStartAttribute(child)) then | ||
| 522 | 54 | Pointer.update(child, BVariable.setStartAttribute(var, Expression.recordElement(ComponentRef.firstName(var.name), exp))); | |
| 523 | end if; | ||
| 524 | end for; | ||
| 525 | end if; | ||
| 526 | end setAuxStartValue; | ||
| 527 | |||
| 528 | function isStartUsefulFunction | ||
| 529 | "builtin functions (sin, abs, ...) are cheap to iterate on and not worth a start equation" | ||
| 530 | input Function fn; | ||
| 531 | output Boolean b = not Function.isBuiltin(fn) and isStartSafeFunction(fn, 0); | ||
| 532 | end isStartUsefulFunction; | ||
| 533 | |||
| 534 | function isStartSafeFunction | ||
| 535 | "A function can be evaluated at the start values of its arguments if it can not fail: no asserts or terminates, | ||
| 536 | not impure or external, and all functions it calls are safe as well." | ||
| 537 | input Function fn; | ||
| 538 | input Integer depth; | ||
| 539 | output Boolean safe; | ||
| 540 | protected | ||
| 541 | list<Statement> body; | ||
| 542 | Pointer<Boolean> unsafe; | ||
| 543 | algorithm | ||
| 544 |
2/4✓ Branch 1 taken 412 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 412 times.
✗ Branch 5 not taken.
|
412 | if Function.isBuiltin(fn) or Function.isDefaultRecordConstructor(fn) then |
| 545 | safe := true; | ||
| 546 | elseif depth > 4 or Function.isExternal(fn) or Function.isImpure(fn) then | ||
| 547 | safe := false; | ||
| 548 | else | ||
| 549 | 400 | body := Function.getBody(fn); | |
| 550 |
2/2✓ Branch 3 taken 397 times.
✓ Branch 4 taken 3 times.
|
797 | unsafe := Pointer.create(List.any(body, function Statement.contains(fn = isUnsafeStatement))); |
| 551 |
2/2✓ Branch 1 taken 397 times.
✓ Branch 2 taken 3 times.
|
400 | if not Pointer.access(unsafe) then |
| 552 | 397 | Statement.applyExpList(body, function markUnsafeCalls(unsafe = unsafe, depth = depth)); | |
| 553 | end if; | ||
| 554 | 400 | safe := not Pointer.access(unsafe); | |
| 555 | end if; | ||
| 556 | end isStartSafeFunction; | ||
| 557 | |||
| 558 | function isUnsafeStatement | ||
| 559 | input Statement stmt; | ||
| 560 | output Boolean b; | ||
| 561 | algorithm | ||
| 562 | b := match stmt | ||
| 563 | case Statement.ASSERT() then true; | ||
| 564 | case Statement.TERMINATE() then true; | ||
| 565 | else false; | ||
| 566 | end match; | ||
| 567 | end isUnsafeStatement; | ||
| 568 | |||
| 569 | function markUnsafeCalls | ||
| 570 | input Expression exp; | ||
| 571 | input Pointer<Boolean> unsafe; | ||
| 572 | input Integer depth; | ||
| 573 | algorithm | ||
| 574 |
4/4✓ Branch 2 taken 2034 times.
✓ Branch 3 taken 1006 times.
✓ Branch 6 taken 807 times.
✓ Branch 7 taken 199 times.
|
3040 | if not Pointer.access(unsafe) and Expression.contains(exp, function isUnsafeCallExp(depth = depth)) then |
| 575 | 199 | Pointer.update(unsafe, true); | |
| 576 | end if; | ||
| 577 | end markUnsafeCalls; | ||
| 578 | |||
| 579 | function isUnsafeCallExp | ||
| 580 | input Expression exp; | ||
| 581 | input Integer depth; | ||
| 582 | output Boolean b; | ||
| 583 | algorithm | ||
| 584 | b := match exp | ||
| 585 | local | ||
| 586 | Function fn; | ||
| 587 | // the generated code asserts on divisions by zero and on the domain of sqrt and log | ||
| 588 | 102 | case Expression.BINARY(operator = Operator.OPERATOR(op = NFOperator.Op.DIV)) then not Expression.isLiteral(exp.exp2); | |
| 589 | ✗ | case Expression.BINARY(operator = Operator.OPERATOR(op = NFOperator.Op.DIV_EW)) then not Expression.isLiteral(exp.exp2); | |
| 590 | ✗ | case Expression.BINARY(operator = Operator.OPERATOR(op = NFOperator.Op.DIV_SCALAR_ARRAY)) then not Expression.isLiteral(exp.exp2); | |
| 591 | ✗ | case Expression.BINARY(operator = Operator.OPERATOR(op = NFOperator.Op.DIV_ARRAY_SCALAR)) then not Expression.isLiteral(exp.exp2); | |
| 592 | case Expression.CALL(call = Call.TYPED_CALL()) algorithm | ||
| 593 | 234 | fn := Call.typedFunction(exp.call); | |
| 594 |
2/2✓ Branch 1 taken 50 times.
✓ Branch 2 taken 184 times.
|
234 | then if Function.isBuiltin(fn) then List.contains({"sqrt", "log", "log10"}, AbsynUtil.pathLastIdent(Function.name(fn)), stringEq) |
| 595 | else not isStartSafeFunction(fn, depth + 1); | ||
| 596 | else false; | ||
| 597 | end match; | ||
| 598 | end isUnsafeCallExp; | ||
| 599 | |||
| 600 | function aliasListToString<T1, T2> | ||
| 601 | input list<tuple<T1, T2>> aux_lst; | ||
| 602 | input idToString func1; | ||
| 603 | input auxToString func2; | ||
| 604 | input String name; | ||
| 605 | output String str; | ||
| 606 | protected | ||
| 607 | list<tuple<String, String>> str_lst; | ||
| 608 | Integer max_length; | ||
| 609 | partial function idToString<T1> | ||
| 610 | input T1 t1; | ||
| 611 | output String str; | ||
| 612 | end idToString; | ||
| 613 | partial function auxToString<T2> | ||
| 614 | input T2 t2; | ||
| 615 | output String str; | ||
| 616 | end auxToString; | ||
| 617 | algorithm | ||
| 618 | ✗ | str := StringUtil.headline_3(name + " Alias"); | |
| 619 | ✗ | if listEmpty(aux_lst) then | |
| 620 | ✗ | str := str + " <no alias>\n\n"; | |
| 621 | else | ||
| 622 | ✗ | str_lst := list((func2(Util.tuple22(tpl)), func1(Util.tuple21(tpl))) for tpl in aux_lst); | |
| 623 | ✗ | max_length := max(stringLength(Util.tuple21(tpl)) for tpl in str_lst) + 3; | |
| 624 | ✗ | str := str + List.toStringCustom(str_lst, function functionAliasTplString(max_length = max_length), "", " ", "\n ", "\n\n"); | |
| 625 | end if; | ||
| 626 | end aliasListToString; | ||
| 627 | |||
| 628 | function resolveAux | ||
| 629 | input UnorderedMap<Call_Id, Call_Aux> map; | ||
| 630 | input Pointer<Integer> eq_index; | ||
| 631 | input Boolean init; | ||
| 632 | input output list<Pointer<Variable>> new_vars_disc; | ||
| 633 | input output list<Pointer<Variable>> new_vars_cont; | ||
| 634 | input output list<Pointer<Variable>> new_vars_init; | ||
| 635 | input output list<Pointer<Variable>> new_vars_recd; | ||
| 636 | input output list<Pointer<Equation>> new_eqns_disc; | ||
| 637 | input output list<Pointer<Equation>> new_eqns_cont; | ||
| 638 | input output list<Pointer<Equation>> new_eqns_init; | ||
| 639 | protected | ||
| 640 | Call_Id id; | ||
| 641 | Call_Aux aux; | ||
| 642 | Boolean disc; | ||
| 643 | Pointer<Equation> new_eqn; | ||
| 644 | list<Pointer<Variable>> new_vars; | ||
| 645 | algorithm | ||
| 646 | // create new simulation variables and corresponding equations for the function alias | ||
| 647 |
2/2✓ Branch 2 taken 982 times.
✓ Branch 3 taken 386 times.
|
1368 | for tpl in listReverse(UnorderedMap.toList(map)) loop |
| 648 | 982 | (id, aux) := tpl; | |
| 649 | // only create new var and eqn if there is not already parsed | ||
| 650 |
2/2✓ Branch 0 taken 606 times.
✓ Branch 1 taken 376 times.
|
982 | if not aux.parsed then |
| 651 | 606 | new_vars := Call_Aux.getVars(aux); | |
| 652 | disc := true; | ||
| 653 | |||
| 654 | // categorize all aux variables | ||
| 655 |
2/2✓ Branch 0 taken 607 times.
✓ Branch 1 taken 606 times.
|
1213 | for new_var in new_vars loop |
| 656 | 607 | (disc, new_vars_disc, new_vars_cont, new_vars_init, new_vars_recd) := addAuxVar(new_var, disc, new_vars_disc, new_vars_cont, new_vars_init, new_vars_recd, init); | |
| 657 | end for; | ||
| 658 | |||
| 659 | // if any of the created variables is continuous, so is the equation | ||
| 660 | 606 | new_eqn := Equation.makeAssignment(aux.replacer, id.call, eq_index, "AUX", id.iter, EquationAttributes.default(aux.kind, init)); | |
| 661 |
2/2✓ Branch 0 taken 230 times.
✓ Branch 1 taken 376 times.
|
606 | if init then |
| 662 | new_eqns_init := new_eqn :: new_eqns_init; | ||
| 663 | elseif disc then | ||
| 664 | new_eqns_disc := new_eqn :: new_eqns_disc; | ||
| 665 | else | ||
| 666 | new_eqns_cont := new_eqn :: new_eqns_cont; | ||
| 667 | end if; | ||
| 668 | |||
| 669 | 606 | aux.parsed := true; | |
| 670 | 606 | UnorderedMap.add(id, aux, map); | |
| 671 | end if; | ||
| 672 | end for; | ||
| 673 | end resolveAux; | ||
| 674 | |||
| 675 | function introduceFunctionAliasEquation | ||
| 676 | "creates auxilliary variables for all not inlineable function calls in the equation" | ||
| 677 | input output Equation eqn; | ||
| 678 | input UnorderedMap<Call_Id, Call_Aux> map; | ||
| 679 | input VariablePointers variables; | ||
| 680 | input UnorderedSet<VariablePointer> set "new iterators"; | ||
| 681 | input Pointer<Integer> aux_index; | ||
| 682 | input Pointer<Integer> eqn_index; | ||
| 683 | input Boolean init; | ||
| 684 | protected | ||
| 685 | Iterator iter; | ||
| 686 | type Depth = enumeration(FULL, CONDITION, STOP); | ||
| 687 | Depth depth; | ||
| 688 | algorithm | ||
| 689 | // inline trivial array constructors first | ||
| 690 | 4497 | eqn := Inline.inlineArrayConstructorSingle(eqn, Iterator.EMPTY(), variables, set, eqn_index); | |
| 691 | |||
| 692 | // get iterator and determine if it needs to be checked further | ||
| 693 | (iter, depth) := match eqn | ||
| 694 | local | ||
| 695 | Equation body; | ||
| 696 |
4/4✓ Branch 2 taken 268 times.
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 265 times.
|
269 | case Equation.FOR_EQUATION(body = {body}) then (eqn.iter, if Equation.isWhenEquation(Pointer.create(body)) |
| 697 | or Equation.isIfEquation(Pointer.create(body)) | ||
| 698 | then Depth.CONDITION else Depth.FULL); | ||
| 699 | case Equation.WHEN_EQUATION() then (Iterator.EMPTY(), Depth.CONDITION); | ||
| 700 | case Equation.IF_EQUATION() then (Iterator.EMPTY(), Depth.CONDITION); | ||
| 701 | case Equation.ALGORITHM() then (Iterator.EMPTY(), Depth.STOP); | ||
| 702 | else (Iterator.EMPTY(), Depth.FULL); | ||
| 703 | end match; | ||
| 704 | |||
| 705 | // do the function alias replacement | ||
| 706 |
2/2✓ Branch 0 taken 265 times.
✓ Branch 1 taken 4 times.
|
269 | if depth == Depth.FULL then |
| 707 |
2/2✓ Branch 0 taken 4053 times.
✓ Branch 1 taken 70 times.
|
8176 | eqn := Equation.map(eqn, function introduceFunctionAlias(map = map, aux_index = aux_index, iter = iter, init = init), NONE(), Expression.fakeMap); |
| 708 | elseif depth == Depth.CONDITION then | ||
| 709 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
166 | eqn := Equation.mapCondition(eqn, function introduceFunctionAlias(map = map, aux_index = aux_index, iter = iter, init = init), NONE(), Expression.fakeMap); |
| 710 | end if; | ||
| 711 | end introduceFunctionAliasEquation; | ||
| 712 | |||
| 713 | function introduceFunctionAlias | ||
| 714 | "checks if an expression is a function call and replaces it with auxilliary if not inlinable | ||
| 715 | map with Equation.map() or Expression.map() | ||
| 716 | ToDo: also exclude special functions der(), pre(), ..." | ||
| 717 | input output Expression exp; | ||
| 718 | input UnorderedMap<Call_Id, Call_Aux> map; | ||
| 719 | input Pointer<Integer> aux_index; | ||
| 720 | input Iterator iter; | ||
| 721 | input Boolean init; | ||
| 722 | protected | ||
| 723 | Iterator deep_iter; | ||
| 724 | algorithm | ||
| 725 | // add local iterators to deep recursion | ||
| 726 | deep_iter := match exp | ||
| 727 | 1395 | case Expression.CALL() then Iterator.expand(iter, exp.call); | |
| 728 | else iter; | ||
| 729 | end match; | ||
| 730 |
2/2✓ Branch 0 taken 22220 times.
✓ Branch 1 taken 6064 times.
|
50504 | exp := Expression.mapShallow(exp, function introduceFunctionAlias(map = map, aux_index = aux_index, iter = deep_iter, init = init)); |
| 731 | |||
| 732 | // use the original iterator for local analysis | ||
| 733 | exp := match exp | ||
| 734 | local | ||
| 735 | Call call; | ||
| 736 | Expression new_exp, sub_exp; | ||
| 737 | |||
| 738 | 660 | case Expression.CALL() guard(checkCallReplacement(exp.call)) then introduceAlias(exp, map, aux_index, NBVariable.FUNCTION_STR, iter, init); | |
| 739 | |||
| 740 | // create alias for array constructors as arguments to functions | ||
| 741 | case new_exp as Expression.CALL(call = call as Call.TYPED_CALL()) algorithm | ||
| 742 |
4/4✓ Branch 0 taken 944 times.
✓ Branch 1 taken 635 times.
✓ Branch 2 taken 944 times.
✓ Branch 3 taken 635 times.
|
2214 | call.arguments := list(Expression.map(arg, function introduceArrayConstructorAlias(map = map, aux_index = aux_index, iter = iter, init = init)) for arg in call.arguments); |
| 743 | 635 | new_exp.call := call; | |
| 744 | then new_exp; | ||
| 745 | |||
| 746 | // create alias for array constructors in multaries and binaries | ||
| 747 | // Note: do not map! only replace top lvl constructors | ||
| 748 | case Expression.MULTARY() algorithm | ||
| 749 |
4/4✓ Branch 0 taken 6860 times.
✓ Branch 1 taken 3772 times.
✓ Branch 2 taken 6860 times.
✓ Branch 3 taken 3772 times.
|
14404 | exp.arguments := list(introduceArrayConstructorAlias(arg, map, aux_index, iter, init) for arg in exp.arguments); |
| 750 |
4/4✓ Branch 0 taken 989 times.
✓ Branch 1 taken 3772 times.
✓ Branch 2 taken 989 times.
✓ Branch 3 taken 3772 times.
|
8533 | exp.inv_arguments := list(introduceArrayConstructorAlias(arg, map, aux_index, iter, init) for arg in exp.inv_arguments); |
| 751 | then exp; | ||
| 752 | case Expression.BINARY() algorithm | ||
| 753 | 245 | exp.exp1 := introduceArrayConstructorAlias(exp.exp1, map, aux_index, iter, init); | |
| 754 | 245 | exp.exp2 := introduceArrayConstructorAlias(exp.exp2, map, aux_index, iter, init); | |
| 755 | then exp; | ||
| 756 | |||
| 757 | // remove tuple expressions that occur when using a function only for one output | ||
| 758 | // y = fun(x)[1] where fun() has multiple outputs | ||
| 759 | // we create y = ($FUN1, $FUN2)[1] and simplify to y = $FUN1 | ||
| 760 | case Expression.TUPLE_ELEMENT(tupleExp = sub_exp as Expression.TUPLE()) algorithm | ||
| 761 | ✗ | if exp.index > listLength(sub_exp.elements) then | |
| 762 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to get subscripted tuple element: " + Expression.toString(exp)}); | |
| 763 | ✗ | fail(); | |
| 764 | else | ||
| 765 | ✗ | new_exp := listGet(sub_exp.elements, exp.index); | |
| 766 | end if; | ||
| 767 | then new_exp; | ||
| 768 | |||
| 769 | // do nothing if not function call or inlineable | ||
| 770 | else exp; | ||
| 771 | end match; | ||
| 772 | end introduceFunctionAlias; | ||
| 773 | |||
| 774 | function introduceArrayConstructorAlias | ||
| 775 | "introduces alias variables for array constructor and reduction calls" | ||
| 776 | input output Expression exp; | ||
| 777 | input UnorderedMap<Call_Id, Call_Aux> map; | ||
| 778 | input Pointer<Integer> aux_index; | ||
| 779 | input Iterator iter; | ||
| 780 | input Boolean init; | ||
| 781 | algorithm | ||
| 782 | exp := match exp | ||
| 783 | 5 | case Expression.CALL(call = Call.TYPED_ARRAY_CONSTRUCTOR()) then introduceAlias(exp, map, aux_index, NBVariable.FUNCTION_STR, iter, init); | |
| 784 | ✗ | case Expression.CALL(call = Call.TYPED_REDUCTION()) then introduceAlias(exp, map, aux_index, NBVariable.FUNCTION_STR, iter, init); | |
| 785 | else exp; | ||
| 786 | end match; | ||
| 787 | end introduceArrayConstructorAlias; | ||
| 788 | |||
| 789 | function introduceAliasCrefConditional | ||
| 790 | "introduces alias variables for crefs, only if they are in the set" | ||
| 791 | input output Expression exp; | ||
| 792 | input UnorderedSet<ComponentRef> set; | ||
| 793 | input UnorderedMap<Call_Id, Call_Aux> map; | ||
| 794 | input Pointer<Integer> aux_index; | ||
| 795 | input Iterator iter; | ||
| 796 | input Boolean init; | ||
| 797 | algorithm | ||
| 798 | exp := match exp | ||
| 799 | case Expression.CREF() guard(UnorderedSet.contains(ComponentRef.stripSubscriptsAll(exp.cref), set)) | ||
| 800 | ✗ | then introduceAlias(exp, map, aux_index, NBVariable.STATE_ALIAS_STR, iter, init); | |
| 801 | else exp; | ||
| 802 | end match; | ||
| 803 | end introduceAliasCrefConditional; | ||
| 804 | |||
| 805 | function introduceAlias | ||
| 806 | "introduces alias variables for any expression. | ||
| 807 | Extra handling for cat() and promotion() calls." | ||
| 808 | input output Expression exp; | ||
| 809 | input UnorderedMap<Call_Id, Call_Aux> map; | ||
| 810 | input Pointer<Integer> aux_index; | ||
| 811 | input String aux_name; | ||
| 812 | input Iterator iter; | ||
| 813 | input Boolean init; | ||
| 814 | protected | ||
| 815 | list<ComponentRef> names; | ||
| 816 | list<Expression> ranges; | ||
| 817 | list<Option<Iterator>> maps; | ||
| 818 | Iterator new_iter; | ||
| 819 | Call_Id id; | ||
| 820 | ComponentRef name; | ||
| 821 | Type ty; | ||
| 822 | Call_Aux aux; | ||
| 823 | Option<Call_Aux> aux_opt; | ||
| 824 | list<Expression> tpl_lst; | ||
| 825 | algorithm | ||
| 826 | // strip nested iterator for the iterators that actually occure in the function call | ||
| 827 |
2/2✓ Branch 1 taken 51 times.
✓ Branch 2 taken 794 times.
|
845 | if not Iterator.isEmpty(iter) then |
| 828 | 51 | (names, ranges, maps) := Iterator.getFrames(iter); | |
| 829 | 51 | new_iter := Iterator.fromFrames(filterFrames(exp, names, ranges, maps)); | |
| 830 | else | ||
| 831 | new_iter := iter; | ||
| 832 | end if; | ||
| 833 | |||
| 834 | // check if call id already exists in the map | ||
| 835 | 845 | id := CALL_ID(exp, new_iter); | |
| 836 | 845 | aux_opt := UnorderedMap.get(id, map); | |
| 837 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 845 times.
✓ Branch 2 taken 636 times.
✓ Branch 3 taken 209 times.
|
845 | if isSome(aux_opt) then |
| 838 | 209 | aux := Util.getOption(aux_opt); | |
| 839 | 209 | exp := aux.replacer; | |
| 840 | else | ||
| 841 | // create auxilliary variables for each cat call argument as well (needed for inline) | ||
| 842 | (exp, aux_opt) := match exp | ||
| 843 | local | ||
| 844 | Call call; | ||
| 845 | Expression arg1, arg2; | ||
| 846 | |||
| 847 | case Expression.CALL(call = call as Call.TYPED_CALL()) algorithm | ||
| 848 | () := match (Call.functionName(call), call.arguments) | ||
| 849 | case (Absyn.IDENT(name = "cat"), _) algorithm | ||
| 850 |
8/8✓ Branch 1 taken 304 times.
✓ Branch 2 taken 104 times.
✓ Branch 3 taken 304 times.
✓ Branch 4 taken 104 times.
✓ Branch 6 taken 225 times.
✓ Branch 7 taken 79 times.
✓ Branch 9 taken 178 times.
✓ Branch 10 taken 47 times.
|
512 | call.arguments := listHead(call.arguments) :: list(if Expression.isLiteral(arg) or Expression.isCref(arg) then arg |
| 851 | else introduceAlias(arg, map, aux_index, aux_name, iter, init) for arg in listRest(call.arguments)); | ||
| 852 | 104 | exp.call := call; | |
| 853 | 104 | id := CALL_ID(exp, new_iter); | |
| 854 | // double check if after replacing cat() call arguments the ID already exists | ||
| 855 | 104 | aux_opt := UnorderedMap.get(id, map); | |
| 856 | then (); | ||
| 857 | |||
| 858 | case (Absyn.IDENT(name = "promote"), {arg1, arg2}) algorithm | ||
| 859 |
2/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
4 | call.arguments := {if Expression.isLiteral(arg1) or Expression.isCref(arg1) then arg1 |
| 860 | else introduceAlias(arg1, map, aux_index, aux_name, iter, init), arg2}; | ||
| 861 | 2 | exp.call := call; | |
| 862 | 2 | id := CALL_ID(exp, new_iter); | |
| 863 | // double check if after replacing promote() call arguments the ID already exists | ||
| 864 | 2 | aux_opt := UnorderedMap.get(id, map); | |
| 865 | then (); | ||
| 866 | |||
| 867 | else (); | ||
| 868 | end match; | ||
| 869 | then (exp, aux_opt); | ||
| 870 | else (exp, aux_opt); | ||
| 871 | end match; | ||
| 872 | |||
| 873 | // for initial systems create parameters, otherwise use type to determine variable kind | ||
| 874 | 636 | ty := Expression.typeOf(exp); | |
| 875 | exp := match (aux_opt, ty) | ||
| 876 | 30 | case (SOME(aux), _) then aux.replacer; | |
| 877 | case (_, Type.TUPLE()) algorithm | ||
| 878 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 time.
|
3 | names := list(Call_Aux.createName(sub_ty, new_iter, aux_index, aux_name, init) for sub_ty in ty.types); |
| 879 |
5/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
|
3 | tpl_lst := list(if ComponentRef.size(cref, true) == 0 then Expression.fromCref(ComponentRef.WILD()) else Expression.fromCref(cref) for cref in names); |
| 880 | 1 | then Expression.TUPLE(ty, tpl_lst); | |
| 881 | else algorithm | ||
| 882 | 605 | name := Call_Aux.createName(ty, new_iter, aux_index, aux_name, init); | |
| 883 | 605 | then Expression.fromCref(name); | |
| 884 | end match; | ||
| 885 | |||
| 886 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 636 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 606 times.
|
636 | if isNone(aux_opt) then |
| 887 | // create auxilliary and add to map if there was none before | ||
| 888 |
2/2✓ Branch 1 taken 600 times.
✓ Branch 2 taken 6 times.
|
1206 | aux := CALL_AUX(exp, if Type.isDiscrete(ty) then EquationKind.DISCRETE else EquationKind.CONTINUOUS, false); |
| 889 | 606 | UnorderedMap.add(id, aux, map); | |
| 890 | end if; | ||
| 891 | end if; | ||
| 892 | end introduceAlias; | ||
| 893 | |||
| 894 | function checkCallReplacement | ||
| 895 | "returns true if the call should be replaced" | ||
| 896 | input Call call; | ||
| 897 | output Boolean b; | ||
| 898 | protected | ||
| 899 | Function fn = Call.typedFunction(call); | ||
| 900 | algorithm | ||
| 901 |
6/6✓ Branch 1 taken 1272 times.
✓ Branch 2 taken 123 times.
✓ Branch 4 taken 832 times.
✓ Branch 5 taken 440 times.
✓ Branch 7 taken 537 times.
✓ Branch 8 taken 295 times.
|
1395 | b := forceReplacement(fn) or not (Function.isSpecialBuiltin(fn) or replaceException(fn)); |
| 902 | end checkCallReplacement; | ||
| 903 | |||
| 904 | function forceReplacement | ||
| 905 | "returns true if the call has to be force replaced without exception" | ||
| 906 | input Function fn; | ||
| 907 | output Boolean b; | ||
| 908 | algorithm | ||
| 909 | b := match AbsynUtil.pathFirstIdent(Function.nameConsiderBuiltin(fn)) | ||
| 910 | case "cat" then true; | ||
| 911 | case "terminal" then true; | ||
| 912 | else false; | ||
| 913 | end match; | ||
| 914 | end forceReplacement; | ||
| 915 | |||
| 916 | function replaceException | ||
| 917 | "returns true if this call should not be replaced" | ||
| 918 | input Function fn; | ||
| 919 | output Boolean b; | ||
| 920 | protected | ||
| 921 | Absyn.Path path; | ||
| 922 | algorithm | ||
| 923 | // do not replace record constructors | ||
| 924 |
7/8✓ Branch 1 taken 832 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 827 times.
✓ Branch 5 taken 5 times.
✓ Branch 7 taken 812 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 6 times.
✓ Branch 10 taken 806 times.
|
832 | if Function.isDefaultRecordConstructor(fn) |
| 925 | or Function.isNonDefaultRecordConstructor(fn) | ||
| 926 | // do not replace impure functions | ||
| 927 | or Function.isImpure(fn) | ||
| 928 | // do not replace functions with no output | ||
| 929 | or listEmpty(fn.outputs) then | ||
| 930 | b := true; | ||
| 931 | 26 | return; | |
| 932 | end if; | ||
| 933 |
2/2✓ Branch 1 taken 532 times.
✓ Branch 2 taken 274 times.
|
806 | if not Function.isBuiltin(fn) then |
| 934 | b := false; | ||
| 935 | else | ||
| 936 | 532 | path := Function.nameConsiderBuiltin(fn); | |
| 937 |
1/2✓ Branch 1 taken 532 times.
✗ Branch 2 not taken.
|
532 | if not AbsynUtil.pathIsIdent(path) then |
| 938 | b := false; | ||
| 939 | else | ||
| 940 | b := match AbsynUtil.pathFirstIdent(path) | ||
| 941 | // functions that trigger events, an alias would lose a surrounding noEvent() | ||
| 942 | case "integer" then true; | ||
| 943 | case "floor" then true; | ||
| 944 | case "ceil" then true; | ||
| 945 | case "div" then true; | ||
| 946 | case "mod" then true; | ||
| 947 | case "rem" then true; | ||
| 948 | case "String" then true; | ||
| 949 | case "$OMC$PositiveMax" then true; | ||
| 950 | case "$OMC$inStreamDiv" then true; | ||
| 951 | else false; | ||
| 952 | end match; | ||
| 953 | end if; | ||
| 954 | end if; | ||
| 955 | end replaceException; | ||
| 956 | |||
| 957 | function filterFrames | ||
| 958 | "filters the list of frames for all iterators that occure in exp" | ||
| 959 | input Expression exp; | ||
| 960 | input list<ComponentRef> names; | ||
| 961 | input list<Expression> ranges; | ||
| 962 | input list<Option<Iterator>> maps; | ||
| 963 | output list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 964 | protected | ||
| 965 | type FrameTuple = tuple<Expression, Option<Iterator>>; | ||
| 966 | UnorderedMap<ComponentRef, FrameTuple> frame_map = UnorderedMap.new<FrameTuple>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 967 | UnorderedMap<ComponentRef, FrameTuple> new_map = UnorderedMap.new<FrameTuple>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 968 | UnorderedMap<ComponentRef, ComponentRef> sub_map = UnorderedMap.new<ComponentRef>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 969 | |||
| 970 | function collectFrames | ||
| 971 | input output Expression exp; | ||
| 972 | input UnorderedMap<ComponentRef, FrameTuple> frame_map; | ||
| 973 | input UnorderedMap<ComponentRef, FrameTuple> new_map; | ||
| 974 | input UnorderedMap<ComponentRef, ComponentRef> sub_map; | ||
| 975 | algorithm | ||
| 976 | () := match exp | ||
| 977 | local | ||
| 978 | FrameTuple frame_tpl; | ||
| 979 | ComponentRef parent; | ||
| 980 | |||
| 981 | // check if the cref is an iterator | ||
| 982 | case Expression.CREF() algorithm | ||
| 983 | () := match UnorderedMap.get(exp.cref, frame_map) | ||
| 984 | case SOME(frame_tpl) algorithm | ||
| 985 | // add to new map | ||
| 986 | 59 | UnorderedMap.add(exp.cref, frame_tpl, new_map); | |
| 987 | then (); | ||
| 988 | |||
| 989 | // if not, check if it has a parent in the sub_map | ||
| 990 | else algorithm | ||
| 991 | () := match UnorderedMap.get(exp.cref, sub_map) | ||
| 992 | // check if the parent is an iterator (should always be) | ||
| 993 | case SOME(parent) algorithm | ||
| 994 | () := match UnorderedMap.get(parent, frame_map) | ||
| 995 | case SOME(frame_tpl) algorithm | ||
| 996 | // add parent to new map | ||
| 997 | ✗ | UnorderedMap.add(parent, frame_tpl, new_map); | |
| 998 | then (); | ||
| 999 | else (); | ||
| 1000 | end match; | ||
| 1001 | then (); | ||
| 1002 | else (); | ||
| 1003 | end match; | ||
| 1004 | then (); | ||
| 1005 | end match; | ||
| 1006 | then (); | ||
| 1007 | else (); | ||
| 1008 | end match; | ||
| 1009 | end collectFrames; | ||
| 1010 | |||
| 1011 | ComponentRef name; | ||
| 1012 | Expression range; | ||
| 1013 | Option<Iterator> map; | ||
| 1014 | list<ComponentRef> n = names, local_n; | ||
| 1015 | list<Expression> r = ranges; | ||
| 1016 | list<Option<Iterator>> m = maps; | ||
| 1017 | algorithm | ||
| 1018 | // iterate over all iterators | ||
| 1019 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 51 times.
|
115 | while not listEmpty(n) loop |
| 1020 | // getting the name, range and map | ||
| 1021 | 64 | name :: n := n; | |
| 1022 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | range :: r := r; |
| 1023 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | map :: m := m; |
| 1024 | // add the name range and map to the frame_map | ||
| 1025 | 64 | UnorderedMap.add(name, (range, map), frame_map); | |
| 1026 | // if there is a sub map add it to the sub_map... mapper | ||
| 1027 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
64 | if isSome(map) then |
| 1028 | ✗ | (local_n, _, _) := Iterator.getFrames(Util.getOption(map)); | |
| 1029 | ✗ | for cref in local_n loop | |
| 1030 | ✗ | UnorderedMap.add(cref, name, sub_map); | |
| 1031 | end for; | ||
| 1032 | end if; | ||
| 1033 | end while; | ||
| 1034 | |||
| 1035 | 51 | Expression.map(exp, function collectFrames(frame_map = frame_map, new_map = new_map, sub_map = sub_map)); | |
| 1036 | 51 | n := UnorderedMap.keyList(new_map); | |
| 1037 | 51 | (r, m) := List.unzip(UnorderedMap.valueList(new_map)); | |
| 1038 | 51 | frames := List.zip3(n, r, m); | |
| 1039 | end filterFrames; | ||
| 1040 | |||
| 1041 | function addAuxVar | ||
| 1042 | "add the aux var to the correct list and potentially resolve records properly" | ||
| 1043 | input Pointer<Variable> new_var; | ||
| 1044 | input output Boolean disc; | ||
| 1045 | input output list<Pointer<Variable>> new_vars_disc; | ||
| 1046 | input output list<Pointer<Variable>> new_vars_cont; | ||
| 1047 | input output list<Pointer<Variable>> new_vars_init; | ||
| 1048 | input output list<Pointer<Variable>> new_vars_recd; | ||
| 1049 | input Boolean init; | ||
| 1050 | protected | ||
| 1051 | list<Variable> children; | ||
| 1052 | algorithm | ||
| 1053 |
2/2✓ Branch 1 taken 48 times.
✓ Branch 2 taken 676 times.
|
724 | if BVariable.isRecord(new_var) then |
| 1054 | 48 | new_vars_recd := new_var :: new_vars_recd; | |
| 1055 | // create record element variables (ignore first output since its the variable itself) | ||
| 1056 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
|
48 | _ :: children := Variable.expandChildren(Pointer.access(new_var), addDimensions = false); |
| 1057 |
2/2✓ Branch 0 taken 117 times.
✓ Branch 1 taken 48 times.
|
165 | for child in children loop |
| 1058 | 117 | (disc, new_vars_disc, new_vars_cont, new_vars_init, new_vars_recd) := addAuxVar(BVariable.makeVarPtr(child, child.name), disc, new_vars_disc, new_vars_cont, new_vars_init, new_vars_recd, init); | |
| 1059 | end for; | ||
| 1060 | elseif init then | ||
| 1061 | 464 | new_vars_init := BVariable.setFixed(new_var, false) :: new_vars_init; | |
| 1062 | elseif BVariable.isContinuous(new_var, false) then | ||
| 1063 | disc := false; | ||
| 1064 | 441 | new_vars_cont := new_var :: new_vars_cont; | |
| 1065 | else | ||
| 1066 | 3 | new_vars_disc := new_var :: new_vars_disc; | |
| 1067 | end if; | ||
| 1068 | end addAuxVar; | ||
| 1069 | |||
| 1070 | function addClockedAlias | ||
| 1071 | "add clocked alias equations and variables | ||
| 1072 | Note: inferred clocks are handled as unknowns for partitioning" | ||
| 1073 | input EquationPointers equations; | ||
| 1074 | input Pointer<Integer> eqn_idx; | ||
| 1075 | output list<Pointer<Equation>> clock_eqns = {}; | ||
| 1076 | output list<Pointer<Equation>> infer_eqns = {}; | ||
| 1077 | output list<Pointer<Variable>> clock_vars; | ||
| 1078 | output list<Pointer<Variable>> infer_vars; | ||
| 1079 | output UnorderedMap<BClock, ComponentRef> clck_coll = UnorderedMap.new<ComponentRef>(BClock.hash, BClock.isEqual); | ||
| 1080 | output UnorderedMap<BClock, ComponentRef> infr_coll = UnorderedMap.new<ComponentRef>(BClock.hash, BClock.isEqual); | ||
| 1081 | protected | ||
| 1082 | Pointer<list<Pointer<Variable>>> new_clocks = Pointer.create({}); | ||
| 1083 | Pointer<list<Pointer<Variable>>> new_infers = Pointer.create({}); | ||
| 1084 | Pointer<Integer> idx = Pointer.create(0); | ||
| 1085 | BClock clock; | ||
| 1086 | ComponentRef clock_name; | ||
| 1087 | algorithm | ||
| 1088 | 193 | EquationPointers.map(equations, function Partitioning.extractClocksEqn( | |
| 1089 | clck_coll = clck_coll, infr_coll = infr_coll, new_clocks = new_clocks, new_infers = new_infers, idx = idx)); | ||
| 1090 | |||
| 1091 | // create clocks | ||
| 1092 | 193 | clock_vars := Pointer.access(new_clocks); | |
| 1093 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 193 times.
|
195 | for tpl in UnorderedMap.toList(clck_coll) loop |
| 1094 | 2 | (clock, clock_name) := tpl; | |
| 1095 | 2 | clock_eqns := Equation.makeAssignment(Expression.fromCref(clock_name), BClock.toExp(clock), eqn_idx, "AUX", Iterator.EMPTY(), EquationAttributes.default(EquationKind.CLOCKED, false)) :: clock_eqns; | |
| 1096 | end for; | ||
| 1097 | |||
| 1098 | // create inferred clocks | ||
| 1099 | 193 | infer_vars := Pointer.access(new_infers); | |
| 1100 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 193 times.
|
193 | for tpl in UnorderedMap.toList(infr_coll) loop |
| 1101 | ✗ | (clock, clock_name) := tpl; | |
| 1102 | ✗ | infer_eqns := Equation.makeAssignment(Expression.fromCref(clock_name), BClock.toExp(clock), eqn_idx, "AUX", Iterator.EMPTY(), EquationAttributes.default(EquationKind.CLOCKED, false)) :: infer_eqns; | |
| 1103 | end for; | ||
| 1104 | end addClockedAlias; | ||
| 1105 | |||
| 1106 | // type for slice collection | ||
| 1107 | type Indices = UnorderedSet<Integer>; | ||
| 1108 | |||
| 1109 | function collectSlicedStatesAliasEquation | ||
| 1110 | "helper function to map equations for sliced state collection" | ||
| 1111 | input output Equation eqn; | ||
| 1112 | input UnorderedMap<ComponentRef,Indices> map; | ||
| 1113 | protected | ||
| 1114 | Iterator iter = Equation.getForIterator(eqn); | ||
| 1115 | algorithm | ||
| 1116 | 2934 | Equation.map(eqn, function collectSlicedStatesAlias(iter = iter, map = map), NONE(), Expression.fakeMap); | |
| 1117 | end collectSlicedStatesAliasEquation; | ||
| 1118 | |||
| 1119 | function collectSlicedStatesAlias | ||
| 1120 | "check cref in a der() call for full access of the variable. | ||
| 1121 | if its not fully accessing the variable, add it to the slice map." | ||
| 1122 | input output Expression exp; | ||
| 1123 | input Iterator iter; | ||
| 1124 | input UnorderedMap<ComponentRef,Indices> map; | ||
| 1125 | algorithm | ||
| 1126 | exp := match exp | ||
| 1127 | local | ||
| 1128 | Integer iter_size, cref_size, var_size; | ||
| 1129 | Expression arg; | ||
| 1130 | UnorderedSet<ComponentRef> call_crefs; | ||
| 1131 | ComponentRef stripped_cref; | ||
| 1132 | UnorderedSet<Integer> indices; | ||
| 1133 | list<ComponentRef> names; | ||
| 1134 | list<Expression> ranges; | ||
| 1135 | list<Option<Iterator>> maps; | ||
| 1136 | |||
| 1137 | // derivative | ||
| 1138 | case Expression.CALL(call = Call.TYPED_CALL(fn = Function.FUNCTION(path = Absyn.IDENT(name = "der")), arguments = {arg})) algorithm | ||
| 1139 | // get the iterator size | ||
| 1140 | 185 | iter_size := Iterator.size(iter, true); | |
| 1141 | // collect all crefs in the call | ||
| 1142 | 185 | call_crefs := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 1143 | 185 | Slice.filterExp(arg, function Slice.getContinuous(init = false), call_crefs); | |
| 1144 |
2/2✓ Branch 1 taken 183 times.
✓ Branch 2 taken 185 times.
|
368 | for cref in UnorderedSet.toList(call_crefs) loop |
| 1145 | 183 | cref_size := Type.sizeOf(ComponentRef.getSubscriptedType(cref), true); | |
| 1146 | 183 | var_size := BVariable.size(BVariable.getVarPointer(cref, sourceInfo()), true); | |
| 1147 | // if the cref does not represent the full variable it has to be collected as it might cause a sliced state | ||
| 1148 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 151 times.
|
183 | if var_size <> cref_size * iter_size then |
| 1149 | 32 | stripped_cref := ComponentRef.stripSubscriptsAll(cref); | |
| 1150 | 32 | indices := UnorderedMap.getOrDefault(stripped_cref, map, UnorderedSet.new(Util.id, intEq)); | |
| 1151 | 32 | (names, ranges, maps) := Iterator.getFrames(iter); | |
| 1152 | // get all the local indices (start index = 0) and collect with potential previous indices | ||
| 1153 |
2/2✓ Branch 2 taken 146 times.
✓ Branch 3 taken 32 times.
|
178 | for index in Slice.getCrefInFrameIndicesLocal(cref, stripped_cref, List.zip3(names, ranges, maps), 0, true) loop |
| 1154 | 146 | UnorderedSet.add(index, indices); | |
| 1155 | end for; | ||
| 1156 | 32 | UnorderedMap.add(stripped_cref, indices, map); | |
| 1157 | end if; | ||
| 1158 | end for; | ||
| 1159 | then exp; | ||
| 1160 | |||
| 1161 | // array constructor, get the iterators and add them going deeper | ||
| 1162 | case Expression.CALL(call = Call.TYPED_ARRAY_CONSTRUCTOR()) algorithm | ||
| 1163 | 15 | Expression.mapShallow(exp, function collectSlicedStatesAlias(iter = Iterator.expand(iter, exp.call), map = map)); | |
| 1164 | then exp; | ||
| 1165 | case Expression.CALL(call = Call.TYPED_REDUCTION()) algorithm | ||
| 1166 | 8 | Expression.mapShallow(exp, function collectSlicedStatesAlias(iter = Iterator.expand(iter, exp.call), map = map)); | |
| 1167 | then exp; | ||
| 1168 | |||
| 1169 | // just map deeper in search for der() calls | ||
| 1170 | else algorithm | ||
| 1171 | 20886 | Expression.mapShallow(exp, function collectSlicedStatesAlias(iter = iter, map = map)); | |
| 1172 | then exp; | ||
| 1173 | end match; | ||
| 1174 | end collectSlicedStatesAlias; | ||
| 1175 | |||
| 1176 | function getSlicedStatesSet | ||
| 1177 | "takes the map of states and their sliced indices and returns the set of all states of which the indices are not covering the full state" | ||
| 1178 | input UnorderedMap<ComponentRef,Indices> map; | ||
| 1179 | output UnorderedSet<ComponentRef> set = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | ||
| 1180 | protected | ||
| 1181 | ComponentRef state; | ||
| 1182 | UnorderedSet<Integer> indices; | ||
| 1183 | algorithm | ||
| 1184 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 190 times.
|
198 | for tpl in UnorderedMap.toList(map) loop |
| 1185 | 8 | (state, indices) := tpl; | |
| 1186 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
|
8 | if BVariable.size(BVariable.getVarPointer(state, sourceInfo()), true) <> UnorderedSet.size(indices) then |
| 1187 | ✗ | UnorderedSet.add(state, set); | |
| 1188 | end if; | ||
| 1189 | end for; | ||
| 1190 | end getSlicedStatesSet; | ||
| 1191 | |||
| 1192 | function introduceSlicedStateAliasEquation | ||
| 1193 | "creates auxilliary variables for all state slices where the variable is only partially a state" | ||
| 1194 | input output Equation eqn; | ||
| 1195 | input UnorderedSet<ComponentRef> set; | ||
| 1196 | input UnorderedMap<Call_Id, Call_Aux> map; | ||
| 1197 | input Pointer<Integer> aux_index; | ||
| 1198 | protected | ||
| 1199 | Iterator iter = Equation.getForIterator(eqn); | ||
| 1200 | algorithm | ||
| 1201 | ✗ | eqn := Equation.map(eqn, function introduceSlicedStateAliasExp(set = set, map = map, iter = iter, aux_index = aux_index), NONE(), Expression.fakeMap); | |
| 1202 | end introduceSlicedStateAliasEquation; | ||
| 1203 | |||
| 1204 | function introduceSlicedStateAliasExp | ||
| 1205 | "replace component references in der() calls that have been found to be only partially states." | ||
| 1206 | input output Expression exp; | ||
| 1207 | input UnorderedSet<ComponentRef> set; | ||
| 1208 | input UnorderedMap<Call_Id, Call_Aux> map; | ||
| 1209 | input Iterator iter; | ||
| 1210 | input Pointer<Integer> aux_index; | ||
| 1211 | algorithm | ||
| 1212 | exp := match exp | ||
| 1213 | local | ||
| 1214 | Call call; | ||
| 1215 | Expression arg, new_exp; | ||
| 1216 | |||
| 1217 | case Expression.CALL(call = call as Call.TYPED_CALL(fn = Function.FUNCTION(path = Absyn.IDENT(name = "der")), arguments = {arg})) algorithm | ||
| 1218 | ✗ | call.arguments := {Expression.map(arg, function introduceAliasCrefConditional(set = set, map = map, iter = iter, aux_index = aux_index, init = false))}; | |
| 1219 | ✗ | exp.call := call; | |
| 1220 | then exp; | ||
| 1221 | |||
| 1222 | // array constructor, get the iterators and add them going deeper | ||
| 1223 | case Expression.CALL(call = Call.TYPED_ARRAY_CONSTRUCTOR()) algorithm | ||
| 1224 | ✗ | new_exp := Expression.mapShallow(exp, function introduceSlicedStateAliasExp(set = set, map = map, iter = Iterator.expand(iter, exp.call), aux_index = aux_index)); | |
| 1225 | then new_exp; | ||
| 1226 | case Expression.CALL(call = Call.TYPED_REDUCTION()) algorithm | ||
| 1227 | ✗ | new_exp := Expression.mapShallow(exp, function introduceSlicedStateAliasExp(set = set, map = map, iter = Iterator.expand(iter, exp.call), aux_index = aux_index)); | |
| 1228 | then new_exp; | ||
| 1229 | |||
| 1230 | // just map deeper in search for der() calls | ||
| 1231 | else algorithm | ||
| 1232 | ✗ | new_exp := Expression.mapShallow(exp, function introduceSlicedStateAliasExp(set = set, map = map, iter = iter, aux_index = aux_index)); | |
| 1233 | then new_exp; | ||
| 1234 | end match; | ||
| 1235 | end introduceSlicedStateAliasExp; | ||
| 1236 | |||
| 1237 | annotation(__OpenModelica_Interface="nbackend"); | ||
| 1238 | end NBFunctionAlias; | ||
| 1239 |