Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 85.5% 482 / 0 / 564
Functions: -% 0 / 1 / 1
Branches: 73.1% 370 / 0 / 506

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