OMCompiler/Compiler/NBackEnd/Modules/2_Pre/NBAlias.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 NBAlias | ||
| 37 | "file: NBAlias.mo | ||
| 38 | package: NBAlias | ||
| 39 | description: This file contains the functions for the alias elimination module. | ||
| 40 | It eliminates alias variables (ToDo: and resolves simple index reduction problems). | ||
| 41 | " | ||
| 42 | |||
| 43 | // ToDo: | ||
| 44 | // 1. simple state rules (with derivative replacement) | ||
| 45 | // - state = state | ||
| 46 | // - state = alg | ||
| 47 | // - state = time | ||
| 48 | // - state = const | ||
| 49 | // 2. write rateVar() and decide if we want an auxiliary for each set | ||
| 50 | // - rateVar() --> mergeAttributes() | ||
| 51 | // 3. post causalize alias elimination | ||
| 52 | // - for the ODE | ||
| 53 | // - for jacobians/hessians (once we got hessians) | ||
| 54 | // - for strong components in general | ||
| 55 | // 4. simplify only replaced equations and remove simplify2 module | ||
| 56 | // - probably not that trivial | ||
| 57 | // - Equation mapExp function that returns true if something was replaced | ||
| 58 | // - EquationArray map function that accumulates pointers if function returns true | ||
| 59 | // - simplify all equations in pointer list | ||
| 60 | |||
| 61 | // 5. trivial solution a = b; a = -b; (or other cyclic sets) | ||
| 62 | // - take an equation from the set, get both crefs in it (a,b) | ||
| 63 | // - solve for a -> set a as known | ||
| 64 | // - solve the rest of the set with causalize | ||
| 65 | // - replacements a -> what it solves for in eq1 and apply on all eq in set | ||
| 66 | // - find equation that solves b, and solve for b. add to replacements | ||
| 67 | // - apply replacements on all eq | ||
| 68 | |||
| 69 | public | ||
| 70 | import Module = NBModule; | ||
| 71 | protected | ||
| 72 | // OF imports | ||
| 73 | import DAE; | ||
| 74 | |||
| 75 | // NF imports | ||
| 76 | import BackendExtension = NFBackendExtension; | ||
| 77 | import NFBackendExtension.{StateSelect, TearingSelect}; | ||
| 78 | import NFBackendExtension.VariableKind; | ||
| 79 | import NFBinding.Binding; | ||
| 80 | import Call = NFCall; | ||
| 81 | import ComponentRef = NFComponentRef; | ||
| 82 | import Expression = NFExpression; | ||
| 83 | import ExpressionIterator = NFExpressionIterator; | ||
| 84 | import Dimension = NFDimension; | ||
| 85 | import Subscript = NFSubscript; | ||
| 86 | import NFFunction.Function; | ||
| 87 | import NFInstNode.InstNode; | ||
| 88 | import Type = NFType; | ||
| 89 | import Operator = NFOperator; | ||
| 90 | import Variable = NFVariable; | ||
| 91 | import NFPrefixes.Variability; | ||
| 92 | |||
| 93 | // Backend imports | ||
| 94 | import BackendDAE = NBackendDAE; | ||
| 95 | import BEquation = NBEquation; | ||
| 96 | import BVariable = NBVariable; | ||
| 97 | import Causalize = NBCausalize; | ||
| 98 | import Differentiate = NBDifferentiate; | ||
| 99 | import NBDifferentiate.{DifferentiationType, DifferentiationArguments}; | ||
| 100 | import NBEquation.{Equation, EquationAttributes, EquationKind, EquationPointers, EqData, Iterator}; | ||
| 101 | import Partition = NBPartition; | ||
| 102 | import Replacements = NBReplacements; | ||
| 103 | import SimplifyExp = NFSimplifyExp; | ||
| 104 | import Solve = NBSolve; | ||
| 105 | import NBSolve.Status; | ||
| 106 | import StrongComponent = NBStrongComponent; | ||
| 107 | import Tearing = NBTearing; | ||
| 108 | import NBVariable.{VariablePointers, VariablePointer, VarData}; | ||
| 109 | import ASSC = NBASSC; | ||
| 110 | |||
| 111 | // Util imports | ||
| 112 | import MetaModelica.Dangerous; | ||
| 113 | import Slice = NBSlice; | ||
| 114 | import StringUtil; | ||
| 115 | import UnorderedMap; | ||
| 116 | import UnorderedSet; | ||
| 117 | public | ||
| 118 | |||
| 119 | // ========================================================================== | ||
| 120 | // Single Variable constants and functions | ||
| 121 | // ========================================================================== | ||
| 122 | constant Real NOMINAL_THRESHOLD = 1000.0; | ||
| 123 | |||
| 124 | function main | ||
| 125 | "Wrapper function for any alias removal function. This will be | ||
| 126 | called during simulation and gets the corresponding subfunction from | ||
| 127 | Config." | ||
| 128 | extends Module.wrapper; | ||
| 129 | input Partition.Kind kind; | ||
| 130 | protected | ||
| 131 | Module.aliasInterface func; | ||
| 132 | algorithm | ||
| 133 | 193 | func := getModule(); | |
| 134 | |||
| 135 | bdae := match bdae | ||
| 136 | local | ||
| 137 | VarData varData "Data containing variable pointers"; | ||
| 138 | EqData eqData "Data containing equation pointers"; | ||
| 139 | |||
| 140 | case BackendDAE.MAIN(varData = varData, eqData = eqData) | ||
| 141 | algorithm | ||
| 142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 193 times.
|
193 | (varData, eqData) := func(varData, eqData, kind); |
| 143 | // allways apply clock alias | ||
| 144 | 190 | (varData, eqData) := aliasClocks(varData, eqData, kind); | |
| 145 | 190 | bdae.varData := varData; | |
| 146 | 190 | bdae.eqData := eqData; | |
| 147 | then bdae; | ||
| 148 | |||
| 149 | case BackendDAE.HESSIAN(varData = varData, eqData = eqData) | ||
| 150 | algorithm | ||
| 151 | ✗ | (varData, eqData) := func(varData, eqData, kind); | |
| 152 | ✗ | bdae.varData := varData; | |
| 153 | ✗ | bdae.eqData := eqData; | |
| 154 | then bdae; | ||
| 155 | |||
| 156 | else algorithm | ||
| 157 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."}); | |
| 158 | ✗ | then fail(); | |
| 159 | end match; | ||
| 160 | end main; | ||
| 161 | |||
| 162 | function getModule | ||
| 163 | "Returns the module function that was chosen by the user." | ||
| 164 | output Module.aliasInterface func; | ||
| 165 | protected | ||
| 166 | String flag = "default"; //Flags.getConfigString(Flags.REMOVE_SIMPLE_EQUATIONS) | ||
| 167 | algorithm | ||
| 168 | func := match flag | ||
| 169 | case "default" then aliasDefault; | ||
| 170 | /* ... New alias modules have to be added here */ | ||
| 171 | else fail(); | ||
| 172 | end match; | ||
| 173 | end getModule; | ||
| 174 | |||
| 175 | protected | ||
| 176 | uniontype AliasSet "gets accumulated to find sets of alias equations and solve them" | ||
| 177 | record ALIAS_SET | ||
| 178 | list<ComponentRef> simple_variables "list of all variables in this set"; | ||
| 179 | list<Pointer<Equation>> simple_equations "list of all equations in this set"; | ||
| 180 | Option<Pointer<Equation>> const_opt "optional constant binding of one variable"; | ||
| 181 | end ALIAS_SET; | ||
| 182 | |||
| 183 | function toString | ||
| 184 | input AliasSet set; | ||
| 185 | output String str; | ||
| 186 | algorithm | ||
| 187 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 13 times.
|
16 | if isSome(set.const_opt) then |
| 188 | 3 | str := "\tConstant/Parameter Binding: " | |
| 189 | + Equation.toString(Pointer.access(Util.getOption(set.const_opt))) + "\n"; | ||
| 190 | else | ||
| 191 | str := "\t<No Constant/Parameter Binding>\n"; | ||
| 192 | end if; | ||
| 193 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
|
16 | if listEmpty(set.simple_equations) then |
| 194 | 2 | str := str + "\t###<No Set Equations>\n"; | |
| 195 | else | ||
| 196 | 14 | str := str + "\t### Set Equations:\n"; | |
| 197 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 14 times.
|
55 | for eq in set.simple_equations loop |
| 198 | 41 | str := str + Equation.toString(Pointer.access(eq), "\t") + "\n"; | |
| 199 | end for; | ||
| 200 | end if; | ||
| 201 | end toString; | ||
| 202 | end AliasSet; | ||
| 203 | |||
| 204 | constant AliasSet EMPTY_ALIAS_SET = ALIAS_SET({}, {}, NONE()); | ||
| 205 | |||
| 206 | // needed for unordered map | ||
| 207 | type SetPtr = Pointer<AliasSet>; | ||
| 208 | |||
| 209 | uniontype CrefTpl "used for findCrefs()" | ||
| 210 | record CREF_TPL | ||
| 211 | Boolean cont "false if search already resulted in non simple structure"; | ||
| 212 | Integer varCount "variable count"; | ||
| 213 | Integer paramCount "parameter/constant count"; | ||
| 214 | list<ComponentRef> cr_lst "list of found variables for replacement"; | ||
| 215 | end CREF_TPL; | ||
| 216 | end CrefTpl; | ||
| 217 | |||
| 218 | constant CrefTpl EMPTY_CREF_TPL = CREF_TPL(true, 0, 0, {}); | ||
| 219 | constant CrefTpl FAILED_CREF_TPL = CREF_TPL(false, 0, 0, {}); | ||
| 220 | |||
| 221 | function aliasDefault | ||
| 222 | "STEPS: | ||
| 223 | 1. collect alias sets (variables, equations, optional constant binding) | ||
| 224 | 2. balance sets - choose variable to keep if necessary | ||
| 225 | 3. match/sort set (linear w.r.t. unknowns since all equations contain two crefs at max and are simple/linear) | ||
| 226 | 4. apply replacements | ||
| 227 | 5. save replacements in bindings of alias variables | ||
| 228 | " | ||
| 229 | extends Module.aliasInterface; | ||
| 230 | algorithm | ||
| 231 | (varData, eqData) := match (varData, eqData) | ||
| 232 | local | ||
| 233 | UnorderedMap<ComponentRef, Expression> replacements; | ||
| 234 | UnorderedSet<VariablePointer> new_iters = UnorderedSet.new(BVariable.hash, BVariable.equalName); | ||
| 235 | EquationPointers newEquations; | ||
| 236 | list<Pointer<Variable>> alias_vars, const_vars, non_trivial_alias; | ||
| 237 | list<Pointer<Equation>> non_trivial_eqs, auxEquations; | ||
| 238 | |||
| 239 | case (BVariable.VAR_DATA_SIM(), BEquation.EQ_DATA_SIM()) | ||
| 240 | algorithm | ||
| 241 | // ----------------------------------- | ||
| 242 | // 1. 2. 3. | ||
| 243 | // ----------------------------------- | ||
| 244 | 193 | (replacements, newEquations) := aliasCausalize(varData.unknowns, eqData.simulation, kind, eqData.uniqueIndex, "Simulation"); | |
| 245 | 190 | (replacements, auxEquations) := checkReplacements(replacements, eqData); | |
| 246 | |||
| 247 | // ----------------------------------- | ||
| 248 | // 4. apply replacements | ||
| 249 | // 5. save replacements in bindings of alias variables | ||
| 250 | // ----------------------------------- | ||
| 251 | 190 | (eqData, varData) := Replacements.applySimple(eqData, varData, replacements); | |
| 252 |
4/4✓ Branch 1 taken 2029 times.
✓ Branch 2 taken 190 times.
✓ Branch 3 taken 2029 times.
✓ Branch 4 taken 190 times.
|
2219 | alias_vars := list(BVariable.getVarPointer(cref, sourceInfo()) for cref in UnorderedMap.keyList(replacements)); |
| 253 | |||
| 254 | // update record variability and flatten to record children | ||
| 255 |
2/2✓ Branch 0 taken 2029 times.
✓ Branch 1 taken 190 times.
|
2219 | for var in alias_vars loop |
| 256 | 2029 | BVariable.setRecordVariability(var, NFPrefixes.Variability.PARAMETER); | |
| 257 | end for; | ||
| 258 |
4/4✓ Branch 0 taken 2029 times.
✓ Branch 1 taken 190 times.
✓ Branch 2 taken 2029 times.
✓ Branch 3 taken 190 times.
|
2219 | alias_vars := List.flatten(list(BVariable.getRecordChildrenOrSelf(var) for var in alias_vars)); |
| 259 | |||
| 260 | // save new equations and compress affected arrays(some might have been removed) | ||
| 261 | 190 | eqData.simulation := EquationPointers.compress(newEquations); | |
| 262 | // aliases between slices of arrays are kept as equations, use their start values anyway | ||
| 263 | 190 | propagateSliceAliasStarts(eqData.simulation); | |
| 264 | 190 | eqData.equations := EquationPointers.compress(eqData.equations); | |
| 265 | 190 | eqData.continuous := EquationPointers.compress(eqData.continuous); | |
| 266 | 190 | eqData.discretes := EquationPointers.compress(eqData.discretes); | |
| 267 | |||
| 268 | // remove alias vars from all relevant arrays | ||
| 269 | 190 | varData.unknowns := VariablePointers.removeList(alias_vars, varData.unknowns); | |
| 270 | 190 | varData.algebraics := VariablePointers.removeList(alias_vars, varData.algebraics); | |
| 271 | 190 | varData.states := VariablePointers.removeList(alias_vars, varData.states); | |
| 272 | 190 | varData.discretes := VariablePointers.removeList(alias_vars, varData.discretes); | |
| 273 | 190 | varData.clocks := VariablePointers.removeList(alias_vars, varData.clocks); | |
| 274 | 190 | varData.initials := VariablePointers.removeList(alias_vars, varData.initials); | |
| 275 | |||
| 276 | // categorize alias vars and sort them to the correct arrays | ||
| 277 | 190 | (non_trivial_alias, alias_vars) := List.splitOnTrue(alias_vars, BVariable.hasNonTrivialAliasBinding); | |
| 278 | |||
| 279 | // only remove trivial alias vars from the array of all variables | ||
| 280 | 190 | varData.variables := VariablePointers.removeList(alias_vars, varData.variables); | |
| 281 | |||
| 282 | // split off constant alias | ||
| 283 | // update constant start values and add to parameters | ||
| 284 | // otherwise they would not show in the result file | ||
| 285 | 190 | (const_vars, alias_vars) := List.splitOnTrue(alias_vars, BVariable.hasConstOrParamAliasBinding); | |
| 286 |
2/2✓ Branch 0 taken 656 times.
✓ Branch 1 taken 190 times.
|
846 | for var in const_vars loop |
| 287 | 656 | BVariable.setVarKind(var, VariableKind.PARAMETER(NONE())); | |
| 288 | 656 | BVariable.setBindingAsStartAndFix(var, true); | |
| 289 | end for; | ||
| 290 | 190 | varData.parameters := VariablePointers.addList(const_vars, varData.parameters); | |
| 291 | 190 | varData.knowns := VariablePointers.addList(const_vars, varData.knowns); | |
| 292 | |||
| 293 | // add only the actual 1/-1 alias vars to alias vars. | ||
| 294 | 190 | varData.aliasVars := VariablePointers.addList(alias_vars, varData.aliasVars); | |
| 295 | 190 | varData.nonTrivialAlias := VariablePointers.addList(non_trivial_alias, varData.nonTrivialAlias); | |
| 296 | |||
| 297 | // add non trivial alias to removed | ||
| 298 |
4/4✓ Branch 0 taken 73 times.
✓ Branch 1 taken 190 times.
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 190 times.
|
263 | non_trivial_eqs := list(Equation.generateBindingEquation(var, eqData.uniqueIndex, false, new_iters) for var in non_trivial_alias); |
| 299 | 190 | eqData.removed := EquationPointers.addList(non_trivial_eqs, eqData.removed); | |
| 300 | // add all new iterators | ||
| 301 | 190 | then (VarData.addTypedList(varData, UnorderedSet.toList(new_iters), NBVariable.VarData.VarType.ITERATOR), EqData.addUntypedList(eqData, auxEquations, false)); | |
| 302 | |||
| 303 | else algorithm | ||
| 304 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."}); | |
| 305 | ✗ | then fail(); | |
| 306 | end match; | ||
| 307 | end aliasDefault; | ||
| 308 | |||
| 309 | type ElementStarts = UnorderedMap<Integer, Expression> "start values of array elements by flat index"; | ||
| 310 | |||
| 311 | function propagateSliceAliasStarts | ||
| 312 | "Alias for-equations between slices of arrays (e.g. a[i].x = b[i].y[1]) can not be | ||
| 313 | removed, since only full arrays are replaced. Like for removed aliases, a variable without | ||
| 314 | start value gets the literal start values of its alias elements, the other elements keep | ||
| 315 | the default start value zero." | ||
| 316 | input EquationPointers equations; | ||
| 317 | protected | ||
| 318 | UnorderedMap<ComponentRef, UnorderedMap<Integer, Expression>> starts; | ||
| 319 | Pointer<Variable> var_ptr; | ||
| 320 | Variable var; | ||
| 321 | Type ty; | ||
| 322 | list<Integer> sizes; | ||
| 323 | array<Expression> elements; | ||
| 324 | algorithm | ||
| 325 | 190 | starts := UnorderedMap.new<ElementStarts>(ComponentRef.hash, ComponentRef.isEqual); | |
| 326 | 190 | EquationPointers.map(equations, function collectSliceAliasStarts(starts = starts)); | |
| 327 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 190 times.
|
191 | for tpl in UnorderedMap.toList(starts) loop |
| 328 | 1 | var_ptr := BVariable.getVarPointer(Util.tuple21(tpl), sourceInfo()); | |
| 329 | 1 | var := Pointer.access(var_ptr); | |
| 330 | 1 | ty := Variable.typeOf(var); | |
| 331 |
4/4✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
|
2 | sizes := list(Dimension.size(dim) for dim in Type.arrayDims(ty)); |
| 332 | 1 | elements := arrayCreate(List.fold(sizes, intMul, 1), Expression.makeZero(Type.arrayElementType(ty))); | |
| 333 |
2/2✓ Branch 2 taken 9 times.
✓ Branch 3 taken 1 time.
|
10 | for elem in UnorderedMap.toList(Util.tuple22(tpl)) loop |
| 334 | 9 | arrayUpdate(elements, Util.tuple21(elem) + 1, Util.tuple22(elem)); | |
| 335 | end for; | ||
| 336 | 1 | Pointer.update(var_ptr, BVariable.setStartAttribute(var, reshapeStart(elements, sizes, Type.arrayElementType(ty), 0), true)); | |
| 337 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
|
1 | if Flags.isSet(Flags.DUMP_REPL) then |
| 338 | ✗ | print("[propagateSliceAliasStarts] start of " + ComponentRef.toString(Util.tuple21(tpl)) + ": " | |
| 339 | + Expression.toString(Util.getOption(BVariable.getStartAttribute(var_ptr))) + "\n"); | ||
| 340 | end if; | ||
| 341 | end for; | ||
| 342 | end propagateSliceAliasStarts; | ||
| 343 | |||
| 344 | function collectSliceAliasStarts | ||
| 345 | input output Equation eqn; | ||
| 346 | input UnorderedMap<ComponentRef, UnorderedMap<Integer, Expression>> starts; | ||
| 347 | protected | ||
| 348 | constant Integer max_size = 100000; | ||
| 349 | ComponentRef cref1, cref2, target, source; | ||
| 350 | Pointer<Variable> var1, var2; | ||
| 351 | list<ComponentRef> names; | ||
| 352 | list<Expression> ranges; | ||
| 353 | list<Option<Iterator>> maps; | ||
| 354 | list<list<Integer>> values = {{}}; | ||
| 355 | Integer start, step, stop; | ||
| 356 | UnorderedMap<ComponentRef, Expression> repl; | ||
| 357 | UnorderedMap<Integer, Expression> elem_starts; | ||
| 358 | Expression start_exp, elem_exp; | ||
| 359 | Option<Integer> index; | ||
| 360 | list<tuple<Integer, Expression>> elems = {}; | ||
| 361 | algorithm | ||
| 362 | () := match eqn | ||
| 363 | case Equation.FOR_EQUATION(body = {Equation.SCALAR_EQUATION(lhs = Expression.CREF(cref = cref1), rhs = Expression.CREF(cref = cref2))}) algorithm | ||
| 364 | 45 | var1 := BVariable.getVarPointer(cref1, sourceInfo()); | |
| 365 | 45 | var2 := BVariable.getVarPointer(cref2, sourceInfo()); | |
| 366 |
5/8✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 6 times.
✓ Branch 10 taken 39 times.
✗ Branch 11 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 39 times.
|
45 | if BVariable.isParamOrConst(var1) or BVariable.isParamOrConst(var2) |
| 367 | or not Type.isReal(Type.arrayElementType(Variable.typeOf(Pointer.access(var1)))) | ||
| 368 | or not Type.isReal(Type.arrayElementType(Variable.typeOf(Pointer.access(var2)))) then | ||
| 369 | 6 | return; | |
| 370 | end if; | ||
| 371 | // exactly one of them has a start value | ||
| 372 | (target, source) := match (BVariable.getStartAttribute(var1), BVariable.getStartAttribute(var2)) | ||
| 373 | case (NONE(), SOME(_)) then (cref1, cref2); | ||
| 374 | case (SOME(_), NONE()) then (cref2, cref1); | ||
| 375 | 35 | else algorithm return; then (cref1, cref2); | |
| 376 | end match; | ||
| 377 |
2/4✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
4 | SOME(start_exp) := BVariable.getStartAttribute(BVariable.getVarPointer(source, sourceInfo())); |
| 378 | |||
| 379 | // all combinations of the iterator values (only literal ranges) | ||
| 380 | 4 | (names, ranges, maps) := Iterator.getFrames(eqn.iter); | |
| 381 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 time.
|
5 | for tpl in List.zip3(names, ranges, maps) loop |
| 382 | () := match tpl | ||
| 383 | case (_, Expression.RANGE(), NONE()) guard(Expression.isLiteral(Util.tuple32(tpl))) algorithm | ||
| 384 | 1 | (start, step, stop) := Expression.getIntegerRange(Util.tuple32(tpl), false); | |
| 385 |
8/8✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 1 time.
|
11 | values := List.flatten(list(list(v :: vs for v in List.intRange3(start, step, stop)) for vs in values)); |
| 386 | then (); | ||
| 387 | 3 | else algorithm return; then (); | |
| 388 | end match; | ||
| 389 | end for; | ||
| 390 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
1 | if listLength(values) > max_size then return; end if; |
| 391 | |||
| 392 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 time.
|
10 | for vs in values loop |
| 393 |
4/4✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 9 times.
|
18 | repl := UnorderedMap.fromLists(names, list(Expression.INTEGER(v) for v in listReverse(vs)), ComponentRef.hash, ComponentRef.isEqual); |
| 394 | // start value of the source element | ||
| 395 | 9 | elem_exp := SimplifyExp.simplify(Expression.map(Expression.fromCref(source), function Replacements.applySimpleExp(replacements = repl))); | |
| 396 | // the start value can have less dimensions than the variable, e.g. {1.0 for i in 1:2} | ||
| 397 | // for each start = 1.0 of x[2, 3] | ||
| 398 | elem_exp := match elem_exp | ||
| 399 | case Expression.CREF() guard(listLength(ComponentRef.subscriptsAllFlat(elem_exp.cref)) <= Type.dimensionCount(Expression.typeOf(start_exp))) | ||
| 400 | 9 | then SimplifyExp.simplify(Expression.applySubscripts(ComponentRef.subscriptsAllFlat(elem_exp.cref), start_exp, true)); | |
| 401 | else Expression.EMPTY(Type.UNKNOWN()); | ||
| 402 | end match; | ||
| 403 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
|
9 | if not Expression.isLiteral(elem_exp) then return; end if; |
| 404 | // flat index of the target element | ||
| 405 | 9 | index := flatIndex(SimplifyExp.simplify(Expression.map(Expression.fromCref(target), function Replacements.applySimpleExp(replacements = repl)))); | |
| 406 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
9 | if isNone(index) then return; end if; |
| 407 | 9 | elems := (Util.getOption(index), elem_exp) :: elems; | |
| 408 | end for; | ||
| 409 | |||
| 410 | 1 | target := ComponentRef.stripSubscriptsAll(target); | |
| 411 | 1 | elem_starts := UnorderedMap.getOrDefault(target, starts, UnorderedMap.new<Expression>(Util.id, intEq)); | |
| 412 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 time.
|
10 | for elem in elems loop |
| 413 | 9 | UnorderedMap.add(Util.tuple21(elem), Util.tuple22(elem), elem_starts); | |
| 414 | end for; | ||
| 415 | 1 | UnorderedMap.add(target, elem_starts, starts); | |
| 416 | then (); | ||
| 417 | else (); | ||
| 418 | end match; | ||
| 419 | end collectSliceAliasStarts; | ||
| 420 | |||
| 421 | function flatIndex | ||
| 422 | "zero based flat index of a cref with literal subscripts in its variable" | ||
| 423 | input Expression exp; | ||
| 424 | output Option<Integer> index = NONE(); | ||
| 425 | protected | ||
| 426 | list<Subscript> subs; | ||
| 427 | list<Integer> sizes; | ||
| 428 | Integer idx = 0; | ||
| 429 | algorithm | ||
| 430 | () := match exp | ||
| 431 | case Expression.CREF() algorithm | ||
| 432 | 9 | subs := ComponentRef.subscriptsAllFlat(exp.cref); | |
| 433 |
4/4✓ Branch 4 taken 9 times.
✓ Branch 5 taken 9 times.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 9 times.
|
18 | sizes := list(Dimension.size(dim) for dim in Type.arrayDims(Variable.typeOf(Pointer.access(BVariable.getVarPointer(exp.cref, sourceInfo()))))); |
| 434 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
9 | if listLength(subs) <> listLength(sizes) then return; end if; |
| 435 |
2/2✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
|
18 | for tpl in List.zip(subs, sizes) loop |
| 436 | () := match tpl | ||
| 437 | case (Subscript.INDEX(index = Expression.INTEGER()), _) algorithm | ||
| 438 | 9 | idx := idx * Util.tuple22(tpl) + Expression.integerValue(Subscript.toExp(Util.tuple21(tpl))) - 1; | |
| 439 | then (); | ||
| 440 | ✗ | else algorithm return; then (); | |
| 441 | end match; | ||
| 442 | end for; | ||
| 443 | index := SOME(idx); | ||
| 444 | then (); | ||
| 445 | else (); | ||
| 446 | end match; | ||
| 447 | end flatIndex; | ||
| 448 | |||
| 449 | function reshapeStart | ||
| 450 | "nested array of the flat elements for the dimension sizes" | ||
| 451 | input array<Expression> elements; | ||
| 452 | input list<Integer> sizes; | ||
| 453 | input Type elemTy; | ||
| 454 | input Integer offset; | ||
| 455 | output Expression exp; | ||
| 456 | protected | ||
| 457 | Integer n, stride; | ||
| 458 | list<Integer> rest; | ||
| 459 | algorithm | ||
| 460 | exp := match sizes | ||
| 461 | 10 | case {} then elements[offset + 1]; | |
| 462 | case n :: rest algorithm | ||
| 463 | 1 | stride := List.fold(rest, intMul, 1); | |
| 464 |
6/6✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 5 taken 10 times.
✓ Branch 6 taken 1 time.
|
12 | then Expression.makeArray(Type.liftArrayLeftList(elemTy, list(Dimension.fromInteger(s) for s in sizes)), |
| 465 | listArray(list(reshapeStart(elements, rest, elemTy, offset + (i - 1) * stride) for i in 1:n)), true); | ||
| 466 | end match; | ||
| 467 | end reshapeStart; | ||
| 468 | |||
| 469 | function checkReplacements | ||
| 470 | "Checks validity of all replacements, returns all valid replacements and auxiliary equations" | ||
| 471 | input UnorderedMap<ComponentRef, Expression> replacements; | ||
| 472 | input EqData eqData; | ||
| 473 | output UnorderedMap<ComponentRef, Expression> newReplacements = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 474 | output list<Pointer<Equation>> auxEquations = {}; | ||
| 475 | protected | ||
| 476 | UnorderedMap<ComponentRef, ExceptionKind> exceptionMap = UnorderedMap.new<ExceptionKind>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 477 | ComponentRef cref; | ||
| 478 | Expression exp; | ||
| 479 | Pointer<Equation> eqPtr; | ||
| 480 | EquationAttributes attr; | ||
| 481 | algorithm | ||
| 482 | 380 | EqData.map(eqData, function filterExceptionsEquation(acc = exceptionMap)); | |
| 483 |
2/2✓ Branch 1 taken 2036 times.
✓ Branch 2 taken 380 times.
|
2416 | for keyValueTpl in UnorderedMap.toList(replacements) loop |
| 484 | 2036 | (cref, exp) := keyValueTpl; | |
| 485 |
2/2✓ Branch 1 taken 2030 times.
✓ Branch 2 taken 6 times.
|
2036 | if isValidReplacement(cref, exp, exceptionMap) then |
| 486 | // replacement is valid - add to newReplacements | ||
| 487 | 2030 | UnorderedMap.add(cref, exp, newReplacements); | |
| 488 | else | ||
| 489 | // add auxiliary equation | ||
| 490 | 6 | attr := BackendDAE.lowerEquationAttributes(ComponentRef.getSubscriptedType(cref), false); | |
| 491 | 6 | eqPtr := Equation.makeAssignment(Expression.fromCref(cref), exp, EqData.getUniqueIndex(eqData), "SIM", Iterator.EMPTY(), attr); | |
| 492 | auxEquations := eqPtr :: auxEquations; | ||
| 493 | end if; | ||
| 494 | end for; | ||
| 495 | |||
| 496 |
2/2✓ Branch 1 taken 366 times.
✓ Branch 2 taken 14 times.
|
380 | if Flags.isSet(Flags.DUMP_REPL) then |
| 497 | 14 | dumpReplacements(newReplacements, auxEquations); | |
| 498 | end if; | ||
| 499 | end checkReplacements; | ||
| 500 | |||
| 501 | function isValidReplacement | ||
| 502 | "Checks if a replacement (cref, exp) is valid" | ||
| 503 | input ComponentRef cref; | ||
| 504 | input Expression exp; | ||
| 505 | input UnorderedMap<ComponentRef, ExceptionKind> exceptionMap; | ||
| 506 | output Boolean b = true; | ||
| 507 | algorithm | ||
| 508 | b := match (UnorderedMap.get(cref, exceptionMap), exp) | ||
| 509 | // no exception for this cref | ||
| 510 | case (NONE(), _) then true; | ||
| 511 | // cref exception. only allow replacement by a cref | ||
| 512 | case (SOME(ExceptionKind.CREF_ALIAS), Expression.CREF()) then true; | ||
| 513 | // disallow other exceptions | ||
| 514 | else false; | ||
| 515 | end match; | ||
| 516 | end isValidReplacement; | ||
| 517 | |||
| 518 | // different kinds of exceptions | ||
| 519 | type ExceptionKind = enumeration(NO_ALIAS, CREF_ALIAS); | ||
| 520 | |||
| 521 | function filterExceptionsEquation | ||
| 522 | input output Equation eqn; | ||
| 523 | input UnorderedMap<ComponentRef, ExceptionKind> acc; | ||
| 524 | algorithm | ||
| 525 | () := match eqn | ||
| 526 | // algorithm outputs shall not be replaced | ||
| 527 | case Equation.ALGORITHM() algorithm | ||
| 528 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 104 times.
|
212 | for cref in eqn.alg.outputs loop |
| 529 | 108 | UnorderedMap.add(cref, ExceptionKind.NO_ALIAS, acc); | |
| 530 | end for; | ||
| 531 | then (); | ||
| 532 | else (); | ||
| 533 | end match; | ||
| 534 | 14659 | Equation.map(eqn, function filterExceptions(acc = acc)); | |
| 535 | end filterExceptionsEquation; | ||
| 536 | |||
| 537 | function filterExceptions | ||
| 538 | "Filter expression for all forbidden aliases (pre, dynamic optimization annotations, ...)" | ||
| 539 | input output Expression exp; | ||
| 540 | input UnorderedMap<ComponentRef, ExceptionKind> acc; | ||
| 541 | algorithm | ||
| 542 | () := match exp | ||
| 543 | local | ||
| 544 | Call call; | ||
| 545 | ComponentRef cref; | ||
| 546 | |||
| 547 | // all variables in pre() call shall not be replaced | ||
| 548 | case Expression.CALL(call = call as Call.TYPED_CALL(arguments = {Expression.CREF(cref = cref)})) | ||
| 549 | guard(AbsynUtil.pathString(Function.nameConsiderBuiltin(call.fn)) == "pre") algorithm | ||
| 550 | 350 | UnorderedMap.add(cref, ExceptionKind.NO_ALIAS, acc); | |
| 551 | then (); | ||
| 552 | |||
| 553 | case Expression.CREF() algorithm | ||
| 554 | // TODO: add guard here (dont do alias for optimization annotations) | ||
| 555 | // UnorderedSet.add(cref, acc); | ||
| 556 | then (); | ||
| 557 | |||
| 558 | // tuple elements shall not be replaced by something that is not a cref | ||
| 559 | case Expression.TUPLE() algorithm | ||
| 560 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 12 times.
|
52 | for elem in exp.elements loop |
| 561 | () := match elem | ||
| 562 | case Expression.CREF() algorithm | ||
| 563 | 40 | UnorderedMap.add(elem.cref, ExceptionKind.CREF_ALIAS, acc); | |
| 564 | then (); | ||
| 565 | else (); | ||
| 566 | end match; | ||
| 567 | end for; | ||
| 568 | then (); | ||
| 569 | |||
| 570 | else (); | ||
| 571 | end match; | ||
| 572 | end filterExceptions; | ||
| 573 | |||
| 574 | function dumpReplacements | ||
| 575 | input UnorderedMap<ComponentRef, Expression> replacements; | ||
| 576 | input list<Pointer<Equation>> auxEquations = {}; | ||
| 577 | algorithm | ||
| 578 | 14 | print(Replacements.simpleToString(replacements) + "\n"); | |
| 579 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 time.
|
14 | if not listEmpty(auxEquations) then |
| 580 | 1 | print(StringUtil.headline_4("[dumprepl] Found But Illegal Alias Replacements (added as equations):")); | |
| 581 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
2 | for eqPtr in auxEquations loop |
| 582 | 1 | print("\t" + Equation.toString(Pointer.access(eqPtr)) + "\n"); | |
| 583 | end for; | ||
| 584 | 1 | print("\n"); | |
| 585 | end if; | ||
| 586 | end dumpReplacements; | ||
| 587 | |||
| 588 | function aliasClocks | ||
| 589 | "STEPS: | ||
| 590 | 1. collect alias sets (variables, equations, optional constant binding) | ||
| 591 | 2. balance sets - choose variable to keep if necessary | ||
| 592 | 3. match/sort set (linear w.r.t. unknowns since all equations contain two crefs at max and are simple/linear) | ||
| 593 | 4. apply replacements | ||
| 594 | 5. save replacements in bindings of alias variables | ||
| 595 | " | ||
| 596 | extends Module.aliasInterface; | ||
| 597 | algorithm | ||
| 598 | (varData, eqData) := match (varData, eqData) | ||
| 599 | local | ||
| 600 | UnorderedMap<ComponentRef, Expression> replacements; | ||
| 601 | EquationPointers newEquations; | ||
| 602 | list<Pointer<Variable>> alias_vars; | ||
| 603 | list<Pointer<Equation>> auxEquations; | ||
| 604 | |||
| 605 | case (BVariable.VAR_DATA_SIM(), BEquation.EQ_DATA_SIM()) | ||
| 606 | algorithm | ||
| 607 | // ----------------------------------- | ||
| 608 | // 1. 2. 3. | ||
| 609 | // ----------------------------------- | ||
| 610 | 190 | (replacements, newEquations) := aliasCausalize(varData.clocks, eqData.clocked, kind, eqData.uniqueIndex, "Clocked"); | |
| 611 | 190 | (replacements, auxEquations) := checkReplacements(replacements, eqData); | |
| 612 | |||
| 613 | // ----------------------------------- | ||
| 614 | // 4. apply replacements | ||
| 615 | // 5. save replacements in bindings of alias variables | ||
| 616 | // ----------------------------------- | ||
| 617 | 190 | (eqData, varData) := Replacements.applySimple(eqData, varData, replacements); | |
| 618 |
4/4✓ Branch 1 taken 1 time.
✓ Branch 2 taken 190 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 190 times.
|
191 | alias_vars := list(BVariable.getVarPointer(cref, sourceInfo()) for cref in UnorderedMap.keyList(replacements)); |
| 619 | |||
| 620 | // save new equations and compress affected arrays(some might have been removed) | ||
| 621 | 190 | eqData.clocked := EquationPointers.compress(newEquations); | |
| 622 | |||
| 623 | // remove alias variables from clocks and add to alias | ||
| 624 | 190 | varData.clocks := VariablePointers.removeList(alias_vars, varData.clocks); | |
| 625 | 190 | varData.aliasVars := VariablePointers.addList(alias_vars, varData.aliasVars); | |
| 626 | 190 | then (varData, EqData.addUntypedList(eqData, auxEquations, false)); | |
| 627 | |||
| 628 | else algorithm | ||
| 629 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."}); | |
| 630 | ✗ | then fail(); | |
| 631 | end match; | ||
| 632 | end aliasClocks; | ||
| 633 | |||
| 634 | function aliasCausalize | ||
| 635 | "STEPS: | ||
| 636 | 1. collect alias sets (variables, equations, optional constant binding) | ||
| 637 | 2. balance sets - choose variable to keep if necessary | ||
| 638 | 3. match/sort set (linear w.r.t. since all equations contain two unknown crefs at max and are simple/linear) | ||
| 639 | " | ||
| 640 | input VariablePointers variables; | ||
| 641 | input EquationPointers equations; | ||
| 642 | input Partition.Kind kind; | ||
| 643 | input Pointer<Integer> index; | ||
| 644 | input String context; | ||
| 645 | output UnorderedMap<ComponentRef, Expression> replacements; | ||
| 646 | output EquationPointers newEquations; | ||
| 647 | protected | ||
| 648 | Integer size, setIdx = 1; | ||
| 649 | UnorderedMap<ComponentRef, SetPtr> map; | ||
| 650 | list<AliasSet> sets; | ||
| 651 | algorithm | ||
| 652 | // ------------------------------------------------------------------------------ | ||
| 653 | // 1. collect alias sets (variables, equations, optional constant binding) | ||
| 654 | // ------------------------------------------------------------------------------ | ||
| 655 | // collect (cref) -> (simpleSet) hashtable | ||
| 656 | 383 | size := VariablePointers.size(variables); | |
| 657 | 383 | map := UnorderedMap.new<SetPtr>(ComponentRef.hash, ComponentRef.isEqual, size); | |
| 658 | 383 | (newEquations, map) := NBEquation.EquationPointers.foldRemovePtr(equations, findSimpleEquation, map); | |
| 659 | |||
| 660 | 383 | sets := getSimpleSets(map, size); | |
| 661 |
2/2✓ Branch 1 taken 17 times.
✓ Branch 2 taken 366 times.
|
383 | if Flags.isSet(Flags.DUMP_REPL) then |
| 662 | 17 | print(StringUtil.headline_2("[dumprepl] " + context + " Alias Sets:") + "\n"); | |
| 663 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 7 times.
|
17 | if listEmpty(sets) then |
| 664 | 7 | print("<No " + context + " Alias Sets>\n\n"); | |
| 665 | else | ||
| 666 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10 times.
|
23 | for set in sets loop |
| 667 | 13 | print(StringUtil.headline_4("Alias Set " + intString(setIdx) + ":") + AliasSet.toString(set) + "\n"); | |
| 668 | 13 | setIdx := setIdx + 1; | |
| 669 | end for; | ||
| 670 | end if; | ||
| 671 | end if; | ||
| 672 | |||
| 673 | // -------------------------------------------------------------------------------------------------------- | ||
| 674 | // 2. balance sets - choose variable to keep if necessary | ||
| 675 | // 3. match/sort set (linear w.r.t. vars since all equations contain two crefs at max and are simple/linear) | ||
| 676 | // -------------------------------------------------------------------------------------------------------- | ||
| 677 | 383 | replacements := UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual, size); | |
| 678 |
2/2✓ Branch 0 taken 1107 times.
✓ Branch 1 taken 380 times.
|
1487 | for set in sets loop |
| 679 | 1107 | replacements := createReplacementRules(set, index, replacements, kind); | |
| 680 | end for; | ||
| 681 | |||
| 682 | end aliasCausalize; | ||
| 683 | |||
| 684 | function findSimpleEquation | ||
| 685 | "Checks if the equation is simple and adds it to the correct set in the hashTable." | ||
| 686 | input Pointer<Equation> eq_ptr; | ||
| 687 | input output UnorderedMap<ComponentRef, SetPtr> map; | ||
| 688 | output Boolean delete = false; | ||
| 689 | protected | ||
| 690 | Equation eq; | ||
| 691 | CrefTpl crefTpl = EMPTY_CREF_TPL; | ||
| 692 | algorithm | ||
| 693 | 4888 | eq := forToFullArrayEquation(Pointer.access(eq_ptr)); | |
| 694 | crefTpl := match eq | ||
| 695 | case BEquation.SCALAR_EQUATION() guard(isSimpleExp(eq.lhs) and isSimpleExp(eq.rhs)) algorithm | ||
| 696 | 2944 | crefTpl := Expression.fold(eq.rhs, findCrefs, crefTpl); | |
| 697 | 2944 | crefTpl := Expression.fold(eq.lhs, findCrefs, crefTpl); | |
| 698 | then crefTpl; | ||
| 699 | |||
| 700 | // an array variable and a scalar are not aliases, even if the array has only one element: | ||
| 701 | // replacing the array by the scalar breaks the array expressions it is used in | ||
| 702 | case BEquation.ARRAY_EQUATION() guard(isSimpleExp(eq.lhs) and isSimpleExp(eq.rhs) and sameArrayness(eq.lhs, eq.rhs)) algorithm | ||
| 703 | 162 | crefTpl := Expression.fold(eq.rhs, findCrefs, crefTpl); | |
| 704 | 162 | crefTpl := Expression.fold(eq.lhs, findCrefs, crefTpl); | |
| 705 | then crefTpl; | ||
| 706 | |||
| 707 | case BEquation.RECORD_EQUATION() guard(isSimpleExp(eq.lhs) and isSimpleExp(eq.rhs)) algorithm | ||
| 708 | 51 | crefTpl := Expression.fold(eq.rhs, findCrefs, crefTpl); | |
| 709 | 51 | crefTpl := Expression.fold(eq.lhs, findCrefs, crefTpl); | |
| 710 | then crefTpl; | ||
| 711 | |||
| 712 | else crefTpl; | ||
| 713 | end match; | ||
| 714 | |||
| 715 | (map, delete) := match crefTpl | ||
| 716 | local | ||
| 717 | SetPtr set_ptr, set1_ptr, set2_ptr; | ||
| 718 | AliasSet set, set1, set2; | ||
| 719 | ComponentRef cr1, cr2; | ||
| 720 | Pointer<Equation> new_eq_ptr; | ||
| 721 | |||
| 722 | // one variable is connected to a parameter or constant | ||
| 723 | case CREF_TPL(cr_lst = {cr1}) algorithm | ||
| 724 |
2/2✓ Branch 1 taken 346 times.
✓ Branch 2 taken 140 times.
|
486 | if not UnorderedMap.contains(cr1, map) then |
| 725 | // the variable does not belong to a set -> create new one | ||
| 726 | set := EMPTY_ALIAS_SET; | ||
| 727 | 346 | set.simple_variables := {cr1}; | |
| 728 | 346 | set.const_opt := SOME(Pointer.create(eq)); | |
| 729 | 346 | UnorderedMap.add(cr1, Pointer.create(set), map); | |
| 730 | else | ||
| 731 | // it already belongs to a set, try to update it and throw error if there already is a const binding | ||
| 732 | 140 | set_ptr := UnorderedMap.getOrFail(cr1, map); | |
| 733 | 140 | set := Pointer.access(set_ptr); | |
| 734 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
✓ Branch 2 taken 140 times.
✗ Branch 3 not taken.
|
140 | if isSome(set.const_opt) then |
| 735 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to add Equation:\n" | |
| 736 | + Equation.toString(eq) + "\n because the set already contains a constant binding. | ||
| 737 | Overdetermined Set!:" + AliasSet.toString(set)}); | ||
| 738 | ✗ | fail(); | |
| 739 | else | ||
| 740 | 140 | set.const_opt := SOME(Pointer.create(eq)); | |
| 741 | 140 | Pointer.update(set_ptr, set); | |
| 742 | end if; | ||
| 743 | end if; | ||
| 744 | then (map, true); | ||
| 745 | |||
| 746 | // two variable crefs are connected by a simple equation | ||
| 747 | case CREF_TPL(cr_lst = {cr1, cr2}) algorithm | ||
| 748 |
4/4✓ Branch 1 taken 356 times.
✓ Branch 2 taken 1102 times.
✓ Branch 4 taken 66 times.
✓ Branch 5 taken 290 times.
|
1458 | if (UnorderedMap.contains(cr1, map) and UnorderedMap.contains(cr2, map)) then |
| 749 | // Merge sets | ||
| 750 | 66 | set1_ptr := UnorderedMap.getOrFail(cr1, map); | |
| 751 | 66 | set2_ptr := UnorderedMap.getOrFail(cr2, map); | |
| 752 | 66 | set1 := Pointer.access(set1_ptr); | |
| 753 | |||
| 754 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 61 times.
|
66 | if referenceEq(set1_ptr, set2_ptr) then |
| 755 | // check if there is a constant binding | ||
| 756 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if isSome(set1.const_opt) then |
| 757 | ✗ | set2 := Pointer.access(set2_ptr); | |
| 758 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to merge following sets " + | |
| 759 | "because they would create a loop and both have a constant binding. This would create an underdetermined Set!:\n\n" + | ||
| 760 | "Trying to merge: " + Equation.toString(eq) + "\n\n" + | ||
| 761 | AliasSet.toString(set1) + "\n" + AliasSet.toString(set2)}); | ||
| 762 | end if; | ||
| 763 | // add eq to set1 | ||
| 764 | 5 | new_eq_ptr := Pointer.create(eq); | |
| 765 | 10 | set1.simple_equations := new_eq_ptr :: set1.simple_equations; | |
| 766 | // update pointer of set1 -> set1 | ||
| 767 | 5 | Pointer.update(set1_ptr, set1); | |
| 768 | |||
| 769 | else | ||
| 770 | 61 | set2 := Pointer.access(set2_ptr); | |
| 771 | set := EMPTY_ALIAS_SET; | ||
| 772 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 61 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
61 | if (isSome(set1.const_opt) and isSome(set2.const_opt)) then |
| 773 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to merge following sets " + | |
| 774 | "because both have a constant binding. This would create an overdetermined Set!:\n\n" + | ||
| 775 | AliasSet.toString(set1) + "\n" + AliasSet.toString(set2)}); | ||
| 776 | ✗ | fail(); | |
| 777 | elseif isSome(set1.const_opt) then | ||
| 778 | ✗ | set.const_opt := set1.const_opt; | |
| 779 | elseif isSome(set2.const_opt) then | ||
| 780 | 4 | set.const_opt := set2.const_opt; | |
| 781 | end if; | ||
| 782 | |||
| 783 | // try to append the shorter to the longer lists | ||
| 784 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 46 times.
|
61 | if List.compareLength(set1.simple_equations, set2.simple_equations) > 0 then |
| 785 | 30 | set.simple_equations := Pointer.create(eq) :: Dangerous.listAppendDestroy(set2.simple_equations, set1.simple_equations); | |
| 786 | else | ||
| 787 | 92 | set.simple_equations := Pointer.create(eq) :: Dangerous.listAppendDestroy(set1.simple_equations, set2.simple_equations); | |
| 788 | end if; | ||
| 789 | |||
| 790 | // try to change as few pointer entries as possible | ||
| 791 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 46 times.
|
61 | if List.compareLength(set1.simple_variables, set2.simple_variables) > 0 then |
| 792 | 15 | set.simple_variables := Dangerous.listAppendDestroy(set2.simple_variables, set1.simple_variables); | |
| 793 | 15 | Pointer.update(set1_ptr, set); | |
| 794 |
2/2✓ Branch 0 taken 147 times.
✓ Branch 1 taken 15 times.
|
162 | for cr in set2.simple_variables loop |
| 795 | 147 | UnorderedMap.add(cr, set1_ptr, map); | |
| 796 | end for; | ||
| 797 | else | ||
| 798 | 46 | set.simple_variables := Dangerous.listAppendDestroy(set2.simple_variables, set1.simple_variables); | |
| 799 | 46 | Pointer.update(set2_ptr, set); | |
| 800 |
2/2✓ Branch 0 taken 98 times.
✓ Branch 1 taken 46 times.
|
144 | for cr in set1.simple_variables loop |
| 801 | 98 | UnorderedMap.add(cr, set2_ptr, map); | |
| 802 | end for; | ||
| 803 | end if; | ||
| 804 | end if; | ||
| 805 | elseif UnorderedMap.contains(cr1, map) then | ||
| 806 | // Update set | ||
| 807 | 290 | set_ptr := UnorderedMap.getOrFail(cr1, map); | |
| 808 | 290 | set := Pointer.access(set_ptr); | |
| 809 | // add cr2 to variables and add new equation pointer | ||
| 810 | 580 | set.simple_variables := cr2 :: set.simple_variables; | |
| 811 | 580 | set.simple_equations := Pointer.create(eq) :: set.simple_equations; | |
| 812 | 290 | Pointer.update(set_ptr, set); | |
| 813 | // add new hash entry for c2 | ||
| 814 | 290 | UnorderedMap.add(cr2, set_ptr, map); | |
| 815 | elseif UnorderedMap.contains(cr2, map) then | ||
| 816 | // Update set | ||
| 817 | 280 | set_ptr := UnorderedMap.getOrFail(cr2, map); | |
| 818 | 280 | set := Pointer.access(set_ptr); | |
| 819 | // add cr1 to variables and add new equation pointer | ||
| 820 | 560 | set.simple_variables := cr1 :: set.simple_variables; | |
| 821 | 560 | set.simple_equations := Pointer.create(eq) :: set.simple_equations; | |
| 822 | 280 | Pointer.update(set_ptr, set); | |
| 823 | // add new hash entry for c1 | ||
| 824 | 280 | UnorderedMap.add(cr1, set_ptr, map); | |
| 825 | else | ||
| 826 | // create new set | ||
| 827 | set := EMPTY_ALIAS_SET; | ||
| 828 | // add both variables and add new equation pointer | ||
| 829 | 822 | set.simple_variables := {cr1, cr2}; | |
| 830 | 1644 | set.simple_equations := {Pointer.create(eq)}; | |
| 831 | 822 | set_ptr := Pointer.create(set); | |
| 832 | // add new hash entry for both variables | ||
| 833 | 822 | UnorderedMap.add(cr1, set_ptr, map); | |
| 834 | 822 | UnorderedMap.add(cr2, set_ptr, map); | |
| 835 | end if; | ||
| 836 | then (map, true); | ||
| 837 | |||
| 838 | // no replacements can be done with this equation | ||
| 839 | else (map, false); | ||
| 840 | end match; | ||
| 841 | end findSimpleEquation; | ||
| 842 | |||
| 843 | function forToFullArrayEquation | ||
| 844 | "Converts a for equation into the array equation of the full variables if it is | ||
| 845 | equivalent to it, e.g. for i in 1:n loop a[i].x = b[i].y; end for; -> a.x = b.y; | ||
| 846 | All array crefs need the same subscripts, consisting of each iterator exactly once | ||
| 847 | (and whole dimensions) and each iterator has to cover its full dimension. | ||
| 848 | Otherwise the equation is returned unchanged." | ||
| 849 | input output Equation eq; | ||
| 850 | protected | ||
| 851 | list<ComponentRef> names; | ||
| 852 | list<Expression> ranges; | ||
| 853 | list<Option<Iterator>> maps; | ||
| 854 | UnorderedMap<ComponentRef, Integer> iter_sizes = UnorderedMap.new<Integer>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 855 | Pointer<Option<list<Subscript>>> subs_ptr = Pointer.create(NONE()); | ||
| 856 | Pointer<Boolean> ok_ptr = Pointer.create(true); | ||
| 857 | Pointer<Option<Type>> ty_ptr = Pointer.create(NONE()); | ||
| 858 | Expression lhs, rhs; | ||
| 859 | Integer start, step, stop; | ||
| 860 | algorithm | ||
| 861 | (lhs, rhs) := match eq | ||
| 862 | case Equation.FOR_EQUATION(body = {Equation.SCALAR_EQUATION(lhs = lhs, rhs = rhs)}) then (lhs, rhs); | ||
| 863 | case Equation.FOR_EQUATION(body = {Equation.ARRAY_EQUATION(lhs = lhs, rhs = rhs)}) then (lhs, rhs); | ||
| 864 | 4604 | else algorithm return; then (Expression.EMPTY(Type.UNKNOWN()), Expression.EMPTY(Type.UNKNOWN())); | |
| 865 | end match; | ||
| 866 | |||
| 867 | // all iterators have to be plain ranges starting at one with step one | ||
| 868 | 284 | (names, ranges, maps) := Iterator.getFrames(Equation.getForIterator(eq)); | |
| 869 |
2/2✓ Branch 1 taken 306 times.
✓ Branch 2 taken 200 times.
|
506 | for tpl in List.zip3(names, ranges, maps) loop |
| 870 | _ := match tpl | ||
| 871 | local | ||
| 872 | ComponentRef name; | ||
| 873 | Expression range; | ||
| 874 | case (name, range as Expression.RANGE(), NONE()) guard(Expression.isLiteral(range)) algorithm | ||
| 875 | 243 | (start, step, stop) := Expression.getIntegerRange(range, false); | |
| 876 |
3/4✓ Branch 0 taken 222 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 222 times.
|
243 | if start <> 1 or step <> 1 then return; end if; |
| 877 | 222 | UnorderedMap.add(name, stop, iter_sizes); | |
| 878 | then (); | ||
| 879 | 63 | else algorithm return; then (); | |
| 880 | end match; | ||
| 881 | end for; | ||
| 882 | |||
| 883 | // check all crefs and replace them by the full variables | ||
| 884 | 200 | lhs := Expression.map(lhs, function fullVariableCref(iter_sizes = iter_sizes, subs_ptr = subs_ptr, ok_ptr = ok_ptr, ty_ptr = ty_ptr)); | |
| 885 | 200 | rhs := Expression.map(rhs, function fullVariableCref(iter_sizes = iter_sizes, subs_ptr = subs_ptr, ok_ptr = ok_ptr, ty_ptr = ty_ptr)); | |
| 886 |
4/8✓ Branch 1 taken 139 times.
✓ Branch 2 taken 61 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 139 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 139 times.
|
200 | if not Pointer.access(ok_ptr) or isNone(Pointer.access(subs_ptr)) then return; end if; |
| 887 | // iterators must not be used outside of the subscripts | ||
| 888 |
3/4✓ Branch 4 taken 139 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 16 times.
✓ Branch 9 taken 123 times.
|
139 | if Expression.contains(lhs, function isIteratorCref(iter_sizes = iter_sizes)) |
| 889 | 16 | or Expression.contains(rhs, function isIteratorCref(iter_sizes = iter_sizes)) then return; end if; | |
| 890 | 123 | lhs := Expression.map(lhs, Expression.repairOperator); | |
| 891 | 123 | rhs := Expression.map(rhs, Expression.repairOperator); | |
| 892 | // every iterator has to be used | ||
| 893 |
1/2✗ Branch 5 not taken.
✓ Branch 6 taken 123 times.
|
123 | if listLength(List.filterOnTrue(Util.getOption(Pointer.access(subs_ptr)), Subscript.isIndex)) <> UnorderedMap.size(iter_sizes) then return; end if; |
| 894 | |||
| 895 | 123 | eq := Equation.ARRAY_EQUATION(Util.getOption(Pointer.access(ty_ptr)), lhs, rhs, Equation.getSource(eq), Equation.getAttributes(eq), NONE()); | |
| 896 | end forToFullArrayEquation; | ||
| 897 | |||
| 898 | function isIteratorCref | ||
| 899 | input Expression exp; | ||
| 900 | input UnorderedMap<ComponentRef, Integer> iter_sizes; | ||
| 901 | output Boolean b; | ||
| 902 | algorithm | ||
| 903 | b := match exp | ||
| 904 | 302 | case Expression.CREF() then UnorderedMap.contains(exp.cref, iter_sizes); | |
| 905 | else false; | ||
| 906 | end match; | ||
| 907 | end isIteratorCref; | ||
| 908 | |||
| 909 | function isFullIteratorSubscript | ||
| 910 | "true if the subscript is whole or an iterator that covers the full dimension" | ||
| 911 | input Subscript sub; | ||
| 912 | input Dimension dim; | ||
| 913 | input UnorderedMap<ComponentRef, Integer> iter_sizes; | ||
| 914 | output Boolean b; | ||
| 915 | algorithm | ||
| 916 | b := match sub | ||
| 917 | local | ||
| 918 | ComponentRef iter; | ||
| 919 | Expression range; | ||
| 920 | Integer start, step, stop; | ||
| 921 | case Subscript.WHOLE() then true; | ||
| 922 | case Subscript.SLICE(slice = range as Expression.RANGE()) guard(Expression.isLiteral(range) and Dimension.isKnown(dim)) algorithm | ||
| 923 | 11 | (start, step, stop) := Expression.getIntegerRange(range, false); | |
| 924 |
3/6✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 11 times.
|
11 | then start == 1 and step == 1 and stop == Dimension.size(dim); |
| 925 | case Subscript.INDEX(index = Expression.CREF(cref = iter)) | ||
| 926 | guard(UnorderedMap.contains(iter, iter_sizes) and Dimension.isKnown(dim)) | ||
| 927 | 381 | then Dimension.size(dim) == UnorderedMap.getSafe(iter, iter_sizes, sourceInfo()); | |
| 928 | else false; | ||
| 929 | end match; | ||
| 930 | end isFullIteratorSubscript; | ||
| 931 | |||
| 932 | function fullVariableCref | ||
| 933 | "helper for forToFullArrayEquation. Replaces subscripted crefs by the full variable | ||
| 934 | and checks that all of them are subscripted the same way and that no iterator is used otherwise." | ||
| 935 | input output Expression exp; | ||
| 936 | input UnorderedMap<ComponentRef, Integer> iter_sizes; | ||
| 937 | input Pointer<Option<list<Subscript>>> subs_ptr; | ||
| 938 | input Pointer<Boolean> ok_ptr; | ||
| 939 | input Pointer<Option<Type>> ty_ptr; | ||
| 940 | protected | ||
| 941 | list<Subscript> subs; | ||
| 942 | list<Dimension> dims; | ||
| 943 | Pointer<Variable> var_ptr; | ||
| 944 | ComponentRef name; | ||
| 945 | Type ty; | ||
| 946 | Boolean ok; | ||
| 947 | algorithm | ||
| 948 |
2/2✓ Branch 1 taken 353 times.
✓ Branch 2 taken 1141 times.
|
1494 | if not Pointer.access(ok_ptr) then return; end if; |
| 949 | exp := match exp | ||
| 950 | // iterators are checked after all crefs are replaced (they are also mapped inside of subscripts) | ||
| 951 | case Expression.CREF() guard(UnorderedMap.contains(exp.cref, iter_sizes)) then exp; | ||
| 952 | |||
| 953 | case Expression.CREF() guard(ComponentRef.isTime(exp.cref) or not ComponentRef.hasSubscripts(exp.cref)) algorithm | ||
| 954 | // unsubscripted crefs have to be scalar, array variables have to be subscripted by the iterators | ||
| 955 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 55 times.
|
57 | if Type.isArray(exp.ty) then |
| 956 | 2 | Pointer.update(ok_ptr, false); | |
| 957 | end if; | ||
| 958 | then exp; | ||
| 959 | |||
| 960 | case Expression.CREF() algorithm | ||
| 961 | 363 | var_ptr := BVariable.getVarPointer(exp.cref, sourceInfo()); | |
| 962 | 363 | name := BVariable.getVarName(var_ptr); | |
| 963 | 363 | ty := ComponentRef.getSubscriptedType(name); | |
| 964 | 363 | dims := Type.arrayDims(ty); | |
| 965 | 363 | subs := ComponentRef.subscriptsAllWithWholeFlat(exp.cref); | |
| 966 | 363 | ok := listLength(subs) == listLength(dims); | |
| 967 | // each subscript is either whole or an iterator of the full dimension size | ||
| 968 |
2/2✓ Branch 0 taken 361 times.
✓ Branch 1 taken 2 times.
|
363 | if ok then |
| 969 |
9/10✓ Branch 0 taken 427 times.
✓ Branch 1 taken 361 times.
✓ Branch 2 taken 427 times.
✓ Branch 3 taken 361 times.
✓ Branch 4 taken 427 times.
✓ Branch 5 taken 361 times.
✓ Branch 7 taken 38 times.
✓ Branch 8 taken 389 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 361 times.
|
788 | ok := List.all(list(isFullIteratorSubscript(sub, dim, iter_sizes) threaded for sub in subs, dim in dims), Util.id); |
| 970 | end if; | ||
| 971 | // all array crefs have the same subscripts and types | ||
| 972 |
2/2✓ Branch 0 taken 325 times.
✓ Branch 1 taken 38 times.
|
363 | if ok then |
| 973 | ok := match Pointer.access(subs_ptr) | ||
| 974 | local | ||
| 975 | list<Subscript> subs2; | ||
| 976 |
4/4✓ Branch 1 taken 138 times.
✓ Branch 2 taken 16 times.
✓ Branch 6 taken 134 times.
✓ Branch 7 taken 4 times.
|
154 | case SOME(subs2) then List.isEqualOnTrue(subs, subs2, Subscript.isEqual) |
| 977 | and Type.isEqual(ty, Util.getOption(Pointer.access(ty_ptr))); | ||
| 978 | else algorithm | ||
| 979 | // each iterator only once | ||
| 980 | 171 | ok := listLength(List.uniqueOnTrue(List.filterOnTrue(subs, Subscript.isIndex), Subscript.isEqual)) == listLength(List.filterOnTrue(subs, Subscript.isIndex)); | |
| 981 | 171 | Pointer.update(subs_ptr, SOME(subs)); | |
| 982 | 171 | Pointer.update(ty_ptr, SOME(ty)); | |
| 983 | then ok; | ||
| 984 | end match; | ||
| 985 | end if; | ||
| 986 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 170 times.
|
402 | Pointer.update(ok_ptr, ok); |
| 987 | 363 | then Expression.fromCref(name); | |
| 988 | |||
| 989 | else exp; | ||
| 990 | end match; | ||
| 991 | end fullVariableCref; | ||
| 992 | |||
| 993 | function findCrefs "BB, kabdelhak | ||
| 994 | looks for variable crefs in Expressions, if more than 2 are found stop searching | ||
| 995 | also stop if complex structures appear, e.g. IFEXP | ||
| 996 | " | ||
| 997 | input Expression exp; | ||
| 998 | input output CrefTpl tpl; | ||
| 999 | algorithm | ||
| 1000 | tpl := match exp | ||
| 1001 | |||
| 1002 | case _ guard(not tpl.cont) then FAILED_CREF_TPL; | ||
| 1003 | |||
| 1004 | // time, parameter or constant found (nothing happens) | ||
| 1005 | case Expression.CREF() | ||
| 1006 | guard(BVariable.isParamOrConst(BVariable.getVarPointer(exp.cref, sourceInfo())) or ComponentRef.isTime(exp.cref)) | ||
| 1007 | then tpl; | ||
| 1008 | |||
| 1009 | // fail for record elements for now | ||
| 1010 | case Expression.CREF() | ||
| 1011 | guard(isSome(BVariable.getParent(BVariable.getVarPointer(exp.cref, sourceInfo())))) | ||
| 1012 | then FAILED_CREF_TPL; | ||
| 1013 | |||
| 1014 | // fail for top level inputs | ||
| 1015 | case Expression.CREF() | ||
| 1016 | guard(Variable.isTopLevelInput(Pointer.access(BVariable.getVarPointer(exp.cref, sourceInfo())))) | ||
| 1017 | then FAILED_CREF_TPL; | ||
| 1018 | |||
| 1019 | // variable found | ||
| 1020 | // 1. not time and not param or const | ||
| 1021 | // 2. less than two previous variables | ||
| 1022 | // 3. if it is an array, it has to be the full array. no slice replacement here | ||
| 1023 | case Expression.CREF() | ||
| 1024 | guard((tpl.varCount < 2) and not ComponentRef.hasSubscripts(exp.cref)) | ||
| 1025 | algorithm | ||
| 1026 | // add the variable to the list and bump var count | ||
| 1027 | 8380 | tpl.cr_lst := exp.cref :: tpl.cr_lst; | |
| 1028 | 4190 | tpl.varCount := tpl.varCount + 1; | |
| 1029 | then tpl; | ||
| 1030 | |||
| 1031 | // set the continue attribute to false if any fail case is met | ||
| 1032 | case _ guard(findCrefsFail(exp)) then FAILED_CREF_TPL; | ||
| 1033 | |||
| 1034 | else tpl; | ||
| 1035 | end match; | ||
| 1036 | end findCrefs; | ||
| 1037 | |||
| 1038 | function findCrefsFail | ||
| 1039 | "finds all failing cases to stop searching for simple crefs. | ||
| 1040 | also fails for crefs because viable cases have to be caught | ||
| 1041 | before invoking this function in findCrefs(). | ||
| 1042 | ToDo: Discuss and find all failing cases" | ||
| 1043 | input Expression exp; | ||
| 1044 | output Boolean cont; | ||
| 1045 | algorithm | ||
| 1046 | cont := match exp | ||
| 1047 | case Expression.CREF() then true; | ||
| 1048 | case Expression.RELATION() then true; | ||
| 1049 | case Expression.IF() then true; | ||
| 1050 | case Expression.CALL() then true; | ||
| 1051 | case Expression.RECORD() then true; | ||
| 1052 | else false; | ||
| 1053 | end match; | ||
| 1054 | end findCrefsFail; | ||
| 1055 | |||
| 1056 | function sameArrayness | ||
| 1057 | "true if both expressions are arrays or both are scalars" | ||
| 1058 | input Expression exp1; | ||
| 1059 | input Expression exp2; | ||
| 1060 | output Boolean same = Type.isArray(Expression.typeOf(exp1)) == Type.isArray(Expression.typeOf(exp2)); | ||
| 1061 | end sameArrayness; | ||
| 1062 | |||
| 1063 | function isSimpleExp | ||
| 1064 | "checks if an expression can be considered simple." | ||
| 1065 | input Expression exp; | ||
| 1066 | input output Boolean simple = true; | ||
| 1067 | output Integer num_cref = 0; | ||
| 1068 | algorithm | ||
| 1069 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 14484 times.
|
14505 | if not simple then return; end if; |
| 1070 | (simple, num_cref) := match exp | ||
| 1071 | local | ||
| 1072 | Integer num_cref_tmp; | ||
| 1073 | Operator.Op op; | ||
| 1074 | |||
| 1075 | case Expression.INTEGER() then (true, 0); | ||
| 1076 | case Expression.REAL() then (true, 0); | ||
| 1077 | case Expression.BOOLEAN() then (true, 0); | ||
| 1078 | case Expression.STRING() then (true, 0); | ||
| 1079 | case Expression.CREF() then (true, 1); | ||
| 1080 | // TODO what about parameters in the denominator, they could be zero, (alias strictness?) | ||
| 1081 | //case Expression.CREF() then (true, if ComponentRef.variability(exp.cref) > Variability.NON_STRUCTURAL_PARAMETER then 1 else 0); | ||
| 1082 | |||
| 1083 | 11 | case Expression.CAST() then isSimpleExp(exp.exp); | |
| 1084 | |||
| 1085 | case Expression.UNARY() algorithm | ||
| 1086 | 20 | (simple, num_cref) := isSimpleExp(exp.exp); | |
| 1087 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | simple := if simple then checkOp(exp.operator, num_cref) else false; |
| 1088 | 20 | then (simple, num_cref); | |
| 1089 | |||
| 1090 | case Expression.LUNARY() algorithm | ||
| 1091 | 9 | (simple, num_cref) := isSimpleExp(exp.exp); | |
| 1092 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | simple := if simple then checkOp(exp.operator, num_cref) else false; |
| 1093 | 9 | then (simple, num_cref); | |
| 1094 | |||
| 1095 | case Expression.BINARY(operator = Operator.OPERATOR(op = op)) algorithm | ||
| 1096 | 88 | (simple, num_cref) := isSimpleExp(exp.exp2); | |
| 1097 | // 1/x is not considered simple | ||
| 1098 |
4/4✓ Branch 0 taken 20 times.
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 1 time.
|
735 | if op == NFOperator.Op.DIV and num_cref <> 0 then simple := false; return; end if; |
| 1099 | 69 | (simple, num_cref_tmp) := isSimpleExp(exp.exp1, simple); | |
| 1100 | 69 | num_cref := num_cref + num_cref_tmp; | |
| 1101 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 23 times.
|
69 | simple := if simple then checkOp(exp.operator, num_cref) else false; |
| 1102 | 69 | then (simple, num_cref); | |
| 1103 | |||
| 1104 | case Expression.LBINARY() algorithm | ||
| 1105 | 12 | (simple, num_cref) := isSimpleExp(exp.exp1); | |
| 1106 | 12 | (simple, num_cref_tmp) := isSimpleExp(exp.exp2, simple); | |
| 1107 | 12 | num_cref := num_cref + num_cref_tmp; | |
| 1108 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
|
12 | simple := if simple then checkOp(exp.operator, num_cref) else false; |
| 1109 | 12 | then (simple, num_cref); | |
| 1110 | |||
| 1111 | case Expression.MULTARY(operator = Operator.OPERATOR(op = op)) algorithm | ||
| 1112 |
2/2✓ Branch 0 taken 594 times.
✓ Branch 1 taken 2534 times.
|
3128 | for arg in exp.inv_arguments loop |
| 1113 | 594 | (simple, num_cref_tmp) := isSimpleExp(arg, simple); | |
| 1114 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 545 times.
|
594 | if not simple then return; end if; |
| 1115 | 545 | num_cref := num_cref + num_cref_tmp; | |
| 1116 | end for; | ||
| 1117 | // 1/x is not considered simple | ||
| 1118 |
4/4✓ Branch 0 taken 1064 times.
✓ Branch 1 taken 1470 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 1048 times.
|
2534 | if op == NFOperator.Op.MUL and num_cref <> 0 then simple := false; return; end if; |
| 1119 |
2/2✓ Branch 0 taken 4596 times.
✓ Branch 1 taken 1936 times.
|
6532 | for arg in exp.arguments loop |
| 1120 | 4596 | (simple, num_cref_tmp) := isSimpleExp(arg, simple); | |
| 1121 |
2/2✓ Branch 0 taken 582 times.
✓ Branch 1 taken 4014 times.
|
4596 | if not simple then return; end if; |
| 1122 | 4014 | num_cref := num_cref + num_cref_tmp; | |
| 1123 | end for; | ||
| 1124 | 1936 | simple := if simple then checkOp(exp.operator, num_cref) else false; | |
| 1125 | 1936 | then (simple, num_cref); | |
| 1126 | |||
| 1127 | else (false, num_cref); | ||
| 1128 | end match; | ||
| 1129 | end isSimpleExp; | ||
| 1130 | |||
| 1131 | function checkOp | ||
| 1132 | "BB" | ||
| 1133 | input Operator op; | ||
| 1134 | input Integer cref_num; | ||
| 1135 | output Boolean b; | ||
| 1136 | algorithm | ||
| 1137 | b := match op | ||
| 1138 | case Operator.OPERATOR(op = NFOperator.Op.ADD) then true; | ||
| 1139 | case Operator.OPERATOR(op = NFOperator.Op.SUB) then true; | ||
| 1140 | case Operator.OPERATOR(op = NFOperator.Op.UMINUS) then true; | ||
| 1141 | case Operator.OPERATOR(op = NFOperator.Op.NOT) then true; | ||
| 1142 | 810 | case Operator.OPERATOR(op = NFOperator.Op.MUL) then cref_num < 2; | |
| 1143 | 1 | case Operator.OPERATOR(op = NFOperator.Op.DIV) then cref_num < 2; | |
| 1144 | 74 | else cref_num == 0; | |
| 1145 | end match; | ||
| 1146 | end checkOp; | ||
| 1147 | |||
| 1148 | function getSimpleSets | ||
| 1149 | "extracts all simple sets from the hashTable and avoids duplicates by marking variables" | ||
| 1150 | input UnorderedMap<ComponentRef, SetPtr> map; | ||
| 1151 | input Integer size; | ||
| 1152 | output list<AliasSet> sets = {}; | ||
| 1153 | protected | ||
| 1154 | UnorderedSet<ComponentRef> cref_marks = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual, size); | ||
| 1155 | list<tuple<ComponentRef, SetPtr>> entry_lst; | ||
| 1156 | ComponentRef simple_cref; | ||
| 1157 | SetPtr set_ptr; | ||
| 1158 | AliasSet set; | ||
| 1159 | algorithm | ||
| 1160 | 383 | entry_lst := UnorderedMap.toList(map); | |
| 1161 |
2/2✓ Branch 0 taken 2560 times.
✓ Branch 1 taken 383 times.
|
2943 | for entry in entry_lst loop |
| 1162 | 2560 | (simple_cref, set_ptr) := entry; | |
| 1163 |
2/2✓ Branch 1 taken 1107 times.
✓ Branch 2 taken 1453 times.
|
2560 | if not UnorderedSet.contains(simple_cref, cref_marks) then |
| 1164 | 1107 | set := Pointer.access(set_ptr); | |
| 1165 | sets := set :: sets; | ||
| 1166 |
2/2✓ Branch 0 taken 2560 times.
✓ Branch 1 taken 1107 times.
|
3667 | for cr in set.simple_variables loop |
| 1167 | try | ||
| 1168 | 2560 | UnorderedSet.addUnique(cr, cref_marks); | |
| 1169 | else | ||
| 1170 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the set for " + ComponentRef.toString(cr) + " was already added."}); | |
| 1171 | end try; | ||
| 1172 | end for; | ||
| 1173 | end if; | ||
| 1174 | end for; | ||
| 1175 | end getSimpleSets; | ||
| 1176 | |||
| 1177 | function createReplacementRules | ||
| 1178 | "Creates replacement rules from a simple set by causalizing it and replacing the expressions in order" | ||
| 1179 | input AliasSet set; | ||
| 1180 | input Pointer<Integer> index; | ||
| 1181 | input output UnorderedMap<ComponentRef, Expression> replacements; | ||
| 1182 | input Partition.Kind kind; | ||
| 1183 | algorithm | ||
| 1184 | replacements := match set.const_opt | ||
| 1185 | local | ||
| 1186 | Expression rhs; | ||
| 1187 | Equation solved_eq; | ||
| 1188 | Pointer<Equation> const_eq, eq; | ||
| 1189 | list<Pointer<Variable>> alias_vars; | ||
| 1190 | VariablePointers vars; | ||
| 1191 | list<Pointer<Variable>> var_lst; | ||
| 1192 | EquationPointers eqs; | ||
| 1193 | list<Pointer<Equation>> eqns; | ||
| 1194 | list<StrongComponent> comps; | ||
| 1195 | AttributeCollector collector; | ||
| 1196 | Pointer<Pointer<Variable>> var_to_keep = Pointer.create(Pointer.create(NBVariable.DUMMY_VARIABLE)); | ||
| 1197 | Status status; | ||
| 1198 | Expression res, expr; | ||
| 1199 | DifferentiationArguments args; | ||
| 1200 | array<Real> lhs; | ||
| 1201 | Integer idx_i = 1; | ||
| 1202 | list<Integer> lst_enum; | ||
| 1203 | UnorderedMap<ComponentRef, Integer> int_to_cref; | ||
| 1204 | |||
| 1205 | case SOME(const_eq) algorithm | ||
| 1206 | // there is a constant binding -> no variable will be kept and all will be replaced by a constant | ||
| 1207 |
4/4✓ Branch 0 taken 659 times.
✓ Branch 1 taken 486 times.
✓ Branch 2 taken 659 times.
✓ Branch 3 taken 486 times.
|
1145 | vars := VariablePointers.fromList(list(BVariable.getVarPointer(cr, sourceInfo()) for cr in set.simple_variables), true); |
| 1208 | 486 | eqs := EquationPointers.fromList(const_eq :: set.simple_equations); | |
| 1209 | // causalize the system | ||
| 1210 | 486 | (_, comps) := Causalize.simple(vars, eqs, kind); | |
| 1211 | // create replacements from strong components | ||
| 1212 | 486 | Replacements.simple(comps, replacements); | |
| 1213 | then replacements; | ||
| 1214 | |||
| 1215 | case NONE() guard(listLength(set.simple_variables) == listLength(set.simple_equations)) algorithm | ||
| 1216 |
4/4✓ Branch 0 taken 24 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 5 times.
|
29 | vars := VariablePointers.fromList(list(BVariable.getVarPointer(cr, sourceInfo()) for cr in set.simple_variables), true); |
| 1217 | // solve the equation system by performing analytical-to-structural singularity conversion | ||
| 1218 | 5 | eqns := ASSC.main(set.simple_equations, set.simple_variables, index); | |
| 1219 | 3 | eqs := EquationPointers.fromList(eqns); | |
| 1220 | // causalize the system | ||
| 1221 | 3 | (_, comps) := Causalize.simple(vars, eqs, kind); | |
| 1222 | // create replacements from strong components | ||
| 1223 | 3 | Replacements.simple(comps, replacements); | |
| 1224 | then replacements; | ||
| 1225 | |||
| 1226 | else algorithm | ||
| 1227 | // there is no constant binding -> all others will be replaced by one variable | ||
| 1228 |
4/4✓ Branch 0 taken 1877 times.
✓ Branch 1 taken 616 times.
✓ Branch 2 taken 1877 times.
✓ Branch 3 taken 616 times.
|
2493 | (alias_vars, collector) := chooseVariableToKeep(list(BVariable.getVarPointer(cr, sourceInfo()) for cr in set.simple_variables), var_to_keep); |
| 1229 | 616 | vars := VariablePointers.fromList(alias_vars); | |
| 1230 | 616 | eqs := EquationPointers.fromList(set.simple_equations); | |
| 1231 | |||
| 1232 | // causalize the system | ||
| 1233 | 616 | (_, comps) := Causalize.simple(vars, eqs, kind); | |
| 1234 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 616 times.
|
616 | if Flags.isSet(Flags.DEBUG_ALIAS) then |
| 1235 | ✗ | print(StringUtil.headline_3("Variable to keep (values of attributes before replacements):") + BVariable.pointerToString(Pointer.access(var_to_keep))+"\n\n"); | |
| 1236 | end if; | ||
| 1237 | |||
| 1238 | // create replacements from strong components | ||
| 1239 | 616 | Replacements.simple(comps, replacements); | |
| 1240 | 616 | var_lst := VariablePointers.toList(vars); | |
| 1241 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 616 times.
|
616 | if Flags.isSet(Flags.DEBUG_ALIAS) then |
| 1242 | ✗ | print(StringUtil.headline_4("Attribute collector (before replacements): ") + collector.toString(collector) + "\n"); | |
| 1243 | end if; | ||
| 1244 | |||
| 1245 | // solve equations for vars to have attribute conversion rules | ||
| 1246 |
2/2✓ Branch 0 taken 1261 times.
✓ Branch 1 taken 616 times.
|
1877 | for var in var_lst loop |
| 1247 | 1261 | rhs := UnorderedMap.getSafe(BVariable.getVarName(var), replacements, sourceInfo()); | |
| 1248 | 1261 | eq := Equation.makeAssignment(BVariable.toExpression(var), rhs, index, NBEquation.TMP_STR, Iterator.EMPTY(), EquationAttributes.default(EquationKind.UNKNOWN, false)); | |
| 1249 | 1261 | (solved_eq, status, _) := Solve.solveBody(Pointer.access(eq), BVariable.getVarName(Pointer.access(var_to_keep)), UnorderedMap.new<Function>(AbsynUtil.pathHash, AbsynUtil.pathEqual)); | |
| 1250 | 1261 | collector := AttributeCollector.fixValues(collector, BVariable.getVarName(var), solved_eq); | |
| 1251 | end for; | ||
| 1252 | |||
| 1253 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 616 times.
|
616 | if Flags.isSet(Flags.DEBUG_ALIAS) then |
| 1254 | ✗ | print(StringUtil.headline_4("Attribute collector (after replacements): ") + collector.toString(collector) + "\n"); | |
| 1255 | end if; | ||
| 1256 | 616 | diffTearingSelect(collector.tearingSelect_map, set); | |
| 1257 | 616 | stateSelectAlways(collector.stateSelect_map, set); | |
| 1258 | 615 | checkNominalThreshold(collector.nominal_map, set); | |
| 1259 | 615 | setNewAttributes(var_to_keep, collector, set); | |
| 1260 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 615 times.
|
615 | if Flags.isSet(Flags.DEBUG_ALIAS) then |
| 1261 | ✗ | print(StringUtil.headline_3("Variable to keep (values of attributes after replacements):") + BVariable.pointerToString(Pointer.access(var_to_keep))+"\n"); | |
| 1262 | end if; | ||
| 1263 | then replacements; | ||
| 1264 | end match; | ||
| 1265 | end createReplacementRules; | ||
| 1266 | |||
| 1267 | function setNewAttributes | ||
| 1268 | "Sets new values for each attribute of kept variable, if possible. " | ||
| 1269 | input Pointer<Pointer<Variable>> var_to_keep_ptr; | ||
| 1270 | input AttributeCollector attrcollector; | ||
| 1271 | input AliasSet set; | ||
| 1272 | protected | ||
| 1273 | Option<ComponentRef> new_cref; | ||
| 1274 | Option<Expression> new_min, new_max, new_start; | ||
| 1275 | Option<StateSelect> new_stateSelect; | ||
| 1276 | Option<TearingSelect> new_tearingSelect; | ||
| 1277 | Pointer<Variable> fixed_var, var_to_keep = Pointer.access(var_to_keep_ptr); | ||
| 1278 | UnorderedMap<ComponentRef, Expression> fixed_start_map; | ||
| 1279 | algorithm | ||
| 1280 | // function calls of different set functions in NBVariable.mo | ||
| 1281 | 615 | new_min := getMaximum(attrcollector.min_val_map); | |
| 1282 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
✓ Branch 2 taken 88 times.
✓ Branch 3 taken 527 times.
|
615 | if isSome(new_min) then |
| 1283 | 88 | Pointer.update(var_to_keep, BVariable.setMin(Pointer.access(var_to_keep), new_min, true)); | |
| 1284 | 88 | UnorderedMap.add(BVariable.getVarName(var_to_keep), Util.getOption(new_min), attrcollector.min_val_map); // update attribute collector | |
| 1285 | end if; | ||
| 1286 | 615 | new_max := getMinimum(attrcollector.max_val_map); | |
| 1287 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
✓ Branch 2 taken 77 times.
✓ Branch 3 taken 538 times.
|
615 | if isSome(new_max) then |
| 1288 | 77 | Pointer.update(var_to_keep, BVariable.setMax(Pointer.access(var_to_keep), new_max, true)); | |
| 1289 | 77 | UnorderedMap.add(BVariable.getVarName(var_to_keep), Util.getOption(new_max), attrcollector.max_val_map); // update attribute collector | |
| 1290 | end if; | ||
| 1291 | 615 | fixed_start_map := setStartFixed(attrcollector.start_map, attrcollector.fixed_map, set); | |
| 1292 |
4/4✓ Branch 1 taken 611 times.
✓ Branch 2 taken 4 times.
✓ Branch 4 taken 66 times.
✓ Branch 5 taken 545 times.
|
615 | if UnorderedMap.isEmpty(fixed_start_map) and not UnorderedMap.isEmpty(attrcollector.start_map) then |
| 1293 | // no fixed variable in the set: select the start value with the | ||
| 1294 | // strongest confidence as computed by the frontend (MLS 8.6.2) | ||
| 1295 | 66 | new_cref := selectStartByConfidence(attrcollector.start_map, attrcollector.start_binding_map, set); | |
| 1296 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
|
66 | if isSome(new_cref) then |
| 1297 | 66 | new_start := SOME(UnorderedMap.getSafe(Util.getOption(new_cref), attrcollector.start_map, sourceInfo())); | |
| 1298 | 66 | Pointer.update(var_to_keep, BVariable.setStartAttribute(Pointer.access(var_to_keep), Util.getOption(new_start), true)); | |
| 1299 | 66 | UnorderedMap.add(BVariable.getVarName(var_to_keep), Util.getOption(new_start), attrcollector.start_map); // update attribute collector | |
| 1300 | end if; | ||
| 1301 | elseif UnorderedMap.size(fixed_start_map) == 1 then | ||
| 1302 | 4 | new_start := SOME(listHead(UnorderedMap.valueList(fixed_start_map))); | |
| 1303 | 4 | fixed_var := BVariable.getVarPointer(UnorderedMap.firstKey(fixed_start_map), sourceInfo()); | |
| 1304 | 4 | BVariable.setFixed(fixed_var, false, true); // avoid having two fixed variables | |
| 1305 | 4 | UnorderedMap.add(BVariable.getVarName(fixed_var), Expression.BOOLEAN(false), attrcollector.fixed_map); // update attribute collector | |
| 1306 | 4 | BVariable.setFixed(var_to_keep, overwrite=true); | |
| 1307 | 4 | UnorderedMap.add(BVariable.getVarName(var_to_keep), Expression.BOOLEAN(true), attrcollector.fixed_map); // update attribute collector | |
| 1308 | 4 | Pointer.update(var_to_keep, BVariable.setStartAttribute(Pointer.access(var_to_keep), Util.getOption(new_start), true)); | |
| 1309 | 4 | UnorderedMap.add(BVariable.getVarName(var_to_keep), Util.getOption(new_start), attrcollector.start_map); // update attribute collector | |
| 1310 | end if; | ||
| 1311 | 615 | (new_cref, new_stateSelect) := chooseStateSelect(attrcollector.stateSelect_map); | |
| 1312 |
6/8✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 591 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 24 times.
✓ Branch 12 taken 15 times.
✓ Branch 13 taken 9 times.
|
615 | if isSome(new_stateSelect) and isSome(UnorderedMap.get(BVariable.getVarName(var_to_keep),attrcollector.stateSelect_map)) then // only update stateSelect value, if var_to_keep has a stateSelect value |
| 1313 | 15 | Pointer.update(var_to_keep, BVariable.setStateSelect(Pointer.access(var_to_keep), Util.getOption(new_stateSelect), true)); | |
| 1314 | 15 | UnorderedMap.add(BVariable.getVarName(var_to_keep), Util.getOption(new_stateSelect), attrcollector.stateSelect_map); // update attribute collector | |
| 1315 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 14 times.
|
15 | if Util.getOption(new_stateSelect) == StateSelect.ALWAYS then // start value of var with StateSelect = always is stronger than start value of fixed var |
| 1316 | 1 | new_start := SOME(UnorderedMap.getSafe(Util.getOption(new_cref), attrcollector.start_map, sourceInfo())); | |
| 1317 | 1 | Pointer.update(var_to_keep, BVariable.setStartAttribute(Pointer.access(var_to_keep), Util.getOption(new_start), true)); | |
| 1318 | 1 | UnorderedMap.add(BVariable.getVarName(var_to_keep), Util.getOption(new_start), attrcollector.start_map); // update attribute collector | |
| 1319 | end if; | ||
| 1320 | end if; | ||
| 1321 | 615 | new_tearingSelect := chooseTearingSelect(attrcollector.tearingSelect_map); | |
| 1322 |
2/8✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 615 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
615 | if isSome(new_tearingSelect) and isSome(UnorderedMap.get(BVariable.getVarName(var_to_keep),attrcollector.tearingSelect_map)) then // only update tearingSelect value, if var_to_keep has a tearingSelect value |
| 1323 | ✗ | Pointer.update(var_to_keep, BVariable.setTearingSelect(Pointer.access(var_to_keep), Util.getOption(new_tearingSelect), true)); | |
| 1324 | ✗ | UnorderedMap.add(BVariable.getVarName(var_to_keep), Util.getOption(new_tearingSelect), attrcollector.tearingSelect_map); // update attribute collector | |
| 1325 | end if; | ||
| 1326 | 615 | Pointer.update(var_to_keep_ptr,var_to_keep); | |
| 1327 | end setNewAttributes; | ||
| 1328 | |||
| 1329 | function chooseVariableToKeep | ||
| 1330 | "choose a variable from a list to keep. returns all variables but the one with the highest rating" | ||
| 1331 | input list<Pointer<Variable>> var_lst; | ||
| 1332 | input Pointer<Pointer<Variable>> var_to_keep = Pointer.create(Pointer.create(NBVariable.DUMMY_VARIABLE)); | ||
| 1333 | output list<Pointer<Variable>> acc = {}; | ||
| 1334 | output AttributeCollector attrcollector = ATTRIBUTE_COLLECTOR( | ||
| 1335 | UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual), | ||
| 1336 | UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual), | ||
| 1337 | UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual), | ||
| 1338 | UnorderedMap.new<Binding>(ComponentRef.hash, ComponentRef.isEqual), | ||
| 1339 | UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual), | ||
| 1340 | UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual), | ||
| 1341 | UnorderedMap.new<StateSelect>(ComponentRef.hash, ComponentRef.isEqual), | ||
| 1342 | UnorderedMap.new<TearingSelect>(ComponentRef.hash, ComponentRef.isEqual)); | ||
| 1343 | protected | ||
| 1344 | Pointer<Variable> var; | ||
| 1345 | list<Pointer<Variable>> rest; | ||
| 1346 | Integer cur_rating, max_rating; | ||
| 1347 | |||
| 1348 | algorithm | ||
| 1349 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 616 times.
|
616 | var :: rest := var_lst; |
| 1350 | 616 | Pointer.update(var_to_keep, var); | |
| 1351 | 616 | (max_rating, attrcollector) := rateVar(var, attrcollector); | |
| 1352 | |||
| 1353 |
2/2✓ Branch 0 taken 1261 times.
✓ Branch 1 taken 616 times.
|
1877 | for var in rest loop |
| 1354 | 1261 | (cur_rating, attrcollector) := rateVar(var, attrcollector); | |
| 1355 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1213 times.
|
1261 | if cur_rating > max_rating then |
| 1356 | max_rating := cur_rating; | ||
| 1357 | 48 | acc := Pointer.access(var_to_keep) :: acc; | |
| 1358 | 48 | Pointer.update(var_to_keep, var); | |
| 1359 | else | ||
| 1360 | // do not change anything and just keep the variable and max_rating | ||
| 1361 | acc := var :: acc; | ||
| 1362 | end if; | ||
| 1363 | end for; | ||
| 1364 | end chooseVariableToKeep; | ||
| 1365 | |||
| 1366 | function getMaximum | ||
| 1367 | "Gets the maximum value of an UnorderedMap." | ||
| 1368 | input UnorderedMap<ComponentRef,Expression> map; | ||
| 1369 | output Option<Expression> max_exp; | ||
| 1370 | protected | ||
| 1371 | list<Expression> constants, rest, lst_values = UnorderedMap.valueList(map); | ||
| 1372 | Real max_val; | ||
| 1373 | algorithm | ||
| 1374 | 615 | (constants, rest) := List.splitOnTrue(lst_values, Expression.isConstNumber); | |
| 1375 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 545 times.
|
615 | if not listEmpty(constants) then |
| 1376 |
4/4✓ Branch 0 taken 116 times.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 70 times.
|
186 | max_val := List.maxElement(list(Expression.realValue(val) for val in constants), realLt); |
| 1377 | 70 | rest := Expression.REAL(max_val) :: rest; | |
| 1378 | end if; | ||
| 1379 | 615 | rest := List.uniqueOnTrue(rest, Expression.isEqual); | |
| 1380 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 527 times.
|
615 | if listEmpty(rest) then // constants and rest are empty |
| 1381 | max_exp := NONE(); | ||
| 1382 | elseif List.hasOneElement(rest) then // one constant or one rest | ||
| 1383 | 87 | max_exp := SOME(listHead(rest)); | |
| 1384 | else | ||
| 1385 | 1 | max_exp := SOME(makeBoundCall(NFBuiltinFuncs.MAX_REAL, rest)); | |
| 1386 | end if; | ||
| 1387 | end getMaximum; | ||
| 1388 | |||
| 1389 | function getMinimum | ||
| 1390 | "Gets the minimum of an UnorderedMap." | ||
| 1391 | input UnorderedMap<ComponentRef,Expression> map; | ||
| 1392 | output Option<Expression> min_exp; | ||
| 1393 | protected | ||
| 1394 | list<Expression> constants, rest, lst_values = UnorderedMap.valueList(map); | ||
| 1395 | Real min_val; | ||
| 1396 | algorithm | ||
| 1397 | 615 | (constants, rest) := List.splitOnTrue(lst_values, Expression.isConstNumber); | |
| 1398 |
2/2✓ Branch 0 taken 59 times.
✓ Branch 1 taken 556 times.
|
615 | if not listEmpty(constants) then |
| 1399 |
4/4✓ Branch 0 taken 85 times.
✓ Branch 1 taken 59 times.
✓ Branch 2 taken 85 times.
✓ Branch 3 taken 59 times.
|
144 | min_val := List.minElement(list(Expression.realValue(val) for val in constants), realLt); |
| 1400 | 59 | rest := Expression.REAL(min_val) :: rest; | |
| 1401 | end if; | ||
| 1402 | 615 | rest := List.uniqueOnTrue(rest, Expression.isEqual); | |
| 1403 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 538 times.
|
615 | if listEmpty(rest) then // constants and rest are empty |
| 1404 | min_exp := NONE(); | ||
| 1405 | elseif List.hasOneElement(rest) then // one constant or one rest | ||
| 1406 | 76 | min_exp := SOME(listHead(rest)); | |
| 1407 | else | ||
| 1408 | 1 | min_exp := SOME(makeBoundCall(NFBuiltinFuncs.MIN_REAL, rest)); | |
| 1409 | end if; | ||
| 1410 | end getMinimum; | ||
| 1411 | |||
| 1412 | function makeBoundCall | ||
| 1413 | "Calls the scalar min or max function, element-wise for array bounds." | ||
| 1414 | input Function fn; | ||
| 1415 | input list<Expression> args; | ||
| 1416 | output Expression exp; | ||
| 1417 | protected | ||
| 1418 | list<Expression> call_args = args; | ||
| 1419 | list<Dimension> dims = {}; | ||
| 1420 | list<tuple<InstNode, Expression>> iters = {}; | ||
| 1421 | InstNode iter; | ||
| 1422 | Subscript sub; | ||
| 1423 | algorithm | ||
| 1424 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | for arg in args loop |
| 1425 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if Expression.hasArrayType(arg) then |
| 1426 | 2 | dims := Type.arrayDims(Expression.typeOf(arg)); | |
| 1427 | 2 | break; | |
| 1428 | end if; | ||
| 1429 | end for; | ||
| 1430 | |||
| 1431 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | for dim in dims loop |
| 1432 | 2 | iter := InstNode.newUniqueIterator(sourceInfo()); | |
| 1433 | 2 | iters := (iter, Expression.RANGE(Type.ARRAY(Type.INTEGER(), {dim}), Expression.INTEGER(1), NONE(), Dimension.sizeExp(dim))) :: iters; | |
| 1434 | 2 | sub := Subscript.INDEX(Expression.CREF(Type.INTEGER(), ComponentRef.makeIterator(iter, Type.INTEGER()))); | |
| 1435 |
5/6✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
6 | call_args := list(if Expression.hasArrayType(a) then Expression.applySubscript(sub, a) else a for a in call_args); |
| 1436 | end for; | ||
| 1437 | |||
| 1438 | // the scalar min and max take two arguments, nest them for more | ||
| 1439 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | exp :: call_args := listReverse(call_args); |
| 1440 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | for arg in call_args loop |
| 1441 | 2 | exp := Expression.CALL(Call.makeTypedCall(fn, {arg, exp}, Variability.PARAMETER, NFPrefixes.Purity.PURE)); | |
| 1442 | end for; | ||
| 1443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if not listEmpty(dims) then |
| 1444 | 2 | exp := Expression.CALL(Call.TYPED_ARRAY_CONSTRUCTOR(Type.liftArrayLeftList(Expression.typeOf(exp), dims), | |
| 1445 | Variability.PARAMETER, NFPrefixes.Purity.PURE, exp, iters)); | ||
| 1446 | end if; | ||
| 1447 | end makeBoundCall; | ||
| 1448 | |||
| 1449 | function setStartFixed | ||
| 1450 | "Analyses start and fixed values." // case 1: 1 or 0 fixed ; case 2: more than 1 fixed | ||
| 1451 | input UnorderedMap<ComponentRef, Expression> start_map; | ||
| 1452 | input UnorderedMap<ComponentRef, Expression> fixed_map; | ||
| 1453 | input AliasSet set; | ||
| 1454 | output UnorderedMap<ComponentRef, Expression> fixed_start_map = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 1455 | protected | ||
| 1456 | list<tuple<ComponentRef, Expression>> fixed_lst = UnorderedMap.toList(fixed_map); | ||
| 1457 | list<Expression> fixed_start_lst; | ||
| 1458 | Integer count_fixed = 0; | ||
| 1459 | ComponentRef cref; | ||
| 1460 | Expression sval, fval; | ||
| 1461 | algorithm | ||
| 1462 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 615 times.
|
627 | for tpl in fixed_lst loop |
| 1463 | 12 | (cref,fval) := tpl; | |
| 1464 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
|
12 | if Expression.isTrue(fval) then |
| 1465 | 4 | count_fixed := count_fixed + 1; | |
| 1466 | 4 | sval := UnorderedMap.getSafe(cref, start_map, sourceInfo()); | |
| 1467 | 4 | UnorderedMap.add(cref, sval, fixed_start_map); | |
| 1468 | end if; | ||
| 1469 | end for; | ||
| 1470 |
1/2✓ Branch 0 taken 615 times.
✗ Branch 1 not taken.
|
615 | if count_fixed > 1 then |
| 1471 | ✗ | fixed_start_lst := UnorderedMap.valueList(fixed_start_map); | |
| 1472 | ✗ | if not List.allEqual(fixed_start_lst, Expression.isEqual) then | |
| 1473 | // isEqual is syntactic: `true` vs. a parameter cref bound to `true` only looks different. | ||
| 1474 | // Fail only for a provable conflict (all literals), otherwise warn and pick one. | ||
| 1475 | ✗ | if List.all(fixed_start_lst, Expression.isLiteral) then | |
| 1476 | ✗ | if Flags.isSet(Flags.DUMP_REPL) then | |
| 1477 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because multiple variables are fixed with different start values!\n" + AliasSet.toString(set) | |
| 1478 | + "\n\tFixed start map after replacements:\n\t" + UnorderedMap.toString(fixed_start_map, ComponentRef.toString, Expression.toString,"\n\t")}); | ||
| 1479 | ✗ | fail(); | |
| 1480 | else | ||
| 1481 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because multiple variables are fixed with different start values! Use -d=dumprepl for more information.\n"}); | |
| 1482 | ✗ | fail(); | |
| 1483 | end if; | ||
| 1484 | elseif Flags.isSet(Flags.DUMP_REPL) then | ||
| 1485 | ✗ | Error.addCompilerWarning(getInstanceName() + ": Multiple variables are fixed with start values that could not be proven equal; picking one arbitrarily.\n" | |
| 1486 | + AliasSet.toString(set) + "\n\tFixed start map after replacements:\n\t" + UnorderedMap.toString(fixed_start_map, ComponentRef.toString, Expression.toString,"\n\t")); | ||
| 1487 | else | ||
| 1488 | ✗ | Error.addCompilerWarning(getInstanceName() + ": Multiple variables are fixed with start values that could not be proven equal; picking one arbitrarily. Use -d=dumprepl for more information.\n"); | |
| 1489 | end if; | ||
| 1490 | elseif List.allEqual(fixed_start_lst, Expression.isEqual) then | ||
| 1491 | ✗ | if Flags.isSet(Flags.DUMP_REPL) then | |
| 1492 | ✗ | Error.addCompilerWarning(getInstanceName() + ": Multiple variables are fixed and have identical start values.\n" | |
| 1493 | + AliasSet.toString(set) + "\n\tFixed start map after replacements:\n\t" + UnorderedMap.toString(fixed_start_map, ComponentRef.toString, Expression.toString,"\n\t")); | ||
| 1494 | else | ||
| 1495 | ✗ | Error.addCompilerWarning(getInstanceName() + ": Multiple variables are fixed and have identical start values. Use -d=dumprepl for more information.\n"); | |
| 1496 | end if; | ||
| 1497 | end if; | ||
| 1498 | end if; | ||
| 1499 | end setStartFixed; | ||
| 1500 | |||
| 1501 | function selectStartByConfidence | ||
| 1502 | "Selects the start value with the strongest (lowest) confidence | ||
| 1503 | as computed by the frontend, per MLS 8.6.2. Warns if the choice | ||
| 1504 | is ambiguous (equal confidence, conflicting values)." | ||
| 1505 | input UnorderedMap<ComponentRef, Expression> start_map; | ||
| 1506 | input UnorderedMap<ComponentRef, Binding> binding_map; | ||
| 1507 | input AliasSet set; | ||
| 1508 | output Option<ComponentRef> best = NONE(); | ||
| 1509 | protected | ||
| 1510 | ComponentRef cref; | ||
| 1511 | Expression val; | ||
| 1512 | Expression best_val = Expression.INTEGER(0); | ||
| 1513 | Binding b, best_b = NFBinding.EMPTY_BINDING; | ||
| 1514 | Integer cmp; | ||
| 1515 | Boolean tie = false; | ||
| 1516 | algorithm | ||
| 1517 |
2/2✓ Branch 1 taken 105 times.
✓ Branch 2 taken 66 times.
|
171 | for tpl in UnorderedMap.toList(start_map) loop |
| 1518 | 105 | (cref, val) := tpl; | |
| 1519 | 105 | b := UnorderedMap.getSafe(cref, binding_map, sourceInfo()); | |
| 1520 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 66 times.
|
105 | cmp := if isNone(best) then -1 else Binding.compareStartConfidence(b, best_b); |
| 1521 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 32 times.
|
39 | if cmp < 0 then |
| 1522 | 73 | (best, best_val, best_b) := (SOME(cref), val, b); | |
| 1523 | tie := false; | ||
| 1524 | elseif cmp == 0 and not Expression.isEqual(val, best_val) then | ||
| 1525 | tie := true; | ||
| 1526 | end if; | ||
| 1527 | end for; | ||
| 1528 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 6 times.
|
66 | if tie then |
| 1529 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 5 times.
|
6 | if Flags.isSet(Flags.DUMP_REPL) then |
| 1530 | 1 | Error.addCompilerWarning(getInstanceName() + ": Alias set with conflicting unfixed start values of equal confidence detected.\n" | |
| 1531 | + AliasSet.toString(set) + "\n\tStart map after replacements:\n\t" + UnorderedMap.toString(start_map, ComponentRef.toString, Expression.toString,"\n\t")); | ||
| 1532 | else | ||
| 1533 | 5 | Error.addCompilerWarning(getInstanceName() + ": Alias set with conflicting unfixed start values of equal confidence detected. Use -d=dumprepl for more information.\n"); | |
| 1534 | end if; | ||
| 1535 | end if; | ||
| 1536 | end selectStartByConfidence; | ||
| 1537 | |||
| 1538 | function checkNominalThreshold | ||
| 1539 | "Calculates quotient of greatest and lowest nominal value and checks if quotient is above the constant NOMINAL_THRESHOLD." | ||
| 1540 | input UnorderedMap<ComponentRef, Expression> map; | ||
| 1541 | input AliasSet set; | ||
| 1542 | protected | ||
| 1543 | list<Expression> current, lst_values = UnorderedMap.valueList(map); | ||
| 1544 | array<ExpressionIterator> arr_iter; | ||
| 1545 | ExpressionIterator iter; | ||
| 1546 | Expression exp; | ||
| 1547 | Integer index = 1; | ||
| 1548 | algorithm | ||
| 1549 | // if there are no values to compare, return | ||
| 1550 |
2/2✓ Branch 0 taken 535 times.
✓ Branch 1 taken 80 times.
|
615 | if listEmpty(lst_values) then return; end if; |
| 1551 | |||
| 1552 | // all expressions have to be of same size | ||
| 1553 |
5/6✓ Branch 0 taken 125 times.
✓ Branch 1 taken 80 times.
✓ Branch 2 taken 125 times.
✓ Branch 3 taken 80 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 80 times.
|
205 | if not List.allEqual(list(Type.sizeOf(Expression.typeOf(e)) for e in lst_values), intEq) then |
| 1554 | ✗ | Error.addCompilerWarning(getInstanceName() + " failed because array nominal values have different size. Use -d=dumprepl for more information.\n"); | |
| 1555 | ✗ | fail(); | |
| 1556 | end if; | ||
| 1557 | |||
| 1558 | // array handling: create expression iterators and loop while there is a next element | ||
| 1559 |
4/4✓ Branch 0 taken 125 times.
✓ Branch 1 taken 80 times.
✓ Branch 2 taken 125 times.
✓ Branch 3 taken 80 times.
|
205 | arr_iter := listArray(list(ExpressionIterator.fromExp(e) for e in lst_values)); |
| 1560 | |||
| 1561 |
2/2✓ Branch 1 taken 92 times.
✓ Branch 2 taken 80 times.
|
172 | while ExpressionIterator.hasNext(arr_iter[1]) loop |
| 1562 | // get all single expressions and compare | ||
| 1563 | current := {}; | ||
| 1564 |
1/2✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
|
234 | for i in 1:arrayLength(arr_iter) loop |
| 1565 | 142 | (iter, exp) := ExpressionIterator.next(arr_iter[i]); | |
| 1566 | 142 | arrayUpdate(arr_iter, i, iter); | |
| 1567 | 142 | current := exp :: current; | |
| 1568 | end for; | ||
| 1569 | // 'current' now represents all values of one array element | ||
| 1570 | 92 | checkNominalThresholdSingle(current, map, set, index); | |
| 1571 | 92 | index := index + 1; | |
| 1572 | end while; | ||
| 1573 | end checkNominalThreshold; | ||
| 1574 | |||
| 1575 | function checkNominalThresholdSingle | ||
| 1576 | "check the nominal of each single value" | ||
| 1577 | input list<Expression> lst_values; | ||
| 1578 | input UnorderedMap<ComponentRef, Expression> map; | ||
| 1579 | input AliasSet set; | ||
| 1580 | input Integer index; | ||
| 1581 | protected | ||
| 1582 | list<Expression> constants, rest, zeroes; | ||
| 1583 | list<Real> real_constants; | ||
| 1584 | Real nom_min, nom_max, nom_quotient; | ||
| 1585 | String str; | ||
| 1586 | algorithm | ||
| 1587 | // split by constant and non constant | ||
| 1588 | 92 | (constants, rest) := List.splitOnTrue(lst_values, Expression.isConstNumber); | |
| 1589 | // remove and report zeros | ||
| 1590 | 92 | (zeroes, constants) := List.splitOnTrue(constants, Expression.isZero); | |
| 1591 | |||
| 1592 | // report non literal nominal values if failtrace is activated | ||
| 1593 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 92 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
92 | if Flags.isSet(Flags.FAILTRACE) and not listEmpty(rest) then |
| 1594 | ✗ | str := getInstanceName() + ": There are non literal nominal values in following alias set:\n" | |
| 1595 | + AliasSet.toString(set) + "\n\tNominal map after replacements (conflicting array index = " | ||
| 1596 | + intString(index) + "):\n\t" + UnorderedMap.toString(map, ComponentRef.toString, Expression.toString,"\n\t"); | ||
| 1597 | ✗ | Error.addCompilerWarning(str); | |
| 1598 | end if; | ||
| 1599 | |||
| 1600 | // report nominal values that are too far apart | ||
| 1601 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 2 times.
|
92 | if not listEmpty(constants) then |
| 1602 |
4/4✓ Branch 0 taken 140 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 140 times.
✓ Branch 3 taken 90 times.
|
230 | real_constants := list(abs(Expression.realValue(val)) for val in constants); |
| 1603 | 90 | nom_min := List.minElement(real_constants, realLt); | |
| 1604 | 90 | nom_max := List.maxElement(real_constants, realLt); | |
| 1605 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
|
90 | nom_quotient := nom_max / nom_min; |
| 1606 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 89 times.
|
90 | if nom_quotient > NOMINAL_THRESHOLD then |
| 1607 | str := getInstanceName() + ": The quotient of the greatest and lowest nominal value is greater than the nominal threshold = "+ realString(NOMINAL_THRESHOLD) + "."; | ||
| 1608 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
1 | if Flags.isSet(Flags.DUMP_REPL) then |
| 1609 | 1 | str := str + "\n" + AliasSet.toString(set) + "\n\tNominal map after replacements (conflicting array index = " | |
| 1610 | + intString(index) + "):\n\t" + UnorderedMap.toString(map, ComponentRef.toString, Expression.toString,"\n\t"); | ||
| 1611 | else | ||
| 1612 | ✗ | str := str + " Use -d=dumprepl for more information.\n"; | |
| 1613 | end if; | ||
| 1614 | 1 | Error.addCompilerWarning(str); | |
| 1615 | end if; | ||
| 1616 | end if; | ||
| 1617 | |||
| 1618 | // zero valued nominal values are invalid, but the models still work, so they are only reported | ||
| 1619 |
1/2✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
|
92 | if not listEmpty(zeroes) then |
| 1620 | str := getInstanceName() + ": Zero valued nominal values are not allowed."; | ||
| 1621 | ✗ | if Flags.isSet(Flags.DUMP_REPL) then | |
| 1622 | ✗ | str := str + "\n\tNominal map after replacements (violating array index = " + intString(index) + "):\n\t" | |
| 1623 | + UnorderedMap.toString(map, ComponentRef.toString, Expression.toString,"\n\t"); | ||
| 1624 | else | ||
| 1625 | ✗ | str := str + " Use -d=dumprepl for more information.\n"; | |
| 1626 | end if; | ||
| 1627 | ✗ | Error.addCompilerWarning(str); | |
| 1628 | end if; | ||
| 1629 | end checkNominalThresholdSingle; | ||
| 1630 | |||
| 1631 | function stateSelectAlways | ||
| 1632 | "Throws an error if multiple variables have StateSelect = always." | ||
| 1633 | input UnorderedMap<ComponentRef, StateSelect> map; | ||
| 1634 | input AliasSet set; | ||
| 1635 | protected | ||
| 1636 | list<StateSelect> lst_values = UnorderedMap.valueList(map); | ||
| 1637 | Integer count = 0; | ||
| 1638 | algorithm | ||
| 1639 |
2/2✓ Branch 0 taken 27 times.
✓ Branch 1 taken 616 times.
|
643 | for val in lst_values loop |
| 1640 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24 times.
|
27 | if val == StateSelect.ALWAYS then |
| 1641 | 3 | count := count + 1; | |
| 1642 | end if; | ||
| 1643 | end for; | ||
| 1644 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 615 times.
|
616 | if count > 1 then |
| 1645 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
1 | if Flags.isSet(Flags.DUMP_REPL) then |
| 1646 | 2 | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because multiple variables have StateSelect = always!\n" + AliasSet.toString(set) | |
| 1647 | + "\n\tStateSelect map after replacements:\n\t" + UnorderedMap.toString(map, ComponentRef.toString, BackendExtension.VariableAttributes.stateSelectString,"\n\t")}); | ||
| 1648 | 1 | fail(); | |
| 1649 | else | ||
| 1650 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because multiple variables have StateSelect = always! Use -d=dumprepl for more information.\n"}); | |
| 1651 | ✗ | fail(); | |
| 1652 | end if; | ||
| 1653 | end if; | ||
| 1654 | end stateSelectAlways; | ||
| 1655 | |||
| 1656 | function diffTearingSelect | ||
| 1657 | "Shows a notification if there are different TearingSelect values." | ||
| 1658 | input UnorderedMap<ComponentRef, TearingSelect> map; | ||
| 1659 | input AliasSet set; | ||
| 1660 | protected | ||
| 1661 | list<TearingSelect> lst_values = UnorderedMap.valueList(map); | ||
| 1662 | TearingSelect first; | ||
| 1663 | list<TearingSelect> rest; | ||
| 1664 | Boolean equal = true; | ||
| 1665 | algorithm | ||
| 1666 |
1/2✓ Branch 0 taken 616 times.
✗ Branch 1 not taken.
|
616 | if not listEmpty(lst_values) then |
| 1667 | ✗ | first :: rest := lst_values; | |
| 1668 | ✗ | for val in rest loop | |
| 1669 | ✗ | if first <> val then | |
| 1670 | equal := false; | ||
| 1671 | break; | ||
| 1672 | end if; | ||
| 1673 | end for; | ||
| 1674 | ✗ | if not equal then | |
| 1675 | ✗ | if Flags.isSet(Flags.DUMP_REPL) then | |
| 1676 | ✗ | Error.addCompilerNotification("There are different TearingSelect values.\n" + AliasSet.toString(set) + "\n\tTearingSelect map after replacements:\n\t" | |
| 1677 | + UnorderedMap.toString(map, ComponentRef.toString, BackendExtension.VariableAttributes.tearingSelectString,"\n\t")); | ||
| 1678 | else | ||
| 1679 | ✗ | Error.addCompilerNotification("There are different TearingSelect values. Use -d=dumprepl for more information.\n"); | |
| 1680 | end if; | ||
| 1681 | end if; | ||
| 1682 | end if; | ||
| 1683 | end diffTearingSelect; | ||
| 1684 | |||
| 1685 | function chooseStateSelect | ||
| 1686 | "Chooses the StateSelect value with the highest rank among all StateSelect values." | ||
| 1687 | input UnorderedMap<ComponentRef, StateSelect> map; | ||
| 1688 | output Option<ComponentRef> chosen_cref; | ||
| 1689 | output Option<StateSelect> chosen_val; | ||
| 1690 | protected | ||
| 1691 | list<tuple<ComponentRef,StateSelect>> lst_values = UnorderedMap.toList(map); | ||
| 1692 | StateSelect sval, state_select = StateSelect.NEVER; | ||
| 1693 | ComponentRef compref, cref; | ||
| 1694 | algorithm | ||
| 1695 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 591 times.
|
615 | if listEmpty(lst_values) then |
| 1696 | chosen_val := NONE(); | ||
| 1697 | chosen_cref := NONE(); | ||
| 1698 | elseif List.hasOneElement(lst_values) then | ||
| 1699 | 23 | (compref, sval) := listHead(lst_values); | |
| 1700 | chosen_val := SOME(sval); | ||
| 1701 | chosen_cref := SOME(compref); | ||
| 1702 | else | ||
| 1703 | 1 | (compref, state_select) := listHead(lst_values); | |
| 1704 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
|
3 | for tpl in lst_values loop |
| 1705 | 2 | (cref,sval) := tpl; | |
| 1706 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
2 | if sval > state_select then |
| 1707 | state_select := sval; | ||
| 1708 | compref := cref; | ||
| 1709 | end if; | ||
| 1710 | end for; | ||
| 1711 | chosen_val := SOME(state_select); | ||
| 1712 | chosen_cref := SOME(compref); | ||
| 1713 | end if; | ||
| 1714 | end chooseStateSelect; | ||
| 1715 | |||
| 1716 | function chooseTearingSelect | ||
| 1717 | "Chooses the TearingSelect value with the highest rank among all TearingSelect values." | ||
| 1718 | input UnorderedMap<ComponentRef, TearingSelect> map; | ||
| 1719 | output Option<TearingSelect> chosen_val; | ||
| 1720 | protected | ||
| 1721 | list<TearingSelect> lst_values = UnorderedMap.valueList(map); | ||
| 1722 | TearingSelect tearing_select; | ||
| 1723 | algorithm | ||
| 1724 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 615 times.
|
615 | if listEmpty(lst_values) then |
| 1725 | chosen_val := NONE(); | ||
| 1726 | elseif List.hasOneElement(lst_values) then | ||
| 1727 | ✗ | chosen_val := SOME(listHead(lst_values)); | |
| 1728 | else | ||
| 1729 | tearing_select := TearingSelect.NEVER; | ||
| 1730 | ✗ | for val in lst_values loop | |
| 1731 | ✗ | if val > tearing_select then | |
| 1732 | tearing_select := val; | ||
| 1733 | end if; | ||
| 1734 | end for; | ||
| 1735 | chosen_val := SOME(tearing_select); | ||
| 1736 | end if; | ||
| 1737 | end chooseTearingSelect; | ||
| 1738 | |||
| 1739 | function mean // better: geometric mean | ||
| 1740 | "Calculates the mean of values" | ||
| 1741 | input list<Expression> lst; | ||
| 1742 | output Real mean_val; | ||
| 1743 | protected | ||
| 1744 | Real cur_sum; | ||
| 1745 | algorithm | ||
| 1746 | ✗ | cur_sum := sum(Expression.realValue(val) for val in lst); | |
| 1747 | ✗ | mean_val := cur_sum / listLength(lst); | |
| 1748 | ✗ | print("Mean = " + String(mean_val)); | |
| 1749 | end mean; | ||
| 1750 | |||
| 1751 | function optionMinMax | ||
| 1752 | "Collects min and max attributes if available." | ||
| 1753 | input Pointer<Variable> var_ptr; | ||
| 1754 | input Option<Binding> attr_min, attr_max; | ||
| 1755 | input output AttributeCollector attrcollector; | ||
| 1756 | protected | ||
| 1757 | Binding min_b, max_b; | ||
| 1758 | algorithm | ||
| 1759 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1729 times.
✓ Branch 2 taken 147 times.
✓ Branch 3 taken 1582 times.
|
1729 | if isSome(attr_min) then |
| 1760 | 147 | SOME(min_b) := attr_min; | |
| 1761 | 147 | UnorderedMap.add(BVariable.getVarName(var_ptr), Binding.getTypedExp(min_b), attrcollector.min_val_map); | |
| 1762 | end if; | ||
| 1763 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1729 times.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 1613 times.
|
1729 | if isSome(attr_max) then |
| 1764 | 116 | SOME(max_b) := attr_max; | |
| 1765 | 116 | UnorderedMap.add(BVariable.getVarName(var_ptr), Binding.getTypedExp(max_b), attrcollector.max_val_map); | |
| 1766 | end if; | ||
| 1767 | end optionMinMax; | ||
| 1768 | |||
| 1769 | function isAuxStart | ||
| 1770 | "true if the start value is the call of a function alias variable" | ||
| 1771 | input Expression exp; | ||
| 1772 | output Boolean b; | ||
| 1773 | algorithm | ||
| 1774 | b := match exp | ||
| 1775 | case Expression.CALL() then true; | ||
| 1776 | ✗ | case Expression.RECORD_ELEMENT() then Expression.isCall(exp.recordExp); | |
| 1777 | 6 | case Expression.TUPLE_ELEMENT() then Expression.isCall(exp.tupleExp); | |
| 1778 | // the start value of a call in a for equation with an array result | ||
| 1779 | 6 | case Expression.ARRAY() then Array.all(exp.elements, isAuxStart); | |
| 1780 | else false; | ||
| 1781 | end match; | ||
| 1782 | end isAuxStart; | ||
| 1783 | |||
| 1784 | function optionStartFixed | ||
| 1785 | "Collects start and fixed attributes if available." | ||
| 1786 | input Pointer<Variable> var_ptr; | ||
| 1787 | input Option<Binding> attr_start, attr_fixed; | ||
| 1788 | input output AttributeCollector attrcollector; | ||
| 1789 | protected | ||
| 1790 | Binding start_b, fixed_b; | ||
| 1791 | algorithm | ||
| 1792 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1825 times.
✓ Branch 2 taken 153 times.
✓ Branch 3 taken 1672 times.
|
1825 | if isSome(attr_start) then |
| 1793 | 153 | SOME(start_b) := attr_start; | |
| 1794 | // the generated start values of function alias variables (see NBFunctionAlias) are only guesses | ||
| 1795 |
5/6✓ Branch 1 taken 46 times.
✓ Branch 2 taken 107 times.
✓ Branch 4 taken 46 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 44 times.
|
153 | if not (BVariable.isFunctionAlias(var_ptr) and Binding.source(start_b) == NFBinding.Source.GENERATED and isAuxStart(Binding.getTypedExp(start_b))) then |
| 1796 | 109 | UnorderedMap.add(BVariable.getVarName(var_ptr), Binding.getTypedExp(start_b), attrcollector.start_map); | |
| 1797 | 109 | UnorderedMap.add(BVariable.getVarName(var_ptr), start_b, attrcollector.start_binding_map); | |
| 1798 | end if; | ||
| 1799 | end if; | ||
| 1800 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1825 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 1813 times.
|
1825 | if isSome(attr_fixed) then |
| 1801 | 12 | SOME(fixed_b) := attr_fixed; | |
| 1802 | 12 | UnorderedMap.add(BVariable.getVarName(var_ptr), Binding.getTypedExp(fixed_b), attrcollector.fixed_map); | |
| 1803 | end if; | ||
| 1804 | end optionStartFixed; | ||
| 1805 | |||
| 1806 | function rateVar | ||
| 1807 | "Rates a variable based on attributes" | ||
| 1808 | input Pointer<Variable> var_ptr; | ||
| 1809 | output Integer rating; | ||
| 1810 | input output AttributeCollector attrcollector; | ||
| 1811 | protected | ||
| 1812 | ComponentRef name; | ||
| 1813 | Expression nominal_val; | ||
| 1814 | StateSelect stateSelect_val; | ||
| 1815 | TearingSelect tearingSelect_val; | ||
| 1816 | algorithm | ||
| 1817 |
3/4✓ Branch 1 taken 1706 times.
✓ Branch 2 taken 171 times.
✓ Branch 4 taken 1706 times.
✗ Branch 5 not taken.
|
1877 | if BVariable.isFunctionAlias(var_ptr) or BVariable.isClockAlias(var_ptr) then |
| 1818 | rating := -10000; | ||
| 1819 | else | ||
| 1820 | 1706 | name := BVariable.getVarName(var_ptr); | |
| 1821 | 1706 | rating := -ComponentRef.depth(name); | |
| 1822 | end if; | ||
| 1823 | |||
| 1824 | () := match Pointer.access(var_ptr) | ||
| 1825 | local | ||
| 1826 | BackendExtension.VariableAttributes attr; | ||
| 1827 | |||
| 1828 | case Variable.VARIABLE(backendinfo=BackendExtension.BACKEND_INFO(attributes=attr as BackendExtension.VariableAttributes.VAR_ATTR_REAL())) algorithm | ||
| 1829 | 1691 | attrcollector := optionMinMax(var_ptr, attr.min, attr.max, attrcollector); | |
| 1830 | 1691 | attrcollector := optionStartFixed(var_ptr, attr.start, attr.fixed, attrcollector); | |
| 1831 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1691 times.
✓ Branch 2 taken 125 times.
✓ Branch 3 taken 1566 times.
|
1691 | if isSome(attr.nominal) then |
| 1832 | 125 | nominal_val := Binding.getTypedExp(Util.getOption(attr.nominal)); | |
| 1833 | 125 | UnorderedMap.add(BVariable.getVarName(var_ptr), nominal_val, attrcollector.nominal_map); | |
| 1834 | end if; | ||
| 1835 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1691 times.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 1664 times.
|
1691 | if isSome(attr.stateSelect) then |
| 1836 | 27 | stateSelect_val := Util.getOption(attr.stateSelect); | |
| 1837 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 24 times.
|
27 | if stateSelect_val == StateSelect.ALWAYS then |
| 1838 | 3 | rating := rating + 100; | |
| 1839 | elseif stateSelect_val == StateSelect.PREFER then | ||
| 1840 | 6 | rating := rating + 50; | |
| 1841 | end if; | ||
| 1842 | 27 | UnorderedMap.add(BVariable.getVarName(var_ptr), stateSelect_val, attrcollector.stateSelect_map); | |
| 1843 | end if; | ||
| 1844 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1691 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1691 times.
|
1691 | if isSome(attr.tearingSelect) then |
| 1845 | ✗ | tearingSelect_val := Util.getOption(attr.tearingSelect); | |
| 1846 | ✗ | UnorderedMap.add(BVariable.getVarName(var_ptr), tearingSelect_val, attrcollector.tearingSelect_map); | |
| 1847 | end if; | ||
| 1848 | then (); | ||
| 1849 | |||
| 1850 | case Variable.VARIABLE(backendinfo=BackendExtension.BACKEND_INFO(attributes=attr as BackendExtension.VariableAttributes.VAR_ATTR_INT())) algorithm | ||
| 1851 | 38 | attrcollector := optionMinMax(var_ptr, attr.min, attr.max, attrcollector); | |
| 1852 | 38 | attrcollector := optionStartFixed(var_ptr, attr.start, attr.fixed, attrcollector); | |
| 1853 | then (); | ||
| 1854 | |||
| 1855 | case Variable.VARIABLE(backendinfo=BackendExtension.BACKEND_INFO(attributes=attr as BackendExtension.VariableAttributes.VAR_ATTR_BOOL())) algorithm | ||
| 1856 | 96 | attrcollector := optionStartFixed(var_ptr, attr.start, attr.fixed, attrcollector); | |
| 1857 | then (); | ||
| 1858 | |||
| 1859 | else (); | ||
| 1860 | end match; | ||
| 1861 | end rateVar; | ||
| 1862 | |||
| 1863 | uniontype AttributeCollector | ||
| 1864 | record ATTRIBUTE_COLLECTOR | ||
| 1865 | UnorderedMap<ComponentRef,Expression> min_val_map "set containing all minimum values"; | ||
| 1866 | UnorderedMap<ComponentRef,Expression> max_val_map "set containing all maximum values"; | ||
| 1867 | UnorderedMap<ComponentRef,Expression> start_map "set containing all start values"; | ||
| 1868 | UnorderedMap<ComponentRef,Binding> start_binding_map "start bindings, for their confidence"; | ||
| 1869 | UnorderedMap<ComponentRef,Expression> fixed_map "set containing all fixed values"; | ||
| 1870 | UnorderedMap<ComponentRef,Expression> nominal_map "set containing all nominal values"; | ||
| 1871 | UnorderedMap<ComponentRef,StateSelect> stateSelect_map "set containing all stateSelect values"; | ||
| 1872 | UnorderedMap<ComponentRef,TearingSelect> tearingSelect_map "set containing all tearingSelect values"; | ||
| 1873 | end ATTRIBUTE_COLLECTOR; | ||
| 1874 | |||
| 1875 | function toString | ||
| 1876 | "Prints all sets of AttributeCollector" | ||
| 1877 | input AttributeCollector attrcollector; | ||
| 1878 | input output String str = ""; | ||
| 1879 | protected | ||
| 1880 | array<UnorderedMap<ComponentRef,Expression>> array_maps; | ||
| 1881 | array<String> array_names; | ||
| 1882 | algorithm | ||
| 1883 | ✗ | array_maps := listArray({attrcollector.min_val_map, attrcollector.max_val_map, attrcollector.start_map, attrcollector.fixed_map, attrcollector.nominal_map}); | |
| 1884 | ✗ | array_names := listArray({"Min map", "Max map", "Start map", "Fixed map", "Nominal map"}); | |
| 1885 | ✗ | for i in 1:arrayLength(array_maps) loop | |
| 1886 | ✗ | if UnorderedMap.isEmpty(array_maps[i]) == false then | |
| 1887 | ✗ | str := str + arrayGet(array_names, i) + ":\n\t"+ UnorderedMap.toString(array_maps[i], ComponentRef.toString, Expression.toString, "\n\t") + "\n"; | |
| 1888 | end if; | ||
| 1889 | end for; | ||
| 1890 | ✗ | if UnorderedMap.isEmpty(attrcollector.stateSelect_map) == false then | |
| 1891 | ✗ | str := str + "StateSelect map" + ":\n\t"+ UnorderedMap.toString(attrcollector.stateSelect_map, ComponentRef.toString, BackendExtension.VariableAttributes.stateSelectString, "\n\t") + "\n"; | |
| 1892 | end if; | ||
| 1893 | ✗ | if UnorderedMap.isEmpty(attrcollector.tearingSelect_map) == false then | |
| 1894 | ✗ | str := str + "TearingSelect map" + ":\n\t"+ UnorderedMap.toString(attrcollector.tearingSelect_map, ComponentRef.toString, BackendExtension.VariableAttributes.tearingSelectString, "\n\t") + "\n"; | |
| 1895 | end if; | ||
| 1896 | end toString; | ||
| 1897 | |||
| 1898 | function fixValues | ||
| 1899 | "Adapts min, max and start values of each variable according to the replacements." | ||
| 1900 | input output AttributeCollector attrcollector; | ||
| 1901 | input ComponentRef var_cref; | ||
| 1902 | input Equation solved_eq; | ||
| 1903 | protected | ||
| 1904 | UnorderedMap<ComponentRef, Expression> repl = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 1905 | Expression rhs, new_rhs, diff_rhs; | ||
| 1906 | DifferentiationArguments args; | ||
| 1907 | Boolean swap_min_max; | ||
| 1908 | Option<Expression> min_val_opt = UnorderedMap.get(var_cref, attrcollector.min_val_map); | ||
| 1909 | Option<Expression> max_val_opt = UnorderedMap.get(var_cref, attrcollector.max_val_map); | ||
| 1910 | Option<Expression> start_opt = UnorderedMap.get(var_cref, attrcollector.start_map); | ||
| 1911 | Option<Expression> nominal_opt = UnorderedMap.get(var_cref, attrcollector.nominal_map); | ||
| 1912 | Type ty; | ||
| 1913 | algorithm | ||
| 1914 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 1261 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1261 times.
|
1261 | SOME(rhs) := Equation.getRHS(solved_eq); |
| 1915 | // min: | ||
| 1916 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1261 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 1196 times.
|
1261 | if isSome(min_val_opt) then |
| 1917 | 65 | UnorderedMap.add(var_cref, Util.getOption(min_val_opt), repl); | |
| 1918 | 65 | new_rhs := Expression.map(rhs, function Replacements.applySimpleExp(replacements = repl)); | |
| 1919 | 65 | new_rhs := SimplifyExp.simplify(new_rhs); | |
| 1920 | 65 | UnorderedMap.add(var_cref, new_rhs, attrcollector.min_val_map); | |
| 1921 | 65 | min_val_opt := UnorderedMap.get(var_cref, attrcollector.min_val_map); | |
| 1922 | end if; | ||
| 1923 | |||
| 1924 | // max: | ||
| 1925 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1261 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 1217 times.
|
1261 | if isSome(max_val_opt) then |
| 1926 | 44 | UnorderedMap.add(var_cref, Util.getOption(max_val_opt), repl); | |
| 1927 | 44 | new_rhs := Expression.map(rhs, function Replacements.applySimpleExp(replacements = repl)); | |
| 1928 | 44 | new_rhs := SimplifyExp.simplify(new_rhs); | |
| 1929 | 44 | UnorderedMap.add(var_cref, new_rhs, attrcollector.max_val_map); | |
| 1930 | 44 | max_val_opt := UnorderedMap.get(var_cref, attrcollector.max_val_map); | |
| 1931 | end if; | ||
| 1932 | |||
| 1933 | // if linear factor is negative => swap min and max. skip discontinuous and record types | ||
| 1934 | 1261 | ty := Expression.typeOf(rhs); | |
| 1935 |
3/6✓ Branch 1 taken 1174 times.
✓ Branch 2 taken 87 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1174 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
1261 | if not Type.isContinuous(ty) or not Type.isInteger(Type.elementType(ty)) or Type.isRecord(ty) then |
| 1936 | swap_min_max := false; | ||
| 1937 | else | ||
| 1938 | ✗ | args := Differentiate.DifferentiationArguments.default(NBDifferentiate.DifferentiationType.SIMPLE); | |
| 1939 | ✗ | args.diffCref := var_cref; | |
| 1940 | ✗ | diff_rhs := Differentiate.differentiateExpression(rhs, args); | |
| 1941 | ✗ | diff_rhs := SimplifyExp.simplify(diff_rhs); | |
| 1942 | ✗ | swap_min_max := Expression.isNegative(diff_rhs); | |
| 1943 | end if; | ||
| 1944 | ✗ | if swap_min_max and isSome(min_val_opt) and isSome(max_val_opt) then | |
| 1945 | ✗ | UnorderedMap.add(var_cref, Util.getOption(max_val_opt), attrcollector.min_val_map); | |
| 1946 | ✗ | UnorderedMap.add(var_cref, Util.getOption(min_val_opt), attrcollector.max_val_map); | |
| 1947 | end if; | ||
| 1948 | |||
| 1949 | // start: | ||
| 1950 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1261 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 1212 times.
|
1261 | if isSome(start_opt) then |
| 1951 | 49 | UnorderedMap.add(var_cref, Util.getOption(start_opt), repl); | |
| 1952 | 49 | new_rhs := Expression.map(rhs, function Replacements.applySimpleExp(replacements = repl)); | |
| 1953 | 49 | new_rhs := SimplifyExp.simplify(new_rhs); | |
| 1954 | 49 | UnorderedMap.add(var_cref, new_rhs, attrcollector.start_map); | |
| 1955 | end if; | ||
| 1956 | |||
| 1957 | // nominal: | ||
| 1958 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1261 times.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 1207 times.
|
1261 | if isSome(nominal_opt) then |
| 1959 | 54 | UnorderedMap.add(var_cref, Util.getOption(nominal_opt), repl); | |
| 1960 | 54 | new_rhs := Expression.map(rhs, function Replacements.applySimpleExp(replacements = repl)); | |
| 1961 | // normalize the nominal values (remove negations) | ||
| 1962 | 54 | new_rhs := Expression.getNominal(new_rhs); | |
| 1963 | 54 | UnorderedMap.add(var_cref, new_rhs, attrcollector.nominal_map); | |
| 1964 | end if; | ||
| 1965 | end fixValues; | ||
| 1966 | |||
| 1967 | end AttributeCollector; | ||
| 1968 | |||
| 1969 | annotation(__OpenModelica_Interface="nbackend"); | ||
| 1970 | end NBAlias; | ||
| 1971 |