Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 58.7% 753 / 0 / 1282
Functions: -% 0 / 1 / 1
Branches: 56.3% 596 / 0 / 1059

OMCompiler/Compiler/NBackEnd/Classes/NBEquation.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 NBEquation
37 " file: NBEquation.mo
38 package: NBEquation
39 description: This file contains all functions and structures regarding
40 backend equations.
41 "
42
43 public
44 // Old Frontend imports
45 import Absyn.Path;
46 import DAE;
47 import ElementSource;
48
49 // New Frontend imports
50 import Algorithm = NFAlgorithm;
51 import BackendDAE = NBackendDAE;
52 import NFBackendExtension.{VariableAttributes, OptimizerExpression};
53 import Binding = NFBinding;
54 import Call = NFCall;
55 import Class = NFClass;
56 import ComplexType = NFComplexType;
57 import ComponentRef = NFComponentRef;
58 import Dimension = NFDimension;
59 import Expression = NFExpression;
60 import NFFunction.Function;
61 import InstNode = NFInstNode.InstNode;
62 import NFInstNode;
63 import MutableWeak;
64 import Operator = NFOperator;
65 import NFPrefixes.{Variability, Purity};
66 import SimplifyExp = NFSimplifyExp;
67 import SimplifyModel = NFSimplifyModel;
68 import Statement = NFStatement;
69 import Subscript = NFSubscript;
70 import Type = NFType;
71 import Typing = NFTyping;
72 import Variable = NFVariable;
73
74 // Old Backend imports
75 import OldBackendDAE = BackendDAE;
76
77 // New Backend imports
78 import DetectStates = NBDetectStates;
79 import NBResizable.EvalOrder;
80 import Evaluation = NBEvaluation;
81 import Inline = NBInline;
82 import Replacements = NBReplacements;
83 import StrongComponent = NBStrongComponent;
84 import Solve = NBSolve;
85 import BVariable = NBVariable;
86 import NBVariable.{VariablePointer, VariablePointers};
87
88 // Util imports
89 import BackendUtil = NBBackendUtil;
90 import BaseHashTable;
91 import ExpandableArray;
92 import Slice = NBSlice;
93 import StringUtil;
94 import UnorderedMap;
95 import Util;
96
97 constant String SIMULATION_STR = "SIM";
98 constant String START_STR = "SRT";
99 constant String PRE_STR = "PRE";
100 constant String TMP_STR = "TMP";
101
102 // mainly used for mapping purposes
103 type EquationPointer = Pointer<Equation>;
104 type EqnSlice = Slice<Pointer<Equation>>;
105
106 // used to process different outcomes of slicing from Util/Slice.mo
107 // have to be defined here and not in Util/Slice.mo because it is a uniontype and not a package
108 type Frame = tuple<ComponentRef, Expression, Option<Iterator>> "iterator-like tuple for array handling";
109 type FrameLocation = tuple<array<Integer>, Frame> "sliced frame at specific sub locations";
110 type SlicingStatus = enumeration(UNCHANGED, TRIVIAL, NONTRIVIAL, FAILURE) "final result of slicing";
111 type RecollectStatus = enumeration(SUCCESS, FAILURE) "result of sub-routine recollect";
112 type FrameOrderingStatus = enumeration(UNCHANGED, CHANGED, FAILURE) "result of sub-routine frame ordering";
113
114 type CrefLst = list<ComponentRef> "type for collecting data in hash maps";
115
116 partial function MapFuncEqn
117 input output Equation e;
118 end MapFuncEqn;
119
120 partial function MapFuncEqnPtr
121 input output Pointer<Equation> e;
122 end MapFuncEqnPtr;
123
124 partial function MapFuncExp
125 input output Expression e;
126 end MapFuncExp;
127
128 partial function MapFuncExpWrapper
129 input output Expression e;
130 input MapFuncExp func;
131 end MapFuncExpWrapper;
132
133 partial function MapFuncCref
134 input output ComponentRef c;
135 end MapFuncCref;
136
137 partial function checkEqn
138 input Pointer<Equation> eqn_ptr;
139 output Boolean b;
140 end checkEqn;
141
142 uniontype Iterator
143 record SINGLE
144 ComponentRef name "the name of the iterator";
145 Expression range "range as <start, step, stop>";
146 Option<Iterator> map "maps to a second iterator if derived from a for-expression";
147 end SINGLE;
148
149 record NESTED
150 array<ComponentRef> names "sorted iterator names";
151 array<Expression> ranges "sorted ranges as <start, step, stop>";
152 array<Option<Iterator>> maps"maps to a second iterator if derived from a for-expression";
153 end NESTED;
154
155 record EMPTY
156 end EMPTY;
157
158 function createFrame
159 "takes a typical (name, exp) tuple representing (for name in exp loop)
160 and checks if exp already is RANGE(). if not it creates a RANGE() of
161 correct size and maps the ARRAY() expression to that RANGE().
162 returns frame structure used for Iterator.fromFrames()"
163 input tuple<InstNode, Expression> iter;
164 input UnorderedSet<VariablePointer> set "new iterators";
165 output tuple<ComponentRef, Expression, Option<Iterator>> frame;
166 algorithm
167 frame := match iter
168 local
169 InstNode node, node2;
170 Expression range, range2;
171 Iterator map;
172 ComponentRef iter_cref;
173 Pointer<Variable> iter_var;
174
175 // it already is a proper range, use it for the for loop
176 253 case (node, range as Expression.RANGE()) then (ComponentRef.makeIterator(node, Type.INTEGER()), range, NONE());
177
178 // it has an array as constructor, map it to a range
179 // used to fix #13031
180 case (node, range as Expression.ARRAY()) algorithm
181 ✗ node2 := InstNode.newIterator("$" + InstNode.name(node), Type.INTEGER(), sourceInfo());
182 ✗ range2 := Expression.makeRange(Expression.INTEGER(1), NONE(), Expression.INTEGER(Type.sizeOf(Expression.typeOf(range))));
183 ✗ map := Iterator.fromFrames({(ComponentRef.makeIterator(node, Type.arrayElementType(Expression.typeOf(range))), range, NONE())});
184
185 // create the new iterator variable
186 ✗ iter_cref := ComponentRef.makeIterator(node2, Type.INTEGER());
187 ✗ iter_var := BackendDAE.lowerIterator(iter_cref);
188 ✗ iter_cref := BVariable.getVarName(iter_var);
189 ✗ UnorderedSet.add(iter_var, set);
190 ✗ then (iter_cref, range2, SOME(map));
191
192 else algorithm
193 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to inline iterator expression: " + InstNode.toString(Util.tuple21(iter)) + " in " + Expression.toString(Util.tuple22(iter)) + "."});
194 ✗ then fail();
195 end match;
196 end createFrame;
197
198 function fromFrames
199 input list<Frame> frames;
200 output Iterator iter;
201 protected
202 list<ComponentRef> names;
203 list<Expression> ranges;
204 list<Option<Iterator>> maps;
205 ComponentRef name;
206 Expression range;
207 Option<Iterator> map;
208 algorithm
209
2/2
✓ Branch 0 taken 442 times.
✓ Branch 1 taken 25 times.
467 if listEmpty(frames) then
210 iter := EMPTY();
211 else
212 442 (names, ranges, maps) := List.unzip3(frames);
213 iter := match (names, ranges, maps)
214 354 case ({name}, {range}, {map}) then SINGLE(name, range, map);
215 88 else NESTED(listArray(names), listArray(ranges), listArray(maps));
216 end match;
217 end if;
218 end fromFrames;
219
220 function addFrames
221 input output Iterator iter;
222 input list<Frame> frames;
223 protected
224 list<ComponentRef> names1, names2;
225 list<Expression> ranges1, ranges2;
226 list<Option<Iterator>> maps1, maps2;
227 algorithm
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
47 if not listEmpty(frames) then
229 47 (names1, ranges1, maps1) := getFrames(iter);
230 47 (names2, ranges2, maps2) := List.unzip3(frames);
231 47 iter := fromFrames(List.zip3(listAppend(names1, names2), listAppend(ranges1, ranges2), listAppend(maps1, maps2)));
232 end if;
233 end addFrames;
234
235 function getFrames
236 input Iterator iter;
237 output list<ComponentRef> names;
238 output list<Expression> ranges;
239 output list<Option<Iterator>> maps;
240 algorithm
241 (names, ranges, maps) := match iter
242 6406 case SINGLE() then ({iter.name}, {iter.range}, {iter.map});
243 688 case NESTED() then (arrayList(iter.names), arrayList(iter.ranges), arrayList(iter.maps));
244 case EMPTY() then ({}, {}, {});
245 end match;
246 end getFrames;
247
248 function merge
249 "merges multiple iterators to one NESTED() iterator"
250 input list<Iterator> iterators;
251 output Iterator result;
252 protected
253 list<ComponentRef> tmp_names, names = {};
254 list<Expression> tmp_ranges, ranges = {};
255 list<Option<Iterator>> tmp_maps, maps = {};
256 algorithm
257
2/2
✓ Branch 1 taken 248 times.
✓ Branch 2 taken 23 times.
271 if List.hasOneElement(iterators) then
258 248 result := listHead(iterators);
259 else
260
2/2
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 23 times.
69 for iter in listReverse(iterators) loop
261 46 (tmp_names, tmp_ranges, tmp_maps) := getFrames(iter);
262 46 names := listAppend(tmp_names, names);
263 46 ranges := listAppend(tmp_ranges, ranges);
264 46 maps := listAppend(tmp_maps, maps);
265 end for;
266 23 result := NESTED(listArray(names), listArray(ranges), listArray(maps));
267 end if;
268 end merge;
269
270 function split
271 "splits an operator in its SINGLE() subparts. used for converting to old structure and writing code
272 NOTE: returns iterators in reverse order!"
273 input Iterator iterator;
274 output list<Iterator> result = {};
275 protected
276 list<ComponentRef> names;
277 list<Expression> ranges;
278 list<Option<Iterator>> maps;
279 algorithm
280 ✗ (names, ranges, maps) := getFrames(iterator);
281 ✗ for tpl in List.zip3(names, ranges, maps) loop
282 ✗ result := Iterator.fromFrames({tpl}) :: result;
283 end for;
284 end split;
285
286 function rename
287 input output Iterator iter;
288 input String newBaseName;
289 input UnorderedMap<ComponentRef, Expression> replacements;
290 algorithm
291 iter := match iter
292 local
293 ComponentRef replacor;
294
295 case SINGLE() algorithm
296 254 replacor := ComponentRef.rename(newBaseName + intString(1), iter.name);
297 254 UnorderedMap.add(iter.name, Expression.fromCref(replacor), replacements);
298 254 iter.name := replacor;
299 then iter;
300
301 case NESTED() algorithm
302
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
108 for i in 1:arrayLength(iter.names) loop
303 56 replacor := ComponentRef.rename(newBaseName + intString(i), iter.names[i]);
304 56 UnorderedMap.add(iter.names[i], Expression.fromCref(replacor), replacements);
305 56 iter.names[i] := replacor;
306 end for;
307 then iter;
308
309 else algorithm
310 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
311 ✗ then fail();
312 end match;
313 end rename;
314
315 function isEqual
316 "compares two iterators not considering their name!"
317 input Iterator iter1;
318 input Iterator iter2;
319 output Boolean b = true;
320 algorithm
321 b := match (iter1, iter2)
322 case (EMPTY(), EMPTY()) then true;
323
3/4
✓ Branch 1 taken 364 times.
✓ Branch 2 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 364 times.
374 case (SINGLE(), SINGLE()) then Expression.isEqual(iter1.range, iter2.range) and Util.optionEqual(iter1.map, iter2.map, isEqual);
324 case (NESTED(), NESTED()) algorithm
325
6/12
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 31 times.
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 31 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 31 times.
✓ Branch 10 taken 31 times.
✗ Branch 11 not taken.
155 if arrayLength(iter1.ranges) == arrayLength(iter2.ranges) and arrayLength(iter1.maps) == arrayLength(iter2.maps) then
326
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
100 for i in 1:arrayLength(iter1.ranges) loop
327 69 b := Expression.isEqual(iter1.ranges[i], iter2.ranges[i]);
328
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 if not b then break; end if;
329 end for;
330
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
131 for i in 1:arrayLength(iter1.maps) loop
331 69 b := Util.optionEqual(iter1.maps[i], iter2.maps[i], isEqual);
332
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 if not b then break; end if;
333 end for;
334 else
335 b := false;
336 end if;
337 then b;
338 else false;
339 end match;
340 end isEqual;
341
342 function isEmpty
343 input Iterator iter;
344 output Boolean b;
345 algorithm
346 b := match iter case EMPTY() then true; else false; end match;
347 end isEmpty;
348
349 function isResizable
350 input Iterator iter;
351 output Boolean b;
352 algorithm
353 187 b := List.any(types(iter), Type.isResizable);
354 end isResizable;
355
356 function intersect
357 input Iterator iter1;
358 input Iterator iter2;
359 output Iterator intersection;
360 output tuple<Iterator, Iterator> rest1;
361 output tuple<Iterator, Iterator> rest2;
362 algorithm
363 (intersection, rest1, rest2) := match (iter1, iter2)
364 local
365 Integer start1, step1, stop1, start2, step2, stop2;
366 Integer start_max, stop_min;
367
368 // ToDo: index shift if mod start1 != start2
369 case (SINGLE(range = Expression.RANGE(start=Expression.INTEGER(start1), step=SOME(Expression.INTEGER(step1)), stop=Expression.INTEGER(stop1))),
370 SINGLE(range = Expression.RANGE(start=Expression.INTEGER(start2), step=SOME(Expression.INTEGER(step2)), stop=Expression.INTEGER(stop2))))
371 guard(step1 == step2 and intMod(start1, step1) == intMod(start2, step2))
372 algorithm
373 intMin(start1, start2);
374 start_max := intMax(start1, start2);
375 stop_min := intMin(stop1, stop2);
376 intMax(stop1, stop2);
377
378 // create intersection
379 ✗ if start_max >= stop_min then
380 intersection := EMPTY();
381 else
382 ✗ intersection := SINGLE(
383 name = iter1.name,
384 range = Expression.RANGE(
385 ty = Expression.typeOf(iter1.range),
386 start = Expression.INTEGER(start_max),
387 step = SOME(Expression.INTEGER(step1)),
388 stop = Expression.INTEGER(stop_min)),
389 map = iter1.map);
390 end if;
391
392 // create rest
393 ✗ rest1 := intersectRest(iter1.name, start1, step1, stop1, start_max-step1, stop_min+step1, iter1.map);
394 ✗ rest2 := intersectRest(iter2.name, start2, step2, stop2, start_max-step2, stop_min+step2, iter2.map);
395 then (intersection, rest1, rest2);
396
397 // cannot intersect
398 ✗ else (EMPTY(), (iter1, EMPTY()), (EMPTY(), iter2));
399 end match;
400 end intersect;
401
402 function intersectRest
403 input ComponentRef name;
404 input Integer start;
405 input Integer step;
406 input Integer stop;
407 input Integer start_max;
408 input Integer stop_min;
409 input Option<Iterator> map;
410 output tuple<Iterator, Iterator> rest;
411 protected
412 Iterator rest_left, rest_right;
413 algorithm
414 ✗ if start > start_max then
415 rest_left := EMPTY();
416 else
417 ✗ rest_left := Iterator.SINGLE(
418 name = name,
419 range = Expression.makeRange(
420 start = Expression.INTEGER(start),
421 step = SOME(Expression.INTEGER(step)),
422 stop = Expression.INTEGER(start_max)),
423 map = map);
424 end if;
425
426 ✗ if stop_min > stop then
427 rest_right := EMPTY();
428 else
429 ✗ rest_right := Iterator.SINGLE(
430 name = name,
431 range = Expression.makeRange(
432 start = Expression.INTEGER(stop_min),
433 step = SOME(Expression.INTEGER(step)),
434 stop = Expression.INTEGER(stop)),
435 map = map);
436 end if;
437 ✗ rest := (rest_left, rest_right);
438 end intersectRest;
439
440 function types
441 input Iterator iter;
442 output list<Type> t "outermost first!";
443 algorithm
444 t := match iter
445 682 case SINGLE() then {Expression.typeOf(iter.range)};
446
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 222 times.
✓ Branch 3 taken 106 times.
434 case NESTED() then list(Expression.typeOf(iter.ranges[i]) for i in 1:arrayLength(iter.ranges));
447 case EMPTY() then {};
448 else algorithm
449 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " could not get types for: " + toString(iter) + "\n"});
450 ✗ then fail();
451 end match;
452 end types;
453
454 function sizes
455 input Iterator iter;
456 input Boolean resize = false;
457 output list<Integer> sizes "outermost first!";
458 algorithm
459 sizes := match iter
460 8560 case SINGLE() then {Expression.rangeSize(iter.range, resize)};
461
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 794 times.
✓ Branch 2 taken 1682 times.
✓ Branch 3 taken 794 times.
3270 case NESTED() then list(Expression.rangeSize(iter.ranges[i], resize) for i in 1:arrayLength(iter.ranges));
462 case EMPTY() then {};
463 else algorithm
464 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " could not get sizes for: " + toString(iter) + "\n"});
465 ✗ then fail();
466 end match;
467 end sizes;
468
469 function size
470 input Iterator iter;
471 input Boolean resize = false;
472 output Integer size = product(i for i in 1 :: sizes(iter, resize));
473 end size;
474
475 function dimensions
476 input Iterator iter;
477 output list<Dimension> dims = List.flatten(list(Type.arrayDims(t) for t in types(iter)));
478 end dimensions;
479
480 function numDimensions
481 input Iterator iter;
482 output Integer num;
483 algorithm
484 num := match iter
485 case SINGLE() then 1;
486 ✗ case NESTED() then arrayLength(iter.names);
487 else 0;
488 end match;
489 end numDimensions;
490
491 function dummy
492 "creates a dummy iterator as a replacement for the actual correct one
493 Used for solving the body to only evaluate a single frame location instead of all."
494 input output Iterator iter;
495 protected
496 list<ComponentRef> names;
497 list<Expression> ranges;
498 list<Option<Iterator>> maps;
499 function dummyRange
500 "artificially set the range to only its first element"
501 input output Expression exp;
502 algorithm
503 exp := match exp
504 5 case Expression.RANGE() then Expression.makeRange(exp.start, NONE(), exp.start);
505 case Expression.ARRAY() algorithm
506 ✗ then if arrayLength(exp.elements) > 0 then Expression.makeArray(
507 ty = Type.ARRAY(Type.INTEGER(), {Dimension.fromInteger(1)}),
508 expl = arrayCreate(1, exp.elements[1]),
509 literal = Expression.isLiteral(exp.elements[1]))
510 else exp;
511 else exp;
512 end match;
513 end dummyRange;
514 algorithm
515 3 (names, ranges, maps) := getFrames(iter);
516
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 3 times.
8 ranges := list(dummyRange(e) for e in ranges);
517 3 iter := fromFrames(List.zip3(names, ranges, maps));
518 end dummy;
519
520 function createLocationReplacements
521 "adds replacements rules for a single frame location
522 Note: does not take body sizes > 1 into account"
523 input Iterator iter "iterator to replace";
524 input array<Integer> location "zero based location";
525 input UnorderedMap<ComponentRef, Expression> replacements "replacement rules";
526 algorithm
527 () := match iter
528 local
529 Integer start, step;
530
531 case SINGLE() guard(arrayLength(location) == 1) algorithm
532 99 (start, step, _) := Expression.getIntegerRange(iter.range, true);
533 99 UnorderedMap.add(iter.name, Expression.INTEGER(start + location[1]*step), replacements);
534 99 createMappedLocationReplacement(iter.map, location[1] + 1, replacements);
535 then ();
536
537 case NESTED() guard(arrayLength(location) == arrayLength(iter.ranges)) algorithm
538 ✗ for i in 1:arrayLength(location) loop
539 ✗ (start, step, _) := Expression.getIntegerRange(iter.ranges[i], true);
540 ✗ UnorderedMap.add(iter.names[i], Expression.INTEGER(start + location[i]*step), replacements);
541 ✗ createMappedLocationReplacement(iter.maps[i], location[i] + 1, replacements);
542 end for;
543 then ();
544
545 else algorithm
546 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " could not create replacements for location: "
547 + Array.toString(location, intString) + " and iterator: " + toString(iter) + "\n"});
548 ✗ then fail();
549 end match;
550 end createLocationReplacements;
551
552 function createMappedLocationReplacement
553 input Option<Iterator> map;
554 input Integer location;
555 input UnorderedMap<ComponentRef, Expression> replacements "replacement rules";
556 algorithm
557 () := match map
558 local
559 ComponentRef name;
560 Expression arr;
561
562 // only does something if the option is filled with an array
563 // fail if there is something else?
564 case SOME(SINGLE(name = name, range = arr as Expression.ARRAY())) algorithm
565 ✗ UnorderedMap.add(name, arr.elements[location], replacements);
566 then ();
567 else ();
568 end match;
569 end createMappedLocationReplacement;
570
571 function createReplacement
572 "adds a replacement rule for one iterator to another.
573 fails if they do not have the same depth or range size."
574 input Iterator replacor "replaces";
575 input Iterator replacee "gets replaced";
576 input UnorderedMap<ComponentRef, Expression> replacements "replacement rules";
577 protected
578 Boolean failed = false;
579 algorithm
580 failed := match (replacor, replacee)
581 case (SINGLE(), SINGLE()) algorithm
582 ✗ failed := createSingleReplacement(replacor.name, replacor.range, replacee.name, replacee.range, replacements);
583 then failed;
584
585 case (NESTED(), NESTED()) algorithm
586 ✗ if arrayLength(replacor.names) == arrayLength(replacee.names) then
587 ✗ for i in 1:arrayLength(replacor.names) loop
588 ✗ failed := createSingleReplacement(replacor.names[i], replacor.ranges[i], replacee.names[i], replacee.ranges[i], replacements);
589 ✗ if failed then break; end if;
590 end for;
591 else
592 failed := true;
593 end if;
594 then failed;
595
596 else true;
597 end match;
598
599 ✗ if failed then
600 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " could not create replacements for replacor: "
601 + toString(replacor) + " and replacee: " + toString(replacee) + "\n"});
602 ✗ fail();
603 end if;
604 end createReplacement;
605
606 function createSingleReplacement
607 "helper function for createReplacement()"
608 input ComponentRef replacor_cref;
609 input Expression replacor_range;
610 input ComponentRef replacee_cref;
611 input Expression replacee_range;
612 input UnorderedMap<ComponentRef, Expression> replacements "replacement rules";
613 output Boolean failed = false;
614 protected
615 Integer or_start, or_step, or_stop, ee_start, ee_step, ee_stop;
616 Expression exp;
617 function rangeLength
618 "compute the number of traversed elements. floor to integer as ranges are allowed to be defined in a non-strict boundary"
619 input Integer start;
620 input Integer step;
621 input Integer stop;
622 output Integer length = realInt((stop-start+Util.intSign(step))/step);
623 end rangeLength;
624 algorithm
625 ✗ (or_start, or_step, or_stop) := Expression.getIntegerRange(replacor_range, true);
626 ✗ (ee_start, ee_step, ee_stop) := Expression.getIntegerRange(replacee_range, true);
627 // check if same size
628 ✗ if rangeLength(or_start, or_step, or_stop) == rangeLength(ee_start, ee_step, ee_stop) then
629 // replacee = ee_start + (ee_step/or_step) * (replacor-or_start)
630 ✗ exp := Expression.MULTARY(
631 arguments = {Expression.REAL(intReal(ee_start)),
632 Expression.MULTARY(
633 arguments = {Expression.REAL(intReal(ee_step)/intReal(or_step)),
634 Expression.MULTARY(
635 arguments = {Expression.fromCref(replacor_cref)},
636 inv_arguments = {Expression.REAL(intReal(or_start))},
637 operator = Operator.makeAdd(Type.REAL()))},
638 inv_arguments = {},
639 operator = Operator.makeMul(Type.REAL()))},
640 inv_arguments = {},
641 operator = Operator.makeAdd(Type.REAL()));
642 ✗ UnorderedMap.add(replacee_cref, exp, replacements);
643 else
644 failed := true;
645 end if;
646 end createSingleReplacement;
647
648 function expand
649 "takes an iterator and expands it with the iterators of an array
650 constructor or a reduction."
651 input output Iterator iter;
652 input Call call;
653 protected
654 // dummy set for new variables. ToDo: save them to global variables
655 UnorderedSet<VariablePointer> new_iters = UnorderedSet.new(BVariable.hash, BVariable.equalName);
656 algorithm
657 iter := match call
658 local
659 list<ComponentRef> names;
660 list<Expression> ranges;
661 list<Option<Iterator>> maps;
662
663 case Call.TYPED_ARRAY_CONSTRUCTOR() algorithm
664 113 (names, ranges, maps) := getFrames(iter);
665
4/4
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 113 times.
✓ Branch 2 taken 125 times.
✓ Branch 3 taken 113 times.
238 then fromFrames(listAppend(list(createFrame(tpl, new_iters) for tpl in call.iters), List.zip3(names, ranges, maps)));
666
667 case Call.TYPED_REDUCTION() algorithm
668 13 (names, ranges, maps) := getFrames(iter);
669
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
26 then fromFrames(listAppend(list(createFrame(tpl, new_iters) for tpl in call.iters), List.zip3(names, ranges, maps)));
670
671 else iter;
672 end match;
673 end expand;
674
675 function extract
676 "takes an expression and maps it to find all occuring iterators.
677 returns an iterator if all iterators are equal, fails otherwise.
678 also replaces all array constructors with indexed expressions."
679 output Iterator iter;
680 input output Expression exp;
681 input UnorderedSet<VariablePointer> new_iters = UnorderedSet.new(BVariable.hash, BVariable.equalName) "store new iterators";
682 input UnorderedMap<list<Dimension>, CrefLst> dims_map = UnorderedMap.new<CrefLst>(Dimension.hashList, function List.isEqualOnTrue(inCompFunc = Dimension.isEqual));
683 protected
684 UnorderedMap<ComponentRef, Expression> replacements = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual);
685 algorithm
686 2735 (exp, iter) := extractFromCall(exp, EMPTY(), replacements, new_iters, dims_map);
687 2735 exp := Expression.map(exp, function Replacements.applySimpleExp(replacements = replacements));
688 2735 exp := Typing.typeExp(exp, NFInstContext.RHS, sourceInfo(), true);
689 end extract;
690
691 function extractFromCall
692 "helper function for extract()"
693 input output Expression exp;
694 input output Iterator iter;
695 input UnorderedMap<ComponentRef, Expression> replacements "replacement rules";
696 input UnorderedSet<VariablePointer> new_iters;
697 input UnorderedMap<list<Dimension>, list<ComponentRef>> dims_map;
698 algorithm
699 (exp, iter) := match exp
700 local
701 Call call;
702 list<Frame> frames = {};
703 Iterator tmp;
704 Iterator tmp_inner;
705 list<Dimension> full_dims;
706
707 case Expression.CALL(call = call as Call.TYPED_ARRAY_CONSTRUCTOR()) algorithm
708 // inline the frontend iterator to get frames for backend iterator
709
2/2
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 72 times.
158 for tpl in listReverse(call.iters) loop
710 86 frames := createFrame(tpl, new_iters) :: frames;
711 end for;
712 72 tmp := fromFrames(frames);
713
714 // create replacement rules if neccessary
715
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
72 if not isEmpty(iter) then
716 ✗ createReplacement(iter, tmp, replacements);
717 else
718 iter := tmp;
719 end if;
720
721 // createFrame creates a new "$i" iterator but leaves the body referencing the old "i"
722 // cref. add replacement rules here so applySimpleExp in extract() can update the body.
723
2/2
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 72 times.
158 for frame in frames loop
724 _ := match Util.tuple33(frame)
725 case SOME(tmp_inner as SINGLE()) algorithm
726 ✗ UnorderedMap.add(tmp_inner.name, Expression.applySubscripts({Subscript.INDEX(Expression.fromCref(Util.tuple31(frame)))}, tmp_inner.range), replacements);
727 then ();
728 else ();
729 end match;
730 end for;
731
732 // add the dimension -> iterator names to the dims map to apply the iterators correctly to the lhs
733 72 full_dims := Type.arrayDims(Expression.typeOf(exp));
734 // remove the dimensions of the type we iterate over to avoid applyings subscripts there
735 72 full_dims := List.firstN(full_dims, listLength(full_dims) - Type.dimensionCount(Expression.typeOf(call.exp)));
736 // only add if it's a new dimension configuration, first iterator replaces others
737
4/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 72 times.
158 UnorderedMap.tryAdd(full_dims, list(Util.tuple31(f) for f in frames), dims_map);
738 72 then (call.exp, iter);
739
740 // do not iterate call arguments
741 189 case Expression.CALL() then (exp, iter);
742
743 // only consider if expressions if all sub-expressions contain an array constructor
744 3 case Expression.IF() guard(extractFromCallIfException(exp)) then (exp, iter);
745
746 else algorithm
747 3657 (exp, iter) := Expression.mapFoldShallow(exp, function extractFromCall(replacements = replacements, new_iters = new_iters, dims_map = dims_map), iter);
748 then (exp, iter);
749 end match;
750 end extractFromCall;
751
752 function extractFromCallIfException
753 "returns true if any branch is not an array constructor"
754 input Expression exp;
755 output Boolean b;
756 algorithm
757 b := match exp
758 case Expression.CALL(call = Call.TYPED_ARRAY_CONSTRUCTOR()) then false;
759
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3 case Expression.IF() then extractFromCallIfException(exp.trueBranch) or extractFromCallIfException(exp.falseBranch);
760 else true;
761 end match;
762 end extractFromCallIfException;
763
764 function normalizedSubscripts
765 "creates a normalized subscript list such that the traversed iterators result in
766 consecutive indices starting at 1."
767 input Iterator iter;
768 input UnorderedMap<ComponentRef, Subscript> iter_map = UnorderedMap.new<Subscript>(ComponentRef.hash, ComponentRef.isEqual);
769 output list<Subscript> subs;
770 protected
771 list<ComponentRef> names;
772 list<Expression> ranges;
773 algorithm
774 278 (names, ranges) := getFrames(iter);
775
7/8
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 165 times.
✓ Branch 3 taken 278 times.
✓ Branch 4 taken 165 times.
✓ Branch 5 taken 278 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 278 times.
443 subs := list(normalizedSubscript(name, range, iter_map) threaded for name in names, range in ranges);
776 end normalizedSubscripts;
777
778 function normalizedSubscript
779 "returns subscripts such that traversing the range results in consecutive subscript values 1,2,3....
780 e.g: i in 10:-2:1 -> x[(i-10)/(-2) + 1] which results in 1,2,3... for i=10,8,6..."
781 input ComponentRef iter_name;
782 input Expression range;
783 input UnorderedMap<ComponentRef, Subscript> iter_map;
784 output Subscript sub;
785 protected
786 Expression step, sub_exp;
787 algorithm
788 sub := match range
789
790 // (iterator-start)/step + 1
791 case Expression.RANGE() algorithm
792 165 step := Util.getOptionOrDefault(range.step, Expression.INTEGER(1));
793 165 sub_exp := Expression.fromCref(iter_name);
794 // i - start
795
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 155 times.
165 if not Expression.isOne(range.start) then
796 10 sub_exp := Expression.MULTARY(
797 arguments = {sub_exp},
798 inv_arguments = {range.start},
799 operator = Operator.makeAdd(Type.INTEGER()));
800 end if;
801
802 // (...)/step
803
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 165 times.
165 if not Expression.isOne(step) then
804 ✗ sub_exp := Expression.MULTARY(
805 arguments = {sub_exp},
806 inv_arguments = {step},
807 operator = Operator.makeMul(Type.REAL()));
808 end if;
809
810 // (...) + 1
811
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 155 times.
165 if not Expression.isOne(range.start) then
812 10 sub_exp := Expression.MULTARY(
813 arguments = {sub_exp, Expression.INTEGER(1)},
814 inv_arguments = {},
815 operator = Operator.makeAdd(Expression.typeOf(sub_exp)));
816 end if;
817
818 165 sub_exp := SimplifyExp.simplifyDump(sub_exp, true, getInstanceName());
819
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 165 times.
165 if not Type.isInteger(Expression.typeOf(sub_exp)) then
820 ✗ sub_exp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.INTEGER_REAL, {sub_exp}, Variability.DISCRETE, Purity.PURE));
821 end if;
822 165 then Subscript.INDEX(sub_exp);
823
824 else algorithm
825 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName()
826 + " failed because range is no range: " + Expression.toString(range)});
827 ✗ then fail();
828 end match;
829
830 // add the pair to the map
831 165 UnorderedMap.add(iter_name, sub, iter_map);
832 end normalizedSubscript;
833
834 function simplifyRangeCondition
835 "used for nested for/if equation. e.g:
836 for i in 1:10 loop
837 if i <> 6 then // (no else case)
838 [...]
839 has to be simplified to
840 for i in {1,2,3,4,5,7,8,9,10} loop
841 [...]"
842 input output Iterator iter;
843 input Expression condition;
844 output Solve.Status status = NBSolve.Status.UNSOLVABLE;
845 protected
846 type IterOpt = Option<Iterator>; // needed for the map
847 list<ComponentRef> names;
848 list<Expression> ranges;
849 list<Option<Iterator>> maps;
850 UnorderedMap<ComponentRef, Expression> iter_map = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual);
851 UnorderedMap<ComponentRef, IterOpt> opt_map = UnorderedMap.new<IterOpt>(ComponentRef.hash, ComponentRef.isEqual);
852 algorithm
853 (iter, status) := match condition
854 local
855 Equation tmpEqn;
856 list<ComponentRef> occs;
857 ComponentRef cref;
858 Solve.RelationInversion invert;
859 Expression range;
860 Operator operator;
861
862 case Expression.RELATION() algorithm
863 // prepare the mappings
864 12 (names, ranges, maps) := getFrames(iter);
865
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
36 for frame in List.zip3(names, ranges, maps) loop
866 12 UnorderedMap.add(Util.tuple31(frame), Util.tuple32(frame), iter_map);
867 12 UnorderedMap.add(Util.tuple31(frame), Util.tuple33(frame), opt_map);
868 end for;
869
870 // create temp equation and collect all occuring iterator crefs
871 12 tmpEqn := Pointer.access(Equation.makeAssignment(condition.exp1, condition.exp2, Pointer.create(0), NBVariable.TEMPORARY_STR, Iterator.EMPTY(), EquationAttributes.default(EquationKind.UNKNOWN, false)));
872 12 occs := Equation.collectCrefs(tmpEqn, function Equation.collectFromMap(check_map = iter_map));
873
874
875
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 if List.hasOneElement(occs) then
876 // get the only occuring iterator cref and solve the body for it
877 12 cref := listHead(occs);
878 12 (tmpEqn, status, invert) := Solve.solveBody(tmpEqn, cref);
879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 operator := if invert == NBSolve.RelationInversion.TRUE then Operator.invert(condition.operator) else condition.operator;
880
881 // if its solvable, get the corresponding iterator range and adapt it with the information of the if-condition
882
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 if status == NBSolve.Status.EXPLICIT and invert <> NBSolve.RelationInversion.UNKNOWN then
883 12 range := UnorderedMap.getSafe(cref, iter_map, sourceInfo());
884 try
885 (range, status) := match range
886 6 case Expression.RANGE() then (adaptRange(UnorderedMap.getSafe(cref, iter_map, sourceInfo()), Util.getOption(Equation.getRHS(tmpEqn)), operator), status);
887
888 // ToDo: intercepting this
889 6 case Expression.ARRAY() then (adaptArray(UnorderedMap.getSafe(cref, iter_map, sourceInfo()), Util.getOption(Equation.getRHS(tmpEqn)), operator), status);
890
891 // can't do anything here
892 ✗ else (range, NBSolve.Status.UNSOLVABLE);
893 end match;
894 else
895 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to combine iterator: " + toString(iter) + " with condition " + Expression.toString(condition) + "."});
896 ✗ fail();
897 end try;
898
899 12 UnorderedMap.add(cref, range, iter_map);
900 else
901 ✗ status := NBSolve.Status.UNSOLVABLE;
902 end if;
903 end if;
904
905 // if something changed, create a new iterator
906
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if status == NBSolve.Status.EXPLICIT then
907
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
24 iter := Iterator.fromFrames(list((name, UnorderedMap.getSafe(name, iter_map, sourceInfo()), UnorderedMap.getSafe(name, opt_map, sourceInfo())) for name in names));
908 end if;
909 12 then (iter, status);
910
911 else (iter, NBSolve.Status.UNSOLVABLE);
912 end match;
913 end simplifyRangeCondition;
914
915 function adaptRange
916 input output Expression range;
917 input Expression rhs;
918 input Operator operator;
919 protected
920 Integer thresh, start, step, stop;
921 Boolean within_range;
922 algorithm
923 // extract the primitive type representation
924 (thresh, start, step, stop) := match (rhs, range)
925 case (Expression.INTEGER(thresh), range as Expression.RANGE(start = Expression.INTEGER(start), step = SOME(Expression.INTEGER(step)), stop = Expression.INTEGER(stop))) then (thresh, start, step, stop);
926 case (Expression.INTEGER(thresh), range as Expression.RANGE(start = Expression.INTEGER(start), stop = Expression.INTEGER(stop))) then (thresh, start, 1, stop);
927 else algorithm
928 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because range could not be evaluated: " + Expression.toString(range)});
929 ✗ then fail();
930 end match;
931
932
8/10
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 6 times.
21 within_range := thresh * sign(step) > start * sign(step) and thresh * sign(step) < stop * sign(step);
933
934 range := match operator.op
935 // i == VAL as a condition
936
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 case NFOperator.Op.EQUAL then
937 // remove all but this element from the range
938 if within_range then Expression.makeRange(Expression.INTEGER(thresh), NONE(), Expression.INTEGER(thresh))
939 // this element is not in the range >>> no valid element
940 else Expression.makeRange(Expression.INTEGER(0), SOME(Expression.INTEGER(0)), Expression.INTEGER(0));
941
942 // i <> VAL as a condition
943
7/8
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 1 time.
6 case NFOperator.Op.NEQUAL then
944 // remove only this element from the range
945 if within_range then Expression.makeExpArray(listArray(list(Expression.INTEGER(i) for i guard(i <> thresh) in List.intRange3(start, step, stop))), Type.INTEGER(), true)
946 // this element is not in the range >>> original range not changed
947 else range;
948
949 // i <, <=, >, >= VAL as a condition
950 1 case NFOperator.Op.LESS then interceptRange(thresh - 1, start, step, stop, within_range, sign(step) > 0, range, intLe);
951 1 case NFOperator.Op.LESSEQ then interceptRange(thresh, start, step, stop, within_range, sign(step) > 0, range, intLt);
952 1 case NFOperator.Op.GREATER then interceptRange(thresh + 1, start, step, stop, within_range, sign(step) < 0, range, intGe);
953 1 case NFOperator.Op.GREATEREQ then interceptRange(thresh, start, step, stop, within_range, sign(step) < 0, range, intGt);
954
955 else algorithm
956 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for operator: " + Operator.toDebugString(operator)});
957 ✗ then fail();
958 end match;
959 end adaptRange;
960
961 function interceptRange
962 input Integer thresh, start, step, stop;
963 input Boolean within_range, at_end;
964 input output Expression range;
965 input intComp func;
966 protected
967 partial function intComp
968 input Integer i1, i2;
969 output Boolean b;
970 end intComp;
971
972 function lowerBoundary
973 input Integer thresh, start, step;
974 output Integer boundary = thresh + mod(start - thresh, step);
975 end lowerBoundary;
976 algorithm
977
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if within_range then
978 // the threshold is within the range, intercept it
979
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if at_end then
980 // interception at the end does not have to be truncated to the fitting part
981 4 range := Expression.makeRange(Expression.INTEGER(start), SOME(Expression.INTEGER(step)), Expression.INTEGER(thresh));
982 else
983 // interception at the start has to compute the correct lower boundary
984 4 range := Expression.makeRange(Expression.INTEGER(lowerBoundary(thresh, start, step)), SOME(Expression.INTEGER(step)), Expression.INTEGER(stop));
985 end if;
986 elseif func(if at_end then stop else start, thresh) then
987 // the threshold leads to an empty range, otherwise leave it as it was
988 ✗ range := Expression.makeRange(Expression.INTEGER(0), SOME(Expression.INTEGER(0)), Expression.INTEGER(0));
989 end if;
990 end interceptRange;
991
992 function adaptArray
993 input output Expression array;
994 input Expression rhs;
995 input Operator operator;
996 protected
997 Integer thresh;
998 list<Integer> elems;
999 algorithm
1000 // extract the primitive type representation
1001 (thresh, elems) := match (rhs, array)
1002
10/11
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 6 times.
✓ Branch 6 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 11 taken 1 time.
✗ Branch 12 not taken.
72 case (Expression.INTEGER(thresh), Expression.ARRAY(literal = true)) then (thresh, list(Expression.integerValue(e) for e in array.elements));
1003 else algorithm
1004 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because array range is non literal: " + Expression.toString(array)});
1005 ✗ then fail();
1006 end match;
1007
1008 array := match operator.op
1009 // i == VAL as a condition
1010
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 case NFOperator.Op.EQUAL then
1011 // remove all but this element from the array
1012 if List.contains(elems, thresh, intEq) then Expression.makeRange(Expression.INTEGER(thresh), NONE(), Expression.INTEGER(thresh))
1013 // this element is not in the range >>> no valid element
1014 else Expression.makeRange(Expression.INTEGER(0), SOME(Expression.INTEGER(0)), Expression.INTEGER(0));
1015
1016 // i <>, <, <=, >, >= VAL as a condition
1017
6/6
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 time.
6 case NFOperator.Op.NEQUAL then Expression.makeExpArray(listArray(list(Expression.INTEGER(i) for i guard(i <> thresh) in elems)), Type.INTEGER(), true);
1018
6/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 time.
6 case NFOperator.Op.LESS then Expression.makeExpArray(listArray(list(Expression.INTEGER(i) for i guard(i < thresh) in elems)), Type.INTEGER(), true);
1019
6/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 time.
6 case NFOperator.Op.LESSEQ then Expression.makeExpArray(listArray(list(Expression.INTEGER(i) for i guard(i <= thresh) in elems)), Type.INTEGER(), true);
1020
6/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 time.
6 case NFOperator.Op.GREATER then Expression.makeExpArray(listArray(list(Expression.INTEGER(i) for i guard(i > thresh) in elems)), Type.INTEGER(), true);
1021
6/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 time.
6 case NFOperator.Op.GREATEREQ then Expression.makeExpArray(listArray(list(Expression.INTEGER(i) for i guard(i >= thresh) in elems)), Type.INTEGER(), true);
1022
1023 else algorithm
1024 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for operator: " + Operator.toDebugString(operator)});
1025 ✗ then fail();
1026 end match;
1027 end adaptArray;
1028
1029 function applyOrder
1030 input output Iterator iter;
1031 input UnorderedMap<ComponentRef, EvalOrder> order;
1032 function applySingleOrder
1033 input ComponentRef name;
1034 input output Expression range;
1035 input UnorderedMap<ComponentRef, EvalOrder> order;
1036 protected
1037 EvalOrder eo = UnorderedMap.getOrDefault(name, order, NBResizable.EvalOrder.INDEPENDENT);
1038 Expression step, res;
1039 list<Integer> elements;
1040 algorithm
1041 range := match range
1042
1043 // revert a range if needed
1044 case Expression.RANGE() algorithm
1045 328 step := Util.getOptionOrDefault(range.step, Expression.INTEGER(1));
1046
7/8
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 326 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 326 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 325 times.
328 if (Expression.isNegative(step) and eo == NBResizable.EvalOrder.FORWARD) or (Expression.isPositive(step) and eo == NBResizable.EvalOrder.BACKWARD) then
1047 1 res := Expression.revertRange(range);
1048 else
1049 res := range;
1050 end if;
1051 then res;
1052
1053 // revert an array/list if needed
1054 case Expression.ARRAY(literal = true) algorithm
1055
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if eo == NBResizable.EvalOrder.FORWARD then
1056 ✗ elements := list(Expression.getInteger(e, true) for e in range.elements);
1057 ✗ range.elements := listArray(list(Expression.INTEGER(e) for e in List.sort(elements, intGt)));
1058 elseif eo == NBResizable.EvalOrder.BACKWARD then
1059 ✗ elements := list(Expression.getInteger(e, true) for e in range.elements);
1060 ✗ range.elements := listArray(list(Expression.INTEGER(e) for e in List.sort(elements, intLt)));
1061 end if;
1062 then range;
1063
1064 // no other allowed
1065 else algorithm
1066 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for unhandled range expression: " + Expression.toString(range)});
1067 ✗ then fail();
1068 end match;
1069 end applySingleOrder;
1070 algorithm
1071 iter := match iter
1072 case SINGLE() algorithm
1073 275 iter.range := applySingleOrder(iter.name, iter.range, order);
1074 then iter;
1075 case NESTED() algorithm
1076
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
115 for i in 1:arrayLength(iter.names) loop
1077 59 iter.ranges[i] := applySingleOrder(iter.names[i], iter.ranges[i], order);
1078 end for;
1079 then iter;
1080 else iter;
1081 end match;
1082 end applyOrder;
1083
1084 function toString
1085 input Iterator iter;
1086 output String str = "";
1087 protected
1088 function singleStr
1089 input ComponentRef name;
1090 input Expression range;
1091 input Option<Iterator> map;
1092 output String str = ComponentRef.toString(name) + " in " + Expression.toString(range);
1093 protected
1094 list<ComponentRef> names;
1095 algorithm
1096
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 673 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 673 times.
673 if isSome(map) then
1097 ✗ (names, _) := getFrames(Util.getOption(map));
1098 ✗ str := str + " (" + ComponentRef.toString(listHead(names)) + ")";
1099 end if;
1100 end singleStr;
1101 algorithm
1102 str := match iter
1103 535 case SINGLE() then singleStr(iter.name, iter.range, iter.map);
1104
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 138 times.
✓ Branch 3 taken 64 times.
266 case NESTED() then "{" + stringDelimitList(list(singleStr(iter.names[i], iter.ranges[i], iter.maps[i]) for i in 1:arrayLength(iter.names)), ", ") + "}";
1105 case EMPTY() then "<EMPTY ITERATOR>";
1106 else algorithm
1107 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for an unknown reason."});
1108 ✗ then fail();
1109 end match;
1110 end toString;
1111
1112 function map
1113 "Traverses all expressions of the iterator range and applies a function to it."
1114 input output Iterator iter;
1115 input MapFuncExp funcExp;
1116 input Option<MapFuncCref> funcCrefOpt = NONE();
1117 input MapFuncExpWrapper mapFunc;
1118 protected
1119 MapFuncCref funcCref;
1120 algorithm
1121 iter := match iter
1122 case SINGLE() algorithm
1123
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 15871 times.
✓ Branch 2 taken 3835 times.
✓ Branch 3 taken 12036 times.
15871 if isSome(funcCrefOpt) then
1124 3835 funcCref := Util.getOption(funcCrefOpt);
1125
1/2
✓ Branch 0 taken 3835 times.
✗ Branch 1 not taken.
3835 iter.name := funcCref(iter.name);
1126 end if;
1127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15871 times.
15871 iter.range := mapFunc(iter.range, funcExp);
1128 then iter;
1129
1130 case NESTED() algorithm
1131
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1515 times.
✓ Branch 2 taken 332 times.
✓ Branch 3 taken 1183 times.
1515 if isSome(funcCrefOpt) then
1132 332 funcCref := Util.getOption(funcCrefOpt);
1133
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 332 times.
✓ Branch 2 taken 332 times.
✗ Branch 3 not taken.
1372 for i in 1:arrayLength(iter.names) loop
1134
1/2
✓ Branch 0 taken 708 times.
✗ Branch 1 not taken.
708 iter.names[i] := funcCref(iter.names[i]);
1135 end for;
1136 end if;
1137
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1515 times.
✓ Branch 2 taken 1515 times.
✗ Branch 3 not taken.
6266 for i in 1:arrayLength(iter.ranges) loop
1138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3236 times.
3236 iter.ranges[i] := mapFunc(iter.ranges[i], funcExp);
1139 end for;
1140 then iter;
1141 else algorithm
1142 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for an unknown reason."});
1143 ✗ then fail();
1144 end match;
1145 end map;
1146 end Iterator;
1147
1148 uniontype Equation
1149 record SCALAR_EQUATION
1150 Type ty "equality type";
1151 Expression lhs "left hand side expression";
1152 Expression rhs "right hand side expression";
1153 DAE.ElementSource source "origin of equation";
1154 EquationAttributes attr "Additional Attributes";
1155 end SCALAR_EQUATION;
1156
1157 record ARRAY_EQUATION
1158 Type ty "equality type containing dimensions";
1159 Expression lhs "left hand side expression";
1160 Expression rhs "right hand side expression";
1161 DAE.ElementSource source "origin of equation";
1162 EquationAttributes attr "Additional Attributes";
1163 Option<Integer> recordSize "NONE() if not a record";
1164 end ARRAY_EQUATION;
1165
1166 record RECORD_EQUATION
1167 Type ty "equality type";
1168 Expression lhs "left hand side expression";
1169 Expression rhs "right hand side expression";
1170 DAE.ElementSource source "origin of equation";
1171 EquationAttributes attr "Additional Attributes";
1172 Integer recordSize "size of the record";
1173 end RECORD_EQUATION;
1174
1175 record ALGORITHM
1176 Integer size "output size";
1177 Algorithm alg "Algorithm statements";
1178 DAE.ElementSource source "origin of algorithm";
1179 DAE.Expand expand "this algorithm was translated from an equation. we should not expand array crefs!";
1180 EquationAttributes attr "Additional Attributes";
1181 end ALGORITHM;
1182
1183 record IF_EQUATION
1184 Integer size "size of equation";
1185 IfEquationBody body "Actual equation body";
1186 DAE.ElementSource source "origin of equation";
1187 EquationAttributes attr "Additional Attributes";
1188 end IF_EQUATION;
1189
1190 record FOR_EQUATION
1191 Integer size "size of equation";
1192 Iterator iter "list of all: <iterator, range>";
1193 list<Equation> body "iterated equations (only multiples if entwined)";
1194 DAE.ElementSource source "origin of equation";
1195 EquationAttributes attr "Additional Attributes";
1196 end FOR_EQUATION;
1197
1198 record WHEN_EQUATION
1199 Integer size "size of equation";
1200 WhenEquationBody body "Actual equation body";
1201 DAE.ElementSource source "origin of equation";
1202 EquationAttributes attr "Additional Attributes";
1203 end WHEN_EQUATION;
1204
1205 record AUX_EQUATION
1206 "Auxiliary equations are generated when auxiliary variables are generated
1207 that are known to always be solved in this specific equation. E.G. $CSE
1208 The variable binding contains the equation, but this equation is also
1209 allowed to have a body for special cases."
1210 Pointer<Variable> auxiliary "Corresponding auxiliary variable";
1211 Option<Equation> body "Optional body equation"; // -> Expression
1212 end AUX_EQUATION;
1213
1214 record DUMMY_EQUATION
1215 end DUMMY_EQUATION;
1216
1217 function toString
1218 input Equation eq;
1219 input output String str = "";
1220 protected
1221 String s = "(" + intString(Equation.size(Pointer.create(eq), true)) + ")";
1222 String tupl_recd_str;
1223 algorithm
1224 str := match eq
1225 602 case SCALAR_EQUATION() then str + "[SCAL] " + s + " " + Expression.toString(eq.lhs) + " = " + Expression.toString(eq.rhs) + ";" + EquationAttributes.toString(eq.attr, " ");
1226 77 case ARRAY_EQUATION() then str + "[ARRY] " + s + " " + Expression.toString(eq.lhs) + " = " + Expression.toString(eq.rhs) + ";" + EquationAttributes.toString(eq.attr, " ");
1227 case RECORD_EQUATION() algorithm
1228
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 tupl_recd_str := if Type.isTuple(eq.ty) then "[TUPL] " else "[RECD] ";
1229 24 then str + tupl_recd_str + s + " " + Expression.toString(eq.lhs) + " = " + Expression.toString(eq.rhs) + ";" + EquationAttributes.toString(eq.attr, " ");
1230 6 case ALGORITHM() then str + "[ALGO] " + s + EquationAttributes.toString(eq.attr, " ") + "\n" + Algorithm.toString(eq.alg, str + "[----] ");
1231 18 case IF_EQUATION() then str + IfEquationBody.toString(eq.body, str + "[----] ", "[-IF-] " + s + EquationAttributes.toString(eq.attr, " ") + "\n");
1232 460 case FOR_EQUATION() then str + forEquationToString(eq.iter, eq.body, str + "[----] ", "[FOR-] " + s + EquationAttributes.toString(eq.attr, " "));
1233 1 case WHEN_EQUATION() then str + WhenEquationBody.toString(eq.body, str + "[----] ", "[WHEN] " + s + EquationAttributes.toString(eq.attr, " ") + "\n");
1234 ✗ case AUX_EQUATION() then str + "[AUX-] " + s + "Auxiliary equation for " + Variable.toString(Pointer.access(eq.auxiliary));
1235 ✗ case DUMMY_EQUATION() then str + "[DUMY] (0) Dummy equation.";
1236 ✗ else str + "[FAIL] (0) " + getInstanceName() + " failed!";
1237 end match;
1238 end toString;
1239
1240 function pointerToString
1241 input Pointer<Equation> eqn_ptr;
1242 input output String str = "";
1243 algorithm
1244 488 str := toString(Pointer.access(eqn_ptr), str);
1245 end pointerToString;
1246
1247 function source
1248 input Equation eq;
1249 output DAE.ElementSource src;
1250 algorithm
1251 src := match eq
1252 270 case SCALAR_EQUATION() then eq.source;
1253 ✗ case ARRAY_EQUATION() then eq.source;
1254 ✗ case RECORD_EQUATION() then eq.source;
1255 ✗ case ALGORITHM() then eq.source;
1256 ✗ case IF_EQUATION() then eq.source;
1257 ✗ case FOR_EQUATION() then eq.source;
1258 ✗ case WHEN_EQUATION() then eq.source;
1259 else algorithm
1260 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for:\n" + toString(eq)});
1261 ✗ then fail();
1262 end match;
1263 end source;
1264
1265 function info
1266 input Equation eq;
1267 output SourceInfo info = ElementSource.getInfo(source(eq));
1268 end info;
1269
1270 function size
1271 input Pointer<Equation> eqn_ptr;
1272 input Boolean resize = false;
1273 output Integer s;
1274 protected
1275 Equation eqn;
1276 algorithm
1277 59665 eqn := Pointer.access(eqn_ptr);
1278 s := match eqn
1279 local
1280 Equation body;
1281 case SCALAR_EQUATION() then 1;
1282 4137 case ARRAY_EQUATION() then Type.sizeOf(eqn.ty, resize);
1283 573 case RECORD_EQUATION() then Type.sizeOf(eqn.ty, resize);
1284
2/2
✓ Branch 0 taken 1476 times.
✓ Branch 1 taken 46 times.
1522 case ALGORITHM() then if resize then algorithmSize(eqn.alg, eqn.size) else eqn.size;
1285
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 23 times.
85 case IF_EQUATION() then if resize then IfEquationBody.size(eqn.body, resize) else eqn.size;
1286
2/2
✓ Branch 0 taken 4786 times.
✓ Branch 1 taken 418 times.
5204 case FOR_EQUATION(body = {body}) then if resize then Iterator.size(eqn.iter, resize) * Equation.size(Pointer.create(body), resize) else eqn.size;
1287
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 2 times.
154 case WHEN_EQUATION() then if resize then WhenEquationBody.size(eqn.body, resize) else eqn.size;
1288 ✗ case AUX_EQUATION() then Variable.size(Pointer.access(eqn.auxiliary), resize);
1289 case DUMMY_EQUATION() then 0;
1290 else algorithm
1291 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for:\n" + toString(eqn)});
1292 ✗ then fail();
1293 end match;
1294 end size;
1295
1296 function algorithmSize
1297 "the size of the outputs of an algorithm with the resized sizes of resizable dimensions"
1298 input Algorithm alg;
1299 input Integer size "the size without resizing";
1300 output Integer s;
1301 algorithm
1302
6/6
✓ Branch 0 taken 286 times.
✓ Branch 1 taken 1190 times.
✓ Branch 2 taken 583 times.
✓ Branch 3 taken 286 times.
✓ Branch 4 taken 583 times.
✓ Branch 5 taken 286 times.
2345 s := if listEmpty(alg.outputs) then size else sum(ComponentRef.size(out, false, true) for out in alg.outputs);
1303 end algorithmSize;
1304
1305 function sizes
1306 input Pointer<Equation> eqn_ptr;
1307 input Boolean resize = false;
1308 output list<Integer> size_lst;
1309 protected
1310 Equation eqn;
1311 algorithm
1312 34 eqn := Pointer.access(eqn_ptr);
1313 size_lst := match eqn
1314 case SCALAR_EQUATION() then {1};
1315 ✗ case ARRAY_EQUATION() then list(Dimension.size(dim, resize) for dim in Type.arrayDims(eqn.ty));
1316 ✗ case RECORD_EQUATION() then {Type.sizeOf(eqn.ty, resize)};
1317 ✗ case ALGORITHM() then {if resize then algorithmSize(eqn.alg, eqn.size) else eqn.size};
1318 ✗ case IF_EQUATION() then {eqn.size};
1319 34 case FOR_EQUATION() then listReverse(Iterator.sizes(eqn.iter, resize)); // does only consider frames and not conditions
1320 ✗ case WHEN_EQUATION() then {eqn.size};
1321 ✗ case AUX_EQUATION() then {Variable.size(Pointer.access(eqn.auxiliary), resize)};
1322 case DUMMY_EQUATION() then {};
1323 else algorithm
1324 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for:\n" + toString(eqn)});
1325 ✗ then fail();
1326 end match;
1327 end sizes;
1328
1329 function applyToType
1330 input output Pointer<Equation> eqn_ptr;
1331 input typeFunc func;
1332 partial function typeFunc
1333 input output Type ty;
1334 end typeFunc;
1335 protected
1336 Equation new, eqn = Pointer.access(eqn_ptr);
1337 algorithm
1338 new := match eqn
1339
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 case new as ARRAY_EQUATION() algorithm new.ty := func(new.ty); then new;
1340 ✗ case new as RECORD_EQUATION() algorithm new.ty := func(new.ty); then new;
1341 else eqn;
1342 end match;
1343
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 10 times.
108 if not referenceEq(eqn, new) then
1344 10 Pointer.update(eqn_ptr, new);
1345 end if;
1346 end applyToType;
1347
1348 function hash
1349 "only hashes the name"
1350 input Pointer<Equation> eqn;
1351 output Integer i = if isDummy(Pointer.access(eqn)) then 0 else ComponentRef.hash(getEqnName(eqn));
1352 end hash;
1353
1354 function equalName
1355 input Pointer<Equation> eqn1;
1356 input Pointer<Equation> eqn2;
1357 output Boolean b = ComponentRef.isEqual(getEqnName(eqn1), getEqnName(eqn2));
1358 end equalName;
1359
1360 function isEqualPtrTpl
1361 input tuple<EquationPointer, EquationPointer> tpl;
1362 output Boolean b;
1363 protected
1364 EquationPointer eqn1, eqn2;
1365 algorithm
1366 ✗ (eqn1, eqn2) := tpl;
1367 ✗ b := isEqualPtr(eqn1, eqn2);
1368 end isEqualPtrTpl;
1369
1370 function isEqualPtr
1371 input Pointer<Equation> eqn1;
1372 input Pointer<Equation> eqn2;
1373 output Boolean b = isEqual(Pointer.access(eqn1), Pointer.access(eqn2));
1374 end isEqualPtr;
1375
1376 function isEqualTpl
1377 input tuple<Equation, Equation> tpl;
1378 output Boolean b;
1379 protected
1380 Equation eqn1, eqn2;
1381 algorithm
1382 ✗ (eqn1, eqn2) := tpl;
1383 ✗ b := isEqual(eqn1, eqn2);
1384 end isEqualTpl;
1385
1386 function isEqual
1387 input Equation eqn1;
1388 input Equation eqn2;
1389 output Boolean b;
1390 algorithm
1391 b := match (eqn1, eqn2)
1392
4/4
✓ Branch 1 taken 4474 times.
✓ Branch 2 taken 1273 times.
✓ Branch 4 taken 68 times.
✓ Branch 5 taken 4406 times.
5747 case (SCALAR_EQUATION(), SCALAR_EQUATION()) then Expression.isEqual(eqn1.lhs, eqn2.lhs) and Expression.isEqual(eqn1.rhs, eqn2.rhs);
1393
2/4
✓ Branch 1 taken 228 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 228 times.
228 case (ARRAY_EQUATION(), ARRAY_EQUATION()) then Expression.isEqual(eqn1.lhs, eqn2.lhs) and Expression.isEqual(eqn1.rhs, eqn2.rhs);
1394
2/4
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 25 times.
25 case (RECORD_EQUATION(), RECORD_EQUATION()) then Expression.isEqual(eqn1.lhs, eqn2.lhs) and Expression.isEqual(eqn1.rhs, eqn2.rhs);
1395 63 case (ALGORITHM(), ALGORITHM()) then Algorithm.isEqual(eqn1.alg, eqn2.alg);
1396 3 case (IF_EQUATION(), IF_EQUATION()) then IfEquationBody.isEqual(eqn1.body, eqn2.body);
1397
12/14
✓ Branch 0 taken 362 times.
✓ Branch 1 taken 362 times.
✓ Branch 2 taken 362 times.
✓ Branch 3 taken 362 times.
✓ Branch 4 taken 362 times.
✓ Branch 5 taken 362 times.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 352 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 362 times.
✓ Branch 12 taken 352 times.
✓ Branch 13 taken 10 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 352 times.
724 case (FOR_EQUATION(), FOR_EQUATION()) then Iterator.isEqual(eqn1.iter, eqn2.iter) and List.all(list(isEqual(b1, b2) threaded for b1 in eqn1.body, b2 in eqn2.body), Util.id);
1398 ✗ case (WHEN_EQUATION(), WHEN_EQUATION()) then WhenEquationBody.isEqual(eqn1.body, eqn2.body);
1399 ✗ case (AUX_EQUATION(), AUX_EQUATION()) then BVariable.equalName(eqn1.auxiliary, eqn2.auxiliary) and Util.optionEqual(eqn1.body, eqn2.body, isEqual);
1400 case (DUMMY_EQUATION(), DUMMY_EQUATION()) then true;
1401 else false;
1402 end match;
1403 end isEqual;
1404
1405 function getEqnName
1406 input Pointer<Equation> eqn;
1407 output ComponentRef name;
1408 protected
1409 Pointer<Variable> residualVar;
1410 algorithm
1411
1/2
✓ Branch 2 taken 276400 times.
✗ Branch 3 not taken.
276400 if isDummy(Pointer.access(eqn)) then
1412 name := ComponentRef.EMPTY();
1413 else
1414 276400 residualVar := getResidualVar(eqn);
1415 276400 name := BVariable.getVarName(residualVar);
1416 end if;
1417 end getEqnName;
1418
1419 function getResidualVar
1420 input Pointer<Equation> eqn;
1421 output Pointer<Variable> residualVar;
1422 algorithm
1423 try
1424 277975 residualVar := EquationAttributes.getResidualVar(getAttributes(Pointer.access(eqn)));
1425 else
1426 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of missing residual variable."});
1427 ✗ fail();
1428 end try;
1429 end getResidualVar;
1430
1431 function getSolvedVar
1432 input Equation eqn;
1433 output Variable var;
1434 algorithm
1435 var := match eqn
1436 local
1437 ComponentRef cref;
1438 ✗ case SCALAR_EQUATION(lhs = Expression.CREF(cref = cref)) then BVariable.getVar(cref, sourceInfo());
1439 ✗ case ARRAY_EQUATION(lhs = Expression.CREF(cref = cref)) then BVariable.getVar(cref, sourceInfo());
1440 ✗ case RECORD_EQUATION(lhs = Expression.CREF(cref = cref)) then BVariable.getVar(cref, sourceInfo());
1441 else NBVariable.DUMMY_VARIABLE;
1442 end match;
1443 end getSolvedVar;
1444
1445 function makeAssignment
1446 input Expression lhs;
1447 input Expression rhs;
1448 input Pointer<Integer> idx;
1449 input String str;
1450 input Iterator iter;
1451 input EquationAttributes attr;
1452 output Pointer<Equation> eq;
1453 protected
1454 Equation e;
1455 algorithm
1456 4999 e := makeAssignmentEqn(lhs, rhs, iter, attr);
1457 4999 eq := Pointer.create(e);
1458 4999 createName(eq, idx, str);
1459 end makeAssignment;
1460
1461 function makeAssignmentUpdate
1462 input output Equation eq;
1463 input Expression lhs;
1464 input Expression rhs;
1465 input Iterator iter;
1466 input EquationAttributes attr;
1467 protected
1468 Pointer<Variable> res_var = Equation.getResidualVar(Pointer.create(eq));
1469 algorithm
1470 4 eq := makeAssignmentEqn(lhs, rhs, iter, attr);
1471 4 eq := Equation.setResidualVar(eq, res_var);
1472 end makeAssignmentUpdate;
1473
1474 function makeAssignmentEqn
1475 input Expression lhs;
1476 input Expression rhs;
1477 input Iterator iter;
1478 input EquationAttributes attr;
1479 output Equation e;
1480 protected
1481 Type ty = Expression.typeOf(lhs);
1482 algorithm
1483 e := match ty
1484 local
1485 ComplexType ct;
1486 862 case Type.ARRAY() then ARRAY_EQUATION(
1487 ty = ty,
1488 lhs = lhs,
1489 rhs = rhs,
1490 source = DAE.emptyElementSource,
1491 attr = attr,
1492 recordSize = NONE()
1493 );
1494 1 case Type.TUPLE() then RECORD_EQUATION(
1495 ty = ty,
1496 lhs = lhs,
1497 rhs = rhs,
1498 source = DAE.emptyElementSource,
1499 attr = attr,
1500 recordSize = Type.sizeOf(ty)
1501 );
1502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 187 times.
374 case Type.COMPLEX(complexTy = ct as ComplexType.RECORD()) then RECORD_EQUATION(
1503 ty = ty,
1504 lhs = lhs,
1505 rhs = rhs,
1506 source = DAE.emptyElementSource,
1507 attr = attr,
1508 recordSize = arrayLength(ct.fields)
1509 );
1510 3981 else SCALAR_EQUATION(
1511 ty = ty,
1512 lhs = lhs,
1513 rhs = rhs,
1514 source = DAE.emptyElementSource,
1515 attr = attr
1516 );
1517 end match;
1518 // create for-loop around it if there is an iterator
1519
2/2
✓ Branch 1 taken 4892 times.
✓ Branch 2 taken 139 times.
5031 if not Iterator.isEmpty(iter) then
1520 139 e := FOR_EQUATION(
1521 size = Type.sizeOf(ty) * Iterator.size(iter),
1522 iter = iter,
1523 body = {e},
1524 source = DAE.emptyElementSource,
1525 attr = attr
1526 );
1527 // inline if it has size 1
1528 139 e := Inline.inlineForEquation(e);
1529 end if;
1530 end makeAssignmentEqn;
1531
1532 function makeAlgorithm
1533 input list<Statement> stmts;
1534 input Boolean init;
1535 output Pointer<Equation> eqn;
1536 protected
1537 Algorithm alg;
1538 algorithm
1539 31 alg := Algorithm.ALGORITHM(stmts, {}, {}, NONE(), NFInstNode.NO_SCOPE, DAE.emptyElementSource);
1540 31 alg := Algorithm.setInputsOutputs(alg);
1541 31 eqn := BackendDAE.lowerAlgorithm(alg, init);
1542 end makeAlgorithm;
1543
1544 function forEquationToString
1545 input Iterator iter "the iterator variable(s)";
1546 input list<Equation> body "iterated equations";
1547 input String indent = "";
1548 input String indicator = "";
1549 output String str = "";
1550 protected
1551 String iterators;
1552 algorithm
1553 460 str := str + indicator + "\n";
1554 460 str := str + indent + "for " + Iterator.toString(iter) + " loop\n";
1555
2/2
✓ Branch 0 taken 460 times.
✓ Branch 1 taken 460 times.
920 for eqn in body loop
1556 460 str := str + toString(eqn, indent + " ") + "\n";
1557 end for;
1558 460 str := str + indent + "end for;";
1559 end forEquationToString;
1560
1561 function getAttributes
1562 input Equation eq;
1563 output EquationAttributes attr;
1564 algorithm
1565 attr := match eq
1566 local
1567 Equation body;
1568 224959 case SCALAR_EQUATION() then eq.attr;
1569 29197 case ARRAY_EQUATION() then eq.attr;
1570 4085 case RECORD_EQUATION() then eq.attr;
1571 10223 case ALGORITHM() then eq.attr;
1572 137 case IF_EQUATION() then eq.attr;
1573 42736 case FOR_EQUATION() then eq.attr;
1574 2825 case WHEN_EQUATION() then eq.attr;
1575 ✗ case AUX_EQUATION(body = SOME(body)) then getAttributes(body);
1576 ✗ else EquationAttributes.default(EquationKind.UNKNOWN, false);
1577 end match;
1578 end getAttributes;
1579
1580 function setAttributes
1581 input output Equation eq;
1582 input EquationAttributes attr;
1583 algorithm
1584 eq := match eq
1585 local
1586 Equation body;
1587 1377 case SCALAR_EQUATION() algorithm eq.attr := attr; then eq;
1588 23 case ARRAY_EQUATION() algorithm eq.attr := attr; then eq;
1589 ✗ case RECORD_EQUATION() algorithm eq.attr := attr; then eq;
1590 ✗ case ALGORITHM() algorithm eq.attr := attr; then eq;
1591 ✗ case IF_EQUATION() algorithm eq.attr := attr; then eq;
1592 64 case FOR_EQUATION() algorithm eq.attr := attr; then eq;
1593 ✗ case WHEN_EQUATION() algorithm eq.attr := attr; then eq;
1594 ✗ case AUX_EQUATION(body = SOME(body)) algorithm eq.body := SOME(setAttributes(body, attr)); then eq;
1595 end match;
1596 end setAttributes;
1597
1598 function setKind
1599 input output Equation eq;
1600 input EquationKind kind;
1601 input Option<Integer> clock_idx = NONE();
1602 algorithm
1603 eq := match eq
1604 local
1605 Equation body;
1606 24 case SCALAR_EQUATION() algorithm eq.attr := EquationAttributes.setKind(eq.attr, kind, clock_idx); then eq;
1607 ✗ case ARRAY_EQUATION() algorithm eq.attr := EquationAttributes.setKind(eq.attr, kind, clock_idx); then eq;
1608 ✗ case RECORD_EQUATION() algorithm eq.attr := EquationAttributes.setKind(eq.attr, kind, clock_idx); then eq;
1609 ✗ case ALGORITHM() algorithm eq.attr := EquationAttributes.setKind(eq.attr, kind, clock_idx); then eq;
1610 ✗ case IF_EQUATION() algorithm eq.attr := EquationAttributes.setKind(eq.attr, kind, clock_idx); then eq;
1611 ✗ case FOR_EQUATION() algorithm eq.attr := EquationAttributes.setKind(eq.attr, kind, clock_idx); then eq;
1612 ✗ case WHEN_EQUATION() algorithm eq.attr := EquationAttributes.setKind(eq.attr, kind, clock_idx); then eq;
1613 ✗ case AUX_EQUATION(body = SOME(body)) algorithm eq.body := SOME(setKind(body, kind, clock_idx)); then eq;
1614 end match;
1615 end setKind;
1616
1617 function getSource
1618 input Equation eq;
1619 output DAE.ElementSource source;
1620 algorithm
1621 source := match eq
1622 local
1623 Equation body;
1624 ✗ case SCALAR_EQUATION() then eq.source;
1625 ✗ case ARRAY_EQUATION() then eq.source;
1626 ✗ case RECORD_EQUATION() then eq.source;
1627 ✗ case ALGORITHM() then eq.source;
1628 ✗ case IF_EQUATION() then eq.source;
1629 600 case FOR_EQUATION() then eq.source;
1630 ✗ case WHEN_EQUATION() then eq.source;
1631 ✗ case AUX_EQUATION(body = SOME(body)) then getSource(body);
1632 else DAE.emptyElementSource;
1633 end match;
1634 end getSource;
1635
1636 function setDerivative
1637 input output Equation eq;
1638 input Pointer<Equation> derivative;
1639 protected
1640 EquationAttributes attr;
1641 algorithm
1642 218 attr := getAttributes(eq);
1643 218 attr.derivative := SOME(derivative);
1644 218 eq := setAttributes(eq, attr);
1645 end setDerivative;
1646
1647 function map
1648 "Traverses all expressions of the equations and applies a function to it.
1649 Optional second input to also traverse crefs, only needed for simple
1650 eqns, when eqns and algorithms."
1651 input output Equation eq;
1652 input MapFuncExp funcExp;
1653 input Option<MapFuncCref> funcCrefOpt = NONE();
1654 input MapFuncExpWrapper mapFunc = Expression.map;
1655 algorithm
1656 eq := match eq
1657 local
1658 Equation body;
1659 Expression lhs, rhs;
1660 Iterator iter;
1661 Algorithm alg;
1662 IfEquationBody ifEqBody;
1663 WhenEquationBody whenEqBody;
1664 Equation body, new_body;
1665
1666 case SCALAR_EQUATION() algorithm
1667
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 191642 times.
191642 lhs := mapFunc(eq.lhs, funcExp);
1668
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 191642 times.
191642 rhs := mapFunc(eq.rhs, funcExp);
1669
2/2
✓ Branch 0 taken 180522 times.
✓ Branch 1 taken 11120 times.
191642 if not referenceEq(lhs, eq.lhs) then
1670 180522 eq.lhs := lhs;
1671 end if;
1672
2/2
✓ Branch 0 taken 147683 times.
✓ Branch 1 taken 43959 times.
191642 if not referenceEq(rhs, eq.rhs) then
1673 147683 eq.rhs := rhs;
1674 end if;
1675 then eq;
1676
1677 case ARRAY_EQUATION() algorithm
1678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19124 times.
19124 lhs := mapFunc(eq.lhs, funcExp);
1679
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19124 times.
19124 rhs := mapFunc(eq.rhs, funcExp);
1680
2/2
✓ Branch 0 taken 18656 times.
✓ Branch 1 taken 468 times.
19124 if not referenceEq(lhs, eq.lhs) then
1681 18656 eq.lhs := lhs;
1682 end if;
1683
2/2
✓ Branch 0 taken 18009 times.
✓ Branch 1 taken 1115 times.
19124 if not referenceEq(rhs, eq.rhs) then
1684 18009 eq.rhs := rhs;
1685 end if;
1686 then eq;
1687
1688 case RECORD_EQUATION() algorithm
1689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2136 times.
2136 lhs := mapFunc(eq.lhs, funcExp);
1690
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2136 times.
2136 rhs := mapFunc(eq.rhs, funcExp);
1691
2/2
✓ Branch 0 taken 2110 times.
✓ Branch 1 taken 26 times.
2136 if not referenceEq(lhs, eq.lhs) then
1692 2110 eq.lhs := lhs;
1693 end if;
1694
2/2
✓ Branch 0 taken 2114 times.
✓ Branch 1 taken 22 times.
2136 if not referenceEq(rhs, eq.rhs) then
1695 2114 eq.rhs := rhs;
1696 end if;
1697 then eq;
1698
1699 case ALGORITHM() algorithm
1700 // pass mapFunc because the function itself does not map
1701 7311 alg := Algorithm.mapExp(eq.alg, function mapFunc(func = funcExp));
1702
1/2
✓ Branch 0 taken 7311 times.
✗ Branch 1 not taken.
7311 if not referenceEq(alg, eq.alg) then
1703 7311 eq.alg := Algorithm.setInputsOutputs(alg);
1704 end if;
1705 then eq;
1706
1707 case IF_EQUATION() algorithm
1708 311 ifEqBody := IfEquationBody.map(eq.body, funcExp, funcCrefOpt, mapFunc);
1709
1/2
✓ Branch 0 taken 311 times.
✗ Branch 1 not taken.
311 if not referenceEq(ifEqBody, eq.body) then
1710 311 eq.body := ifEqBody;
1711 end if;
1712 then eq;
1713
1714 case FOR_EQUATION() algorithm
1715 15944 iter := Iterator.map(eq.iter, funcExp, funcCrefOpt, mapFunc);
1716
2/2
✓ Branch 0 taken 14523 times.
✓ Branch 1 taken 1421 times.
15944 if not referenceEq(iter, eq.iter) then
1717 14523 eq.iter := iter;
1718 end if;
1719
4/4
✓ Branch 0 taken 15944 times.
✓ Branch 1 taken 15944 times.
✓ Branch 2 taken 15944 times.
✓ Branch 3 taken 15944 times.
47832 eq.body := list(map(body_eqn, funcExp, funcCrefOpt, mapFunc) for body_eqn in eq.body);
1720 then eq;
1721
1722 case WHEN_EQUATION() algorithm
1723 3106 whenEqBody := WhenEquationBody.map(eq.body, funcExp, funcCrefOpt, mapFunc);
1724
1/2
✓ Branch 0 taken 3106 times.
✗ Branch 1 not taken.
3106 if not referenceEq(whenEqBody, eq.body) then
1725 3106 eq.body := whenEqBody;
1726 end if;
1727 then eq;
1728
1729 case AUX_EQUATION(body = SOME(body)) algorithm
1730 ✗ new_body := map(body, funcExp, funcCrefOpt, mapFunc);
1731 ✗ if not referenceEq(new_body, body) then
1732 ✗ eq.body := SOME(new_body);
1733 end if;
1734 then eq;
1735
1736 case DUMMY_EQUATION() then eq;
1737
1738 else algorithm
1739 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because there was no suitable case for: " + toString(eq)});
1740 ✗ then fail();
1741
1742 end match;
1743 end map;
1744
1745 function mapCondition
1746 "Traverses all expressions in conditions of the equations and applies a function to it.
1747 Optional second input to also traverse crefs, only needed for simple
1748 eqns, when eqns and algorithms."
1749 input output Equation eq;
1750 input MapFuncExp funcExp;
1751 input Option<MapFuncCref> funcCrefOpt = NONE();
1752 input MapFuncExpWrapper mapFunc = Expression.map;
1753 algorithm
1754 eq := match eq
1755 local
1756 IfEquationBody ifEqBody;
1757 WhenEquationBody whenEqBody;
1758 Equation body, new_body;
1759
1760 // todo, map the conditions here
1761 //case ALGORITHM()
1762
1763 case IF_EQUATION() algorithm
1764 9 ifEqBody := IfEquationBody.mapCondition(eq.body, funcExp, funcCrefOpt, mapFunc);
1765
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if not referenceEq(ifEqBody, eq.body) then
1766 9 eq.body := ifEqBody;
1767 end if;
1768 then eq;
1769
1770 case FOR_EQUATION() algorithm
1771
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
12 eq.body := list(mapCondition(body_eqn, funcExp, funcCrefOpt, mapFunc) for body_eqn in eq.body);
1772 then eq;
1773
1774 case WHEN_EQUATION() algorithm
1775 74 whenEqBody := WhenEquationBody.mapCondition(eq.body, funcExp, funcCrefOpt, mapFunc);
1776
1/2
✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
74 if not referenceEq(whenEqBody, eq.body) then
1777 74 eq.body := whenEqBody;
1778 end if;
1779 then eq;
1780
1781 case AUX_EQUATION(body = SOME(body)) algorithm
1782 ✗ new_body := mapCondition(body, funcExp, funcCrefOpt, mapFunc);
1783 ✗ if not referenceEq(new_body, body) then
1784 ✗ eq.body := SOME(new_body);
1785 end if;
1786 then eq;
1787
1788 else eq;
1789 end match;
1790 end mapCondition;
1791
1792 function collectCrefs
1793 "filters all crefs of an equation and adds them
1794 to a list of crefs. needs cref filter function."
1795 input Equation eq;
1796 input Slice.filterCref filter;
1797 input MapFuncExpWrapper mapFunc = Expression.map;
1798 output list<ComponentRef> cref_lst;
1799 protected
1800 UnorderedSet<ComponentRef> acc = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
1801 algorithm
1802 // map with the expression and cref filter functions
1803 7790 map(eq, function Slice.filterExp(filter = filter, acc = acc),
1804 SOME(function filter(acc = acc)),
1805 mapFunc = mapFunc);
1806 3895 cref_lst := UnorderedSet.toList(acc);
1807 end collectCrefs;
1808
1809 function collectFromSet extends Slice.filterCref;
1810 input UnorderedSet<ComponentRef> check_set;
1811 algorithm
1812
2/2
✓ Branch 1 taken 422 times.
✓ Branch 2 taken 121 times.
543 if UnorderedSet.contains(cref, check_set) then
1813 121 UnorderedSet.add(cref, acc);
1814 end if;
1815 end collectFromSet;
1816
1817 function collectFromMap<T> extends Slice.filterCref;
1818 input UnorderedMap<ComponentRef, T> check_map;
1819 algorithm
1820
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 173 times.
183 if UnorderedMap.contains(cref, check_map) then
1821 173 UnorderedSet.add(cref, acc);
1822 end if;
1823 end collectFromMap;
1824
1825 function getLHS
1826 "gets the left hand side expression of an equation."
1827 input Equation eq;
1828 output Option<Expression> lhs;
1829 algorithm
1830 lhs := match eq
1831 local
1832 Expression exp;
1833 Boolean success;
1834 8554 case SCALAR_EQUATION() then SOME(eq.lhs);
1835 898 case ARRAY_EQUATION() then SOME(eq.lhs);
1836 79 case RECORD_EQUATION() then SOME(eq.lhs);
1837 585 case FOR_EQUATION(body = {_}) then getLHS(listHead(eq.body));
1838 case IF_EQUATION() algorithm
1839 10 (exp, success) := IfEquationBody.getLHS(eq.body);
1840
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 then if success then SOME(exp) else NONE();
1841 else NONE();
1842 end match;
1843 end getLHS;
1844
1845 function getRHS
1846 "gets the right hand side expression of an equation."
1847 input Equation eq;
1848 output Option<Expression> rhs;
1849 algorithm
1850 rhs := match eq
1851 local
1852 Expression exp;
1853 Boolean success;
1854 8271 case SCALAR_EQUATION() then SOME(eq.rhs);
1855 766 case ARRAY_EQUATION() then SOME(eq.rhs);
1856 312 case RECORD_EQUATION() then SOME(eq.rhs);
1857 391 case FOR_EQUATION(body = {_}) then getRHS(listHead(eq.body));
1858 case IF_EQUATION() algorithm
1859 5 (exp, success) := IfEquationBody.getRHS(eq.body);
1860
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 then if success then SOME(exp) else NONE();
1861 else NONE();
1862 end match;
1863 end getRHS;
1864
1865 function setLHS
1866 "sets the left hand side expression of an equation."
1867 input output Equation eq;
1868 input Expression lhs;
1869 algorithm
1870 eq := match eq
1871 2096 case SCALAR_EQUATION() algorithm eq.lhs := lhs; then eq;
1872 87 case ARRAY_EQUATION() algorithm eq.lhs := lhs; then eq;
1873 ✗ case RECORD_EQUATION() algorithm eq.lhs := lhs; then eq;
1874 case FOR_EQUATION(body = {_}) algorithm
1875 ✗ eq.body := {setLHS(listHead(eq.body), lhs)};
1876 then eq;
1877 else algorithm
1878 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because LHS " + Expression.toString(lhs) + " could not be set for:\n " + toString(eq)});
1879 ✗ then fail();
1880 end match;
1881 end setLHS;
1882
1883 function setRHS
1884 "sets the right hand side expression of an equation."
1885 input output Equation eq;
1886 input Expression rhs;
1887 algorithm
1888 eq := match eq
1889 2096 case SCALAR_EQUATION() algorithm eq.rhs := rhs; then eq;
1890 87 case ARRAY_EQUATION() algorithm eq.rhs := rhs; then eq;
1891 ✗ case RECORD_EQUATION() algorithm eq.rhs := rhs; then eq;
1892 case FOR_EQUATION(body = {_}) algorithm
1893 ✗ eq.body := {setRHS(listHead(eq.body), rhs)};
1894 then eq;
1895 else algorithm
1896 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because RHS could not be set for: " + toString(eq)});
1897 ✗ then fail();
1898 end match;
1899 end setRHS;
1900
1901 function updateLHSandRHS
1902 input output Equation eqn;
1903 input Expression lhs;
1904 input Expression rhs;
1905 protected
1906 Type ty;
1907 EquationAttributes attr = getAttributes(eqn);
1908 DAE.ElementSource src = source(eqn);
1909 Option<Integer> opt_rec_size;
1910 Integer rec_size;
1911 algorithm
1912 270 ty := Expression.typeOf(lhs);
1913 270 opt_rec_size := Type.complexSize(ty);
1914 eqn := match (ty, opt_rec_size)
1915 ✗ case (Type.ARRAY(), _) then ARRAY_EQUATION(ty, lhs, rhs, src, attr, opt_rec_size);
1916 ✗ case (Type.COMPLEX(), SOME(rec_size)) then RECORD_EQUATION(ty, lhs, rhs, src, attr, rec_size);
1917 270 else SCALAR_EQUATION(ty, lhs, rhs, src, attr);
1918 end match;
1919 end updateLHSandRHS;
1920
1921 function swapLHSandRHS
1922 input output Equation eqn;
1923 algorithm
1924 eqn := match eqn
1925 local
1926 Expression tmpExp;
1927
1928 case SCALAR_EQUATION() algorithm
1929 1753 tmpExp := eqn.rhs;
1930 1753 eqn.rhs := eqn.lhs;
1931 1753 eqn.lhs := tmpExp;
1932 then eqn;
1933
1934 case ARRAY_EQUATION() algorithm
1935 209 tmpExp := eqn.rhs;
1936 209 eqn.rhs := eqn.lhs;
1937 209 eqn.lhs := tmpExp;
1938 then eqn;
1939
1940 case RECORD_EQUATION() algorithm
1941 81 tmpExp := eqn.rhs;
1942 81 eqn.rhs := eqn.lhs;
1943 81 eqn.lhs := tmpExp;
1944 then eqn;
1945
1946 else algorithm
1947 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for: " + toString(eqn)});
1948 ✗ then fail();
1949 end match;
1950 end swapLHSandRHS;
1951
1952 function getLHSVars
1953 "use only on solved equations"
1954 input Equation eqn;
1955 output list<Slice<VariablePointer>> vars;
1956 function getLHSVarsExp
1957 input Expression exp;
1958 output list<Slice<VariablePointer>> vars;
1959 algorithm
1960 vars := match exp
1961 local
1962 ComponentRef cref;
1963 ✗ case Expression.CREF(cref = cref) then {Slice.SLICE(BVariable.getVarPointer(cref, sourceInfo()), {})};
1964 ✗ case Expression.TUPLE() then List.flatten(list(getLHSVarsExp(elem) for elem in exp.elements));
1965 ✗ case Expression.ARRAY() then List.flatten(list(getLHSVarsExp(elem) for elem in exp.elements));
1966 else algorithm
1967 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for: " + Expression.toString(exp)});
1968 ✗ then fail();
1969 end match;
1970 end getLHSVarsExp;
1971 algorithm
1972 vars := match eqn
1973 ✗ case SCALAR_EQUATION() then getLHSVarsExp(eqn.lhs);
1974 ✗ case ARRAY_EQUATION() then getLHSVarsExp(eqn.lhs);
1975 ✗ case RECORD_EQUATION() then getLHSVarsExp(eqn.lhs);
1976 ✗ case FOR_EQUATION() then List.flatten(list(getLHSVars(b) for b in eqn.body));
1977 ✗ case IF_EQUATION() then List.flatten(list(getLHSVars(Pointer.access(b)) for b in eqn.body.then_eqns));
1978 else {};
1979 end match;
1980 end getLHSVars;
1981
1982 function simplify
1983 input output Equation eq;
1984 input String name = "";
1985 input String indent = "";
1986 input Pointer<list<Pointer<Variable>>> acc_discrete_states = Pointer.create({});
1987 input Pointer<list<Pointer<Variable>>> acc_previous = Pointer.create({});
1988 input SimplifyFunc simplifyExp = function SimplifyExp.simplifyDump(includeScope = true, name = name, indent = indent);
1989
1990 partial function SimplifyFunc
1991 input output Expression exp;
1992 end SimplifyFunc;
1993 protected
1994 // FIXME a polymorphic `apply<TI, TO>` does not work for some reason
1995 function apply extends MapFuncExpWrapper;
1996 algorithm
1997
2/2
✓ Branch 0 taken 48399 times.
✓ Branch 1 taken 8353 times.
56752 e := func(e);
1998 end apply;
1999 Equation old_eq;
2000 algorithm
2001
4/6
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 26054 times.
✓ Branch 3 taken 126 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 126 times.
26180 if Flags.isSet(Flags.DUMP_SIMPLIFY) and not stringEqual(indent, "") then
2002 ✗ print("\n");
2003 end if;
2004
2005 // simplify all expressions in the equation
2006 26180 eq := map(eq, simplifyExp, mapFunc = apply);
2007
2008 // simplify equation structure
2009 26180 old_eq := eq;
2010 eq := match eq
2011 local
2012 Equation new_eq;
2013 WhenEquationBody when_body;
2014 IfEquationBody if_body;
2015 Iterator iter;
2016 Solve.Status status;
2017
2018 case SCALAR_EQUATION() algorithm
2019
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20563 times.
20563 if Expression.isEqual(eq.lhs, eq.rhs) then
2020 ✗ eq.lhs := Expression.makeZero(eq.ty);
2021 ✗ eq.rhs := Expression.makeZero(eq.ty);
2022 end if;
2023 then eq;
2024
2025 case ARRAY_EQUATION() algorithm
2026
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2279 times.
2279 if Expression.isEqual(eq.lhs, eq.rhs) then
2027 ✗ eq.lhs := Expression.makeZero(eq.ty);
2028 ✗ eq.rhs := Expression.makeZero(eq.ty);
2029 end if;
2030 then eq;
2031
2032 case RECORD_EQUATION() algorithm
2033
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 260 times.
260 if Expression.isEqual(eq.lhs, eq.rhs) then
2034 ✗ eq.lhs := Expression.makeZero(eq.ty);
2035 ✗ eq.rhs := Expression.makeZero(eq.ty);
2036 end if;
2037 then eq;
2038
2039 case ALGORITHM() algorithm
2040 1180 eq.alg := SimplifyModel.simplifyAlgorithm(eq.alg);
2041
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1179 times.
1180 then if Algorithm.isEmpty(eq.alg) then Equation.DUMMY_EQUATION() else eq;
2042
2043 case WHEN_EQUATION() algorithm
2044 new_eq := match WhenEquationBody.simplify(SOME(eq.body))
2045 case SOME(when_body) algorithm
2046 240 eq.body := when_body;
2047 then eq;
2048 else algorithm
2049 1 DetectStates.findDiscreteStatesFromWhenBody(eq.body, acc_discrete_states, acc_previous);
2050 then Equation.DUMMY_EQUATION();
2051 end match;
2052 then new_eq;
2053
2054 case IF_EQUATION() algorithm
2055 new_eq := match IfEquationBody.simplify(SOME(eq.body))
2056 case SOME(if_body) algorithm
2057
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 12 times.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
18 if isNone(if_body.else_if) and not List.hasSeveralElements(if_body.then_eqns) then
2058 // first if-branch is true and has only one equation
2059 // just replace if-equation with body
2060 6 new_eq := Pointer.access(listHead(if_body.then_eqns));
2061 else
2062 12 eq.body := if_body;
2063 try
2064 12 new_eq := IfEquationBody.inline(if_body, eq);
2065 else
2066 ✗ new_eq := eq;
2067 end try;
2068 end if;
2069 then new_eq;
2070 else Equation.DUMMY_EQUATION();
2071 end match;
2072 then new_eq;
2073
2074 // for equation with a single if-body without else-if.
2075 // structurally ambiguous of size, the if-condition and the for-loop have to be combined
2076 case FOR_EQUATION(body = {IF_EQUATION(body = if_body as IfEquationBody.IF_EQUATION_BODY(else_if = NONE()))}) algorithm
2077 12 (iter, status) := Iterator.simplifyRangeCondition(eq.iter, if_body.condition);
2078
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if status == NBSolve.Status.EXPLICIT then
2079 12 eq.iter := iter;
2080
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
36 eq.body := list(Pointer.access(be) for be in if_body.then_eqns);
2081 12 eq.size := Equation.size(Pointer.create(eq), true);
2082 end if;
2083 12 then Inline.inlineForEquation(eq);
2084
2085 1627 case FOR_EQUATION() then Inline.inlineForEquation(eq);
2086 case AUX_EQUATION() then eq;
2087 else algorithm
2088 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed for: " + toString(eq)});
2089 ✗ then fail();
2090 end match;
2091
2092
4/4
✓ Branch 1 taken 26054 times.
✓ Branch 2 taken 126 times.
✓ Branch 4 taken 111 times.
✓ Branch 5 taken 15 times.
26180 if Flags.isSet(Flags.DUMP_SIMPLIFY) and not isEqual(old_eq, eq) then
2093 15 print(indent + "### dumpSimplify | " + name + " ###\n");
2094 15 print(indent + "[BEFORE]\n" + toString(old_eq, indent + " ") + "\n");
2095 15 print(indent + "[AFTER ]\n" + toString(eq, indent + " ") + "\n\n");
2096 end if;
2097 end simplify;
2098
2099 function createName
2100 input Pointer<Equation> eqn_ptr;
2101 input Pointer<Integer> idx;
2102 input String context;
2103 protected
2104 Equation eqn = Pointer.access(eqn_ptr);
2105 Pointer<Variable> residualVar;
2106 list<Pointer<Equation>> dummy_eqns;
2107 algorithm
2108 // create residual var as name
2109 11069 (residualVar, _) := BVariable.makeResidualVar(context, Pointer.access(idx), getType(eqn));
2110 11069 Pointer.update(idx, Pointer.access(idx) + 1);
2111 11069 eqn := setResidualVar(eqn, residualVar);
2112 eqn := match eqn
2113 case IF_EQUATION() algorithm
2114 9 IfEquationBody.createNames(eqn.body, idx, context);
2115 then eqn;
2116 case FOR_EQUATION() algorithm
2117 // ToDo: multiple body equations require sub indexing - should not happen!
2118
4/4
✓ Branch 0 taken 487 times.
✓ Branch 1 taken 487 times.
✓ Branch 2 taken 487 times.
✓ Branch 3 taken 487 times.
974 dummy_eqns := list(Pointer.create(body_eqn) for body_eqn in eqn.body);
2119
2/2
✓ Branch 1 taken 487 times.
✓ Branch 2 taken 487 times.
974 for body_eqn in dummy_eqns loop createName(body_eqn, idx, context); end for;
2120
4/4
✓ Branch 0 taken 487 times.
✓ Branch 1 taken 487 times.
✓ Branch 2 taken 487 times.
✓ Branch 3 taken 487 times.
1461 eqn.body := list(Pointer.access(body_eqn) for body_eqn in dummy_eqns);
2121 then eqn;
2122 else eqn;
2123 end match;
2124 11069 Pointer.update(eqn_ptr, eqn);
2125 end createName;
2126
2127 function setResidualVar
2128 input output Equation eqn;
2129 input Pointer<Variable> residualVar;
2130 algorithm
2131 // update equation attributes
2132 eqn := match eqn
2133 case SCALAR_EQUATION() algorithm
2134 8793 eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2135 then eqn;
2136
2137 case ARRAY_EQUATION() algorithm
2138 1179 eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2139 then eqn;
2140
2141 case RECORD_EQUATION() algorithm
2142 223 eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2143 then eqn;
2144
2145 case ALGORITHM() algorithm
2146 322 eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2147 then eqn;
2148
2149 case IF_EQUATION() algorithm
2150 9 eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2151 then eqn;
2152
2153 case FOR_EQUATION() algorithm
2154 487 eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2155 then eqn;
2156
2157 case WHEN_EQUATION() algorithm
2158 74 eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2159 then eqn;
2160
2161 else algorithm
2162 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(eqn)});
2163 ✗ then fail();
2164 end match;
2165 end setResidualVar;
2166
2167 function subIdxName
2168 input Pointer<Equation> eqn_ptr;
2169 input Pointer<Integer> idx;
2170 protected
2171 Equation eqn = Pointer.access(eqn_ptr);
2172 Pointer<Variable> residualVar;
2173 algorithm
2174 // update equation attributes
2175 eqn := match eqn
2176 case SCALAR_EQUATION() algorithm
2177 ✗ residualVar := EquationAttributes.getResidualVar(eqn.attr);
2178 ✗ residualVar := BVariable.subIdxName(residualVar, idx);
2179 ✗ eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2180 then eqn;
2181
2182 case ARRAY_EQUATION() algorithm
2183 ✗ residualVar := EquationAttributes.getResidualVar(eqn.attr);
2184 ✗ residualVar := BVariable.subIdxName(residualVar, idx);
2185 ✗ eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2186 then eqn;
2187
2188 case RECORD_EQUATION() algorithm
2189 ✗ residualVar := EquationAttributes.getResidualVar(eqn.attr);
2190 ✗ residualVar := BVariable.subIdxName(residualVar, idx);
2191 ✗ eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2192 then eqn;
2193
2194 case ALGORITHM() algorithm
2195 ✗ residualVar := EquationAttributes.getResidualVar(eqn.attr);
2196 ✗ residualVar := BVariable.subIdxName(residualVar, idx);
2197 ✗ eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2198 then eqn;
2199
2200 case IF_EQUATION() algorithm
2201 ✗ residualVar := EquationAttributes.getResidualVar(eqn.attr);
2202 ✗ residualVar := BVariable.subIdxName(residualVar, idx);
2203 ✗ eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2204 then eqn;
2205
2206 case FOR_EQUATION() algorithm
2207 ✗ residualVar := EquationAttributes.getResidualVar(eqn.attr);
2208 ✗ residualVar := BVariable.subIdxName(residualVar, idx);
2209 ✗ eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2210 then eqn;
2211
2212 case WHEN_EQUATION() algorithm
2213 ✗ residualVar := EquationAttributes.getResidualVar(eqn.attr);
2214 ✗ residualVar := BVariable.subIdxName(residualVar, idx);
2215 ✗ eqn.attr := EquationAttributes.setResidualVar(eqn.attr, residualVar);
2216 then eqn;
2217
2218 else algorithm
2219 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(eqn)});
2220 ✗ then fail();
2221
2222 end match;
2223 ✗ Pointer.update(idx, Pointer.access(idx) + 1);
2224 ✗ Pointer.update(eqn_ptr, eqn);
2225 end subIdxName;
2226
2227 function createResidual
2228 "Creates a residual equation from a regular equation.
2229 Example (for DAEMode): $RES_DAE_idx := rhs."
2230 input output Pointer<Equation> eqn_ptr;
2231 input Option<ComponentRef> residualCref_opt = NONE();
2232 input Boolean new = false "set to true if the resulting pointer should be a new one";
2233 input Boolean allowFail = false;
2234 protected
2235 Equation eqn = Pointer.access(eqn_ptr);
2236 EquationAttributes attr;
2237 ComponentRef residualCref;
2238 Expression lhs, rhs;
2239 Boolean failed;
2240 algorithm
2241 // leave immediately if its already in residual form
2242
2/2
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1246 times.
1311 if isResidual(eqn_ptr) then
2243 65 return;
2244 end if;
2245
2246 // TODO: future improvement - save the residual in [INI] -> re-use for [ODE] tearing
2247 // get name cref which is the residual
2248 residualCref := match (eqn, residualCref_opt)
2249 local
2250 list<Subscript> subs;
2251
2252 // some residual cref given
2253 case (_, SOME(residualCref)) then residualCref;
2254
2255 // no residual cref given
2256 case (FOR_EQUATION(), NONE()) algorithm
2257 22 residualCref := getEqnName(eqn_ptr);
2258 22 subs := Iterator.normalizedSubscripts(eqn.iter);
2259 22 subs := listAppend(List.fill(Subscript.WHOLE(), Type.dimensionCount(Equation.getType(listHead(eqn.body)))), subs);
2260 22 residualCref := ComponentRef.setSubscripts(subs, residualCref);
2261 then residualCref;
2262 1202 else getEqnName(eqn_ptr);
2263 end match;
2264
2265 (eqn, failed) := match eqn
2266 case IF_EQUATION() algorithm
2267 ✗ eqn.body := IfEquationBody.createResidual(eqn.body, residualCref, new, allowFail);
2268 ✗ then (IfEquationBody.inline(eqn.body, eqn), false);
2269 case FOR_EQUATION() algorithm
2270
4/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 22 times.
88 eqn.body := list(Pointer.access(createResidual(Pointer.create(body_eqn), SOME(residualCref), new, allowFail)) for body_eqn in eqn.body);
2271 then (eqn, false);
2272 else algorithm
2273 // update RHS and LHS
2274 1224 lhs := Expression.fromCref(residualCref);
2275 try
2276 1224 rhs := getResidualExp(eqn, not allowFail);
2277 1224 eqn := setLHS(eqn, lhs);
2278 1224 eqn := setRHS(eqn, rhs);
2279 failed := false;
2280 else
2281 failed := true;
2282 ✗ if not allowFail then fail(); end if;
2283 end try;
2284 then (eqn, failed);
2285 end match;
2286
2287 // update residual attribute
2288
1/2
✓ Branch 0 taken 1246 times.
✗ Branch 1 not taken.
1246 if not failed then
2289 1246 attr := getAttributes(eqn);
2290 1246 attr.residual := true;
2291 1246 eqn := setAttributes(eqn, attr);
2292 end if;
2293
2294 // update pointer or create new
2295
2/2
✓ Branch 0 taken 1244 times.
✓ Branch 1 taken 2 times.
1246 if new then eqn_ptr := Pointer.create(eqn); else Pointer.update(eqn_ptr, eqn); end if;
2296 end createResidual;
2297
2298 function getResidualExp
2299 input Equation eqn;
2300 input Boolean throwOnFail = true;
2301 output Expression exp;
2302 algorithm
2303 exp := match eqn
2304 local
2305 Operator operator;
2306 InstNode cls_node;
2307 Class cls;
2308
2309 case SCALAR_EQUATION() algorithm
2310 3780 operator := Operator.OPERATOR(Expression.typeOf(eqn.lhs), NFOperator.Op.ADD);
2311 3780 then Expression.MULTARY({eqn.rhs}, {eqn.lhs}, operator);
2312
2313 case ARRAY_EQUATION() algorithm
2314 179 operator := Operator.OPERATOR(Expression.typeOf(eqn.lhs), NFOperator.Op.ADD_EW);
2315 179 then Expression.MULTARY({eqn.rhs}, {eqn.lhs}, operator);
2316
2317 case RECORD_EQUATION(ty = Type.COMPLEX()) algorithm
2318 // check if additive inverses exist
2319 9 cls_node := Type.complexNode(eqn.ty);
2320 9 cls := InstNode.getClass(cls_node);
2321
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 for op in {"'+'", "'0'", "'-'"} loop
2322
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 if not Class.hasOperator(op, cls) then
2323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if throwOnFail then
2324 ✗ Error.addMessage(Error.INTERNAL_ERROR,
2325 {"Trying to construct residual expression of type " + Type.toString(eqn.ty)
2326 + " for equation " + toString(eqn) + " but operator " + op + " is not defined."});
2327 end if;
2328 9 fail();
2329 end if;
2330 end for;
2331 ✗ operator := Operator.OPERATOR(Expression.typeOf(eqn.lhs), NFOperator.Op.ADD);
2332 ✗ then Expression.MULTARY({eqn.rhs}, {eqn.lhs}, operator);
2333
2334 // returns innermost residual!
2335 // Ambiguous for entwined for loops!
2336 124 case FOR_EQUATION(body = {_}) then getResidualExp(listHead(eqn.body), throwOnFail);
2337
2338 else algorithm
2339 ✗ if throwOnFail then
2340 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for:\n" + toString(eqn)});
2341 end if;
2342 ✗ then fail();
2343 end match;
2344 4083 exp := SimplifyExp.simplifyDump(exp, true, getInstanceName());
2345 end getResidualExp;
2346
2347 function tryGetResidualExp
2348 "like getResidualExp, but returns NONE() instead of failing (and without an
2349 error message) if no residual expression could be constructed, e.g. a
2350 RECORD_EQUATION whose type has no '+'/'-'/'0' operators (a plain Medium
2351 ThermodynamicState, for example)."
2352 input Pointer<Equation> eqn_ptr;
2353 output Option<Expression> residual;
2354 algorithm
2355 residual := matchcontinue eqn_ptr
2356 local
2357 Expression exp;
2358 case _ algorithm
2359 1660 exp := getResidualExp(Pointer.access(eqn_ptr), throwOnFail = false);
2360 then SOME(exp);
2361 else NONE();
2362 end matchcontinue;
2363 end tryGetResidualExp;
2364
2365 function getType
2366 input Equation eq;
2367 input Boolean skipIterator = false;
2368 output Type ty;
2369 algorithm
2370 ty := match eq
2371 32223 case SCALAR_EQUATION() then eq.ty;
2372 3489 case ARRAY_EQUATION() then eq.ty;
2373 468 case RECORD_EQUATION() then eq.ty;
2374 case FOR_EQUATION() algorithm
2375 2660 ty := getType(listHead(eq.body));
2376
2/2
✓ Branch 0 taken 552 times.
✓ Branch 1 taken 2108 times.
2660 if not skipIterator then
2377 552 ty := Type.liftArrayRightList(ty, Iterator.dimensions(eq.iter));
2378 end if;
2379 then ty;
2380 198 case WHEN_EQUATION() then WhenEquationBody.getType(eq.body);
2381 36 case IF_EQUATION() then IfEquationBody.getType(eq.body);
2382 else Type.REAL(); // TODO: WRONG there should not be an else case
2383 end match;
2384 end getType;
2385
2386 function getForIterator
2387 "does not work for algorithms"
2388 input Equation eqn;
2389 output Iterator iterator;
2390 algorithm
2391 iterator := match eqn
2392 6560 case FOR_EQUATION() then eqn.iter;
2393 else Iterator.EMPTY();
2394 end match;
2395 end getForIterator;
2396
2397 function getForFrames
2398 input Equation eqn;
2399 output list<Frame> frames;
2400 algorithm
2401 frames := match eqn
2402 local
2403 list<ComponentRef> names;
2404 list<Expression> ranges;
2405 list<Option<Iterator>> maps;
2406
2407 case FOR_EQUATION() algorithm
2408 ✗ (names, ranges, maps) := Iterator.getFrames(eqn.iter);
2409 ✗ then List.zip3(names, ranges, maps);
2410
2411 else {};
2412 end match;
2413 end getForFrames;
2414
2415 function applyForOrder
2416 input output Equation eqn;
2417 input UnorderedMap<ComponentRef, EvalOrder> order;
2418 algorithm
2419 eqn := match eqn
2420 case FOR_EQUATION() algorithm
2421 303 eqn.iter := Iterator.applyOrder(eqn.iter, order);
2422 then eqn;
2423 else eqn;
2424 end match;
2425 end applyForOrder;
2426
2427 function isDummy
2428 input Equation eqn;
2429 output Boolean b;
2430 algorithm
2431 b := match eqn case DUMMY_EQUATION() then true; else false; end match;
2432 end isDummy;
2433
2434 function isResidual extends checkEqn;
2435 protected
2436 EquationAttributes attr;
2437 algorithm
2438 1313 attr := getAttributes(Pointer.access(eqn_ptr));
2439 1313 b := attr.residual;
2440 end isResidual;
2441
2442 function isDiscrete extends checkEqn;
2443 protected
2444 EquationAttributes attr;
2445 algorithm
2446 10961 attr := getAttributes(Pointer.access(eqn_ptr));
2447 10961 b := attr.kind == EquationKind.DISCRETE;
2448 end isDiscrete;
2449
2450 function isContinuous extends checkEqn;
2451 protected
2452 EquationAttributes attr;
2453 algorithm
2454 1650 attr := getAttributes(Pointer.access(eqn_ptr));
2455 1650 b := attr.kind == EquationKind.CONTINUOUS;
2456 end isContinuous;
2457
2458 function isDiscontinuous
2459 "only for function interface purposes"
2460 extends checkEqn;
2461 algorithm
2462 ✗ b := not isContinuous(eqn_ptr);
2463 end isDiscontinuous;
2464
2465 function isContinousRecordAware
2466 "acts like isContinous, but returns false if it is part of a record that has a discrete variable"
2467 extends checkEqn;
2468 protected
2469 Equation eqn = Pointer.access(eqn_ptr);
2470 algorithm
2471 b := match eqn
2472 9 case RECORD_EQUATION() then Type.isContinuous(eqn.ty);
2473 1650 else isContinuous(eqn_ptr);
2474 end match;
2475 end isContinousRecordAware;
2476
2477 function isInitial extends checkEqn;
2478 protected
2479 EquationAttributes attr;
2480 algorithm
2481 4058 attr := getAttributes(Pointer.access(eqn_ptr));
2482 4058 b := attr.exclusively_initial;
2483 end isInitial;
2484
2485 function isWhenEquation extends checkEqn;
2486 protected
2487 Equation eqn = Pointer.access(eqn_ptr);
2488 algorithm
2489 b := match eqn
2490 case WHEN_EQUATION() then true;
2491
4/4
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 124 times.
✓ Branch 2 taken 124 times.
✓ Branch 3 taken 124 times.
248 case FOR_EQUATION() then List.any(list(Pointer.create(e) for e in eqn.body), isWhenEquation);
2492 else false;
2493 end match;
2494 end isWhenEquation;
2495
2496 function isIfEquation extends checkEqn;
2497 algorithm
2498 b := match Pointer.access(eqn_ptr)
2499 case IF_EQUATION() then true;
2500 else false;
2501 end match;
2502 end isIfEquation;
2503
2504 function isForEquation extends checkEqn;
2505 algorithm
2506 b := match Pointer.access(eqn_ptr)
2507 case FOR_EQUATION() then true;
2508 else false;
2509 end match;
2510 end isForEquation;
2511
2512 function isArrayEquation extends checkEqn;
2513 algorithm
2514 b := match Pointer.access(eqn_ptr)
2515 case ARRAY_EQUATION() then true;
2516 else false;
2517 end match;
2518 end isArrayEquation;
2519
2520 function isRecordOrTupleEquation extends checkEqn;
2521 algorithm
2522 b := match Pointer.access(eqn_ptr)
2523 local
2524 WhenEquationBody when_body;
2525 IfEquationBody if_body;
2526 Equation body_eqn;
2527
2528 case RECORD_EQUATION() then true;
2529 case ARRAY_EQUATION(recordSize = SOME(_)) then true;
2530 case WHEN_EQUATION(body = when_body)
2531 67 then WhenEquationBody.isRecordOrTupleEquation(when_body);
2532 case IF_EQUATION(body = if_body)
2533 ✗ then IfEquationBody.isRecordOrTupleEquation(if_body);
2534 // a for-equation of a tuple, e.g. (a[i], b[i]) = f(x[i]), has all outputs of one call per iteration
2535 case FOR_EQUATION(body = {body_eqn})
2536 6781 then isTupleEquation(Pointer.create(body_eqn));
2537 else false;
2538 end match;
2539 end isRecordOrTupleEquation;
2540
2541 function isRecordEquation extends checkEqn;
2542 algorithm
2543 b := match Pointer.access(eqn_ptr)
2544 local
2545 Equation e;
2546 ✗ case e as RECORD_EQUATION() then not Type.isTuple(e.ty);
2547 case ARRAY_EQUATION(recordSize = SOME(_)) then true;
2548 else false;
2549 end match;
2550 end isRecordEquation;
2551
2552 function isTupleEquation extends checkEqn;
2553 algorithm
2554 b := match Pointer.access(eqn_ptr)
2555 local
2556 Equation e;
2557 14 case e as RECORD_EQUATION() then Type.isTuple(e.ty);
2558 else false;
2559 end match;
2560 end isTupleEquation;
2561
2562 function isAlgorithm extends checkEqn;
2563 algorithm
2564 b := match Pointer.access(eqn_ptr)
2565 case ALGORITHM() then true;
2566 else false;
2567 end match;
2568 end isAlgorithm;
2569
2570 function isParameterEquation
2571 input Equation eqn;
2572 output Boolean b = true;
2573 protected
2574 Pointer<Boolean> b_ptr = Pointer.create(b);
2575 algorithm
2576 ✗ map(eqn, function expIsParamOrConst(b_ptr = b_ptr), SOME(function crefIsParamOrConst(b_ptr = b_ptr)));
2577 ✗ b := Pointer.access(b_ptr);
2578 end isParameterEquation;
2579
2580 function isClocked extends checkEqn;
2581 algorithm
2582 b := match getAttributes(Pointer.access(eqn_ptr))
2583 case EQUATION_ATTRIBUTES(kind = EquationKind.CLOCKED) then true;
2584 else false;
2585 end match;
2586 end isClocked;
2587
2588 function isTypeClock extends checkEqn;
2589 protected
2590 Equation eq = Pointer.access(eqn_ptr);
2591 algorithm
2592 // only check scalar equations as clocks have to be scalar
2593 // ToDo: for-equations?
2594 b := match eq
2595 5629 case SCALAR_EQUATION() then Type.isClock(eq.ty);
2596 else false;
2597 end match;
2598 end isTypeClock;
2599
2600 function isCompound extends checkEqn;
2601 algorithm
2602 b := match Pointer.access(eqn_ptr)
2603 case ALGORITHM() then true;
2604 case IF_EQUATION() then true;
2605 case WHEN_EQUATION() then true;
2606 else false;
2607 end match;
2608 end isCompound;
2609
2610 function isResizable extends checkEqn;
2611 algorithm
2612 ✗ b := Type.isResizable(getType(Pointer.access(eqn_ptr)));
2613 end isResizable;
2614
2615 function hasDerivative extends checkEqn;
2616 algorithm
2617 b := match getAttributes(Pointer.access(eqn_ptr))
2618 case EQUATION_ATTRIBUTES(derivative = SOME(_)) then true;
2619 else false;
2620 end match;
2621 end hasDerivative;
2622
2623 function expIsParamOrConst
2624 input output Expression exp;
2625 input Pointer<Boolean> b_ptr;
2626 algorithm
2627 ✗ if Pointer.access(b_ptr) then
2628 () := match exp
2629 // set b_ptr to false on impure functions
2630 case Expression.CREF() algorithm
2631 ✗ crefIsParamOrConst(exp.cref, b_ptr);
2632 then ();
2633 case Expression.CALL() algorithm
2634 ✗ Pointer.update(b_ptr, Call.isImpure(exp.call));
2635 then ();
2636 else ();
2637 end match;
2638 end if;
2639 end expIsParamOrConst;
2640
2641 function crefIsParamOrConst
2642 input output ComponentRef cref;
2643 input Pointer<Boolean> b_ptr;
2644 algorithm
2645 ✗ if Pointer.access(b_ptr) then
2646 ✗ Pointer.update(b_ptr, BVariable.isParamOrConst(BVariable.getVarPointer(cref, sourceInfo())));
2647 end if;
2648 end crefIsParamOrConst;
2649
2650 function generateBindingEquation
2651 input Pointer<Variable> var_ptr;
2652 input Pointer<Integer> idx;
2653 input Boolean initial_;
2654 input UnorderedSet<VariablePointer> new_iters;
2655 output Pointer<Equation> eqn;
2656 protected
2657 String context = "BND";
2658 Variable var;
2659 Expression lhs, rhs;
2660 EquationAttributes eqnAttr;
2661 Iterator iter;
2662 list<Subscript> subs;
2663 // maps used to correctly apply subscripts
2664 UnorderedMap<list<Dimension>, CrefLst> dims_map = UnorderedMap.new<CrefLst>(Dimension.hashList, function List.isEqualOnTrue(inCompFunc = Dimension.isEqual));
2665 UnorderedMap<ComponentRef, Subscript> iter_map = UnorderedMap.new<Subscript>(ComponentRef.hash, ComponentRef.isEqual);
2666 algorithm
2667 1599 var := Pointer.access(var_ptr);
2668 rhs := match var.binding
2669 local
2670 Binding qual;
2671 Option<Expression> start;
2672 1579 case qual as Binding.TYPED_BINDING() then qual.bindingExp;
2673 ✗ case qual as Binding.UNTYPED_BINDING() then qual.bindingExp;
2674 20 case qual as Binding.FLAT_BINDING() then qual.bindingExp;
2675 case Binding.UNBOUND() algorithm
2676 ✗ start := VariableAttributes.getStartAttribute(var.backendinfo.attributes);
2677 then match start
2678 local
2679 Expression start_exp;
2680 case SOME(start_exp) then start_exp;
2681 ✗ else Expression.makeZero(ComponentRef.getSubscriptedType(var.name, true)); // only making the zero when absolutely neccessary
2682 end match;
2683 else algorithm
2684 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong binding type: " + Binding.toDebugString(var.binding) + " for variable " + Variable.toString(Pointer.access(var_ptr))});
2685 ✗ then fail();
2686 end match;
2687
2688
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 1587 times.
1599 if BVariable.isClock(var_ptr) then
2689 12 eqnAttr := EquationAttributes.default(EquationKind.CLOCKED, initial_, SOME(-1));
2690 elseif BVariable.isContinuous(var_ptr, initial_) then
2691 1526 eqnAttr := EquationAttributes.default(EquationKind.CONTINUOUS, initial_, NONE(), var.backendinfo.annotations.optimizerExpression);
2692 else
2693 61 eqnAttr := EquationAttributes.default(EquationKind.DISCRETE, initial_);
2694 end if;
2695
2696 // simplify rhs and get potential iterators
2697 1599 (iter, rhs) := Iterator.extract(rhs, new_iters, dims_map);
2698 1599 rhs := SimplifyExp.simplifyDump(rhs, true, getInstanceName());
2699
2700
2/2
✓ Branch 1 taken 1555 times.
✓ Branch 2 taken 44 times.
1599 if Iterator.isEmpty(iter) then
2701 // no iterator -> no for-loop
2702 1555 lhs := Expression.fromCref(var.name);
2703 1555 eqn := makeAssignment(lhs, rhs, idx, context, Iterator.EMPTY(), eqnAttr);
2704 else
2705 // iterator -> create for loop and add subscripts to lhs
2706 44 rhs := Expression.map(rhs, Expression.repairOperator);
2707 44 subs := Iterator.normalizedSubscripts(iter, iter_map);
2708
2709 44 lhs := Expression.fromCref(ComponentRef.mergeSubscriptsMapped(var.name, dims_map, iter_map));
2710 44 eqn := makeAssignment(lhs, rhs, idx, context, iter, eqnAttr);
2711 // this could lead to non existing variables, should not be a problem though
2712 44 renameIterators(eqn, "$i");
2713 end if;
2714 end generateBindingEquation;
2715
2716 function mergeIterators
2717 "do not use on entwined for loops!"
2718 input output Equation eq;
2719 input Boolean top_level = true;
2720 output list<Iterator> acc;
2721 algorithm
2722 (eq, acc) := match eq
2723 local
2724 Equation body;
2725 case FOR_EQUATION() algorithm
2726 294 (body, acc) := mergeIterators(listHead(eq.body), false);
2727 294 acc := eq.iter :: acc;
2728
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 23 times.
565 then (if top_level then FOR_EQUATION(eq.size, Iterator.merge(acc), {body}, eq.source, eq.attr) else body, acc);
2729 else (eq, {});
2730 end match;
2731 end mergeIterators;
2732
2733 function splitIterators
2734 "do not use on entwined for-loops!"
2735 input output Equation eqn;
2736 algorithm
2737 eqn := match eqn
2738 local
2739 list<Iterator> iterators;
2740 Equation body;
2741 case FOR_EQUATION() algorithm
2742 // split returns innermost first
2743 ✗ iterators := Iterator.split(eqn.iter);
2744 ✗ body := listHead(eqn.body);
2745 ✗ for iter in iterators loop
2746 ✗ body := FOR_EQUATION(eqn.size, iter, {body}, eqn.source, eqn.attr);
2747 end for;
2748 then body;
2749 else eqn;
2750 end match;
2751 end splitIterators;
2752
2753 function renameIterators
2754 input Pointer<Equation> eqn_ptr;
2755 input String newBaseName;
2756 protected
2757 Equation eqn = Pointer.access(eqn_ptr);
2758 algorithm
2759 () := match eqn
2760 local
2761 UnorderedMap<ComponentRef, Expression> replacements;
2762
2763 case FOR_EQUATION() algorithm
2764 280 replacements := UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual);
2765 280 eqn.iter := Iterator.rename(eqn.iter, newBaseName, replacements);
2766
4/4
✓ Branch 0 taken 280 times.
✓ Branch 1 taken 280 times.
✓ Branch 2 taken 280 times.
✓ Branch 3 taken 280 times.
840 eqn.body := list(map(body_eqn, function Replacements.applySimpleExp(replacements = replacements)) for body_eqn in eqn.body);
2767 280 Pointer.update(eqn_ptr, eqn);
2768 then ();
2769
2770 else ();
2771 end match;
2772 end renameIterators;
2773
2774 function entwine
2775 input list<Equation> eqn_lst "has to be for-loops with combinable ranges";
2776 input Integer nesting_level = 0;
2777 output list<Equation> entwined = {} "returns a single for-loop on top level if it is possible";
2778 protected
2779 Equation eqn1, eqn2, next;
2780 list<Equation> rest, tmp;
2781 Iterator intersection, rest1_left, rest1_right, rest2_left, rest2_right;
2782 String shift = StringUtil.repeat(" ", nesting_level);
2783 algorithm
2784 ✗ if Flags.isSet(Flags.DUMP_SLICE) then
2785 ✗ print(shift + "[" + intString(nesting_level) + "] ### Entwining following equations:\n"
2786 + List.toString(eqn_lst, function toString(str = shift + " "), List.Style.NEWLINE) + "\n\n");
2787 end if;
2788 ✗ eqn1 :: rest := eqn_lst;
2789 ✗ while not listEmpty(rest) loop
2790 ✗ eqn2 :: rest := rest;
2791 eqn1 := match (eqn1, eqn2)
2792
2793 // entwine body if possible - equal iterator -> no intersecting
2794 case (FOR_EQUATION(), FOR_EQUATION()) guard(Iterator.isEqual(eqn1.iter, eqn2.iter)) algorithm
2795 ✗ eqn1.body := entwine(listAppend(eqn1.body, eqn2.body), nesting_level + 1);
2796 then eqn1;
2797
2798 // if the iterators are not equal, they have to be intersected and the respective rests have to be handled
2799 case (FOR_EQUATION(), FOR_EQUATION()) algorithm
2800 ✗ (intersection, (rest1_left, rest1_right), (rest2_left, rest2_right)) := Iterator.intersect(eqn1.iter, eqn2.iter);
2801 tmp := {};
2802 ✗ if not Iterator.isEmpty(rest1_left) then
2803 ✗ tmp := FOR_EQUATION(eqn1.size, rest1_left, eqn1.body, eqn1.source, eqn1.attr) :: tmp;
2804 end if;
2805 ✗ if not Iterator.isEmpty(rest2_left) then
2806 ✗ tmp := FOR_EQUATION(eqn2.size, rest2_left, eqn2.body, eqn2.source, eqn2.attr) :: tmp;
2807 end if;
2808 ✗ if not Iterator.isEmpty(intersection) then
2809 ✗ tmp := FOR_EQUATION(
2810 size = eqn1.size,
2811 iter = intersection,
2812 body = entwine(listAppend(eqn1.body, eqn2.body), nesting_level + 1),
2813 source = eqn1.source,
2814 attr = eqn1.attr
2815 ) :: tmp;
2816 end if;
2817 ✗ if not Iterator.isEmpty(rest1_right) then
2818 ✗ tmp := FOR_EQUATION(eqn1.size, rest1_right, eqn1.body, eqn1.source, eqn1.attr) :: tmp;
2819 end if;
2820 ✗ if not Iterator.isEmpty(rest2_right) then
2821 ✗ tmp := FOR_EQUATION(eqn2.size, rest2_right, eqn2.body, eqn2.source, eqn2.attr) :: tmp;
2822 end if;
2823 // there has to be at least one equation
2824 ✗ next :: tmp := tmp;
2825 ✗ entwined := listAppend(tmp, entwined);
2826 then next;
2827
2828 // no entwining -> just add the equation
2829 else algorithm
2830 entwined := eqn1 :: entwined;
2831 then eqn2;
2832 end match;
2833 end while;
2834 ✗ entwined := listReverse(eqn1 :: entwined);
2835 ✗ if Flags.isSet(Flags.DUMP_SLICE) then
2836 ✗ print(shift + "[" + intString(nesting_level) + "] +++ Result of entwining:\n"
2837 + List.toString(entwined, function toString(str = shift + " "), List.Style.NEWLINE) + "\n\n");
2838 end if;
2839 end entwine;
2840
2841 function slice
2842 "performs a single slice based on the given indices and the cref to solve for
2843 does not work for entwined for loops!"
2844 input Pointer<Equation> eqn_ptr "equation to slice";
2845 input list<Integer> indices "zero based indices of the eqn";
2846 output list<Pointer<Equation>> sliced_eqn;
2847 output SlicingStatus slicing_status "unchanged, trivial (only rearranged) or nontrivial";
2848 protected
2849 Equation eqn;
2850 list<Dimension> dims;
2851 list<Integer> sizes;
2852 algorithm
2853 ✗ eqn := Pointer.access(eqn_ptr);
2854 (sliced_eqn, slicing_status) := match eqn
2855 local
2856
2857 // empty index list indicates no slicing and no rearranging
2858 ✗ case _ guard(listEmpty(indices)) then ({Pointer.create(eqn)}, SlicingStatus.UNCHANGED);
2859
2860 case RECORD_EQUATION() algorithm
2861 ✗ slicing_status := if Equation.size(eqn_ptr) == listLength(indices) then SlicingStatus.TRIVIAL else SlicingStatus.NONTRIVIAL;
2862 ✗ then ({Pointer.create(eqn)}, slicing_status);
2863
2864 case ARRAY_EQUATION() algorithm
2865 ✗ slicing_status := if Equation.size(eqn_ptr) == listLength(indices) then SlicingStatus.TRIVIAL else SlicingStatus.NONTRIVIAL;
2866 ✗ then ({Pointer.create(eqn)}, slicing_status);
2867
2868 case FOR_EQUATION() algorithm
2869 // trivial slices replace the original equation entirely
2870 ✗ dims := Type.arrayDims(getType(eqn));
2871 ✗ sizes := list(Dimension.size(dim) for dim in dims);
2872 ✗ slicing_status := if Equation.size(eqn_ptr) == listLength(indices) then SlicingStatus.TRIVIAL else SlicingStatus.NONTRIVIAL;
2873 if slicing_status == SlicingStatus.NONTRIVIAL then
2874 ✗ sliced_eqn := sliceFor(listHead(eqn.body), getForIterator(eqn), sizes, listReverse(getForFrames(eqn)), indices);
2875 else
2876 ✗ sliced_eqn := {Pointer.create(eqn)};
2877 end if;
2878 then (sliced_eqn, slicing_status);
2879
2880 else algorithm
2881 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because slicing is not yet supported for:\n" + toString(eqn)});
2882 ✗ then fail();
2883 end match;
2884 end slice;
2885
2886 function sliceFor
2887 input Equation body;
2888 input Iterator iter;
2889 input list<Integer> sizes;
2890 input list<Frame> frames;
2891 input list<Integer> indices;
2892 input Boolean naive = false;
2893 output list<Pointer<Equation>> result;
2894 protected
2895 list<Integer> location;
2896 list<Frame> new_frames;
2897 list<list<Integer>> locations;
2898 list<array<Integer>> locations_T;
2899 list<FrameLocation> frame_locations;
2900 UnorderedMap<ComponentRef, Expression> replacements;
2901 FrameOrderingStatus frame_status;
2902 RecollectStatus recollect_status;
2903 Equation tmp;
2904 Option<UnorderedMap<ComponentRef, Expression>> removed_diagonals_opt;
2905 Integer size;
2906 Iterator new_iter;
2907 algorithm
2908 // get the sizes of the 'return value' of the equation
2909 ✗ if List.hasOneElement(indices) then
2910 // perform a single replacement for the one index
2911 ✗ location := Slice.indexToLocation(listHead(indices), sizes);
2912 ✗ replacements := UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual);
2913 ✗ Iterator.createLocationReplacements(iter, listArray(location), replacements);
2914 ✗ tmp := map(body, function Replacements.applySimpleExp(replacements = replacements));
2915 ✗ result := {Pointer.create(tmp)};
2916 else
2917 // create the frame locations
2918 ✗ locations := list(Slice.indexToLocation(idx, sizes) for idx in indices);
2919 ✗ locations_T := Slice.transposeLocations(locations, listLength(sizes));
2920 ✗ frame_locations := List.zip(locations_T, frames);
2921 ✗ (frame_locations, replacements, frame_status) := Slice.orderTransposedFrameLocations(frame_locations);
2922 ✗ if frame_status == FrameOrderingStatus.FAILURE then
2923 ✗ if naive then
2924 // already tried naive, need to fully scalarize
2925 ✗ result := List.flatten(list(sliceFor(body, iter, sizes, frames, {i}, true) for i in indices));
2926 else
2927 // try naive separation
2928 ✗ result := List.flatten(list(sliceFor(body, iter, sizes, frames, subset, true) for subset in Slice.naiveSeparation(indices)));
2929 end if;
2930 else
2931 ✗ (new_frames, removed_diagonals_opt, recollect_status) := Slice.recollectRangesHeuristic(frame_locations);
2932 ✗ if recollect_status == RecollectStatus.FAILURE or isSome(removed_diagonals_opt) then
2933 ✗ if naive then
2934 // already tried naive, need to fully scalarize
2935 ✗ result := List.flatten(list(sliceFor(body, iter, sizes, frames, {i}, true) for i in indices));
2936 else
2937 // try naive separation
2938 ✗ result := List.flatten(list(sliceFor(body, iter, sizes, frames, subset, true) for subset in Slice.naiveSeparation(indices)));
2939 end if;
2940 else
2941 // replace iterators
2942 ✗ tmp := map(body, function Replacements.applySimpleExp(replacements = replacements));
2943
2944 ✗ new_iter := Iterator.fromFrames(new_frames);
2945 ✗ size := Iterator.size(new_iter) * Equation.size(Pointer.create(tmp));
2946 ✗ tmp := FOR_EQUATION(
2947 size = size,
2948 iter = new_iter,
2949 body = {tmp},
2950 source = getSource(body),
2951 attr = getAttributes(body));
2952 ✗ result := {Pointer.create(tmp)};
2953 end if;
2954 end if;
2955 end if;
2956 end sliceFor;
2957
2958 function isArrayBodyFor
2959 "a for equation whose body is an array equation"
2960 input Equation eqn;
2961 output Boolean b;
2962 algorithm
2963 b := match eqn
2964 ✗ case FOR_EQUATION(body = {_}) then Equation.size(Pointer.create(listHead(eqn.body))) > 1;
2965 else false;
2966 end match;
2967 end isArrayBodyFor;
2968
2969 function isSingleBodyFor
2970 "a for equation with a single (scalar or array) body equation"
2971 input Equation eqn;
2972 output Boolean b;
2973 algorithm
2974 b := match eqn
2975 case FOR_EQUATION(body = {_}) then true;
2976 else false;
2977 end match;
2978 end isSingleBodyFor;
2979
2980 function scalarizeElement
2981 "picks one element of an array valued expression by pushing the subscripts to the operands"
2982 input Expression exp;
2983 input list<Subscript> subs;
2984 output Expression elem;
2985 algorithm
2986 elem := match exp
2987 local
2988 Expression e1, e2;
2989 Operator op;
2990
2991 case Expression.BINARY() algorithm
2992 ✗ e1 := if Type.isArray(Expression.typeOf(exp.exp1)) then scalarizeElement(exp.exp1, subs) else exp.exp1;
2993 ✗ e2 := if Type.isArray(Expression.typeOf(exp.exp2)) then scalarizeElement(exp.exp2, subs) else exp.exp2;
2994 ✗ then Expression.repairOperator(Expression.BINARY(e1, exp.operator, e2));
2995
2996 case Expression.UNARY() algorithm
2997 ✗ e1 := scalarizeElement(exp.exp, subs);
2998 ✗ then Expression.repairOperator(Expression.UNARY(exp.operator, e1));
2999
3000 case Expression.MULTARY()
3001
12/12
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 73 times.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 73 times.
✓ Branch 6 taken 16 times.
✓ Branch 7 taken 80 times.
✓ Branch 9 taken 50 times.
✓ Branch 10 taken 73 times.
✓ Branch 11 taken 50 times.
✓ Branch 12 taken 73 times.
✓ Branch 15 taken 8 times.
✓ Branch 16 taken 42 times.
219 then Expression.repairOperator(Expression.MULTARY(
3002 list(if Type.isArray(Expression.typeOf(e)) then scalarizeElement(e, subs) else e for e in exp.arguments),
3003 list(if Type.isArray(Expression.typeOf(e)) then scalarizeElement(e, subs) else e for e in exp.inv_arguments),
3004 exp.operator));
3005
3006 16 else Expression.applySubscripts(subs, exp);
3007 end match;
3008 end scalarizeElement;
3009
3010 function forArrayBodyRowResidual
3011 "the scalar residual of a single row (zero based index) of a for equation with a single (scalar or array) body"
3012 input Equation eqn;
3013 input Integer idx;
3014 output Expression residual;
3015 protected
3016 Iterator iter;
3017 Equation body;
3018 list<Integer> sizes, location;
3019 Integer n_body;
3020 UnorderedMap<ComponentRef, Expression> replacements = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual);
3021 algorithm
3022
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 65 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 65 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 65 times.
65 FOR_EQUATION(iter = iter, body = {body}) := eqn;
3023
4/4
✓ Branch 2 taken 73 times.
✓ Branch 3 taken 65 times.
✓ Branch 4 taken 73 times.
✓ Branch 5 taken 65 times.
138 sizes := list(Dimension.size(dim) for dim in Type.arrayDims(Equation.getType(eqn)));
3024 65 n_body := listLength(Type.arrayDims(Equation.getType(body)));
3025 // the rows are row major w.r.t. the body dimensions followed by the iterator frames
3026 65 location := listReverse(Slice.indexToLocation(idx, sizes));
3027 65 Iterator.createLocationReplacements(iter, listArray(List.lastN(location, listLength(location) - n_body)), replacements);
3028 // if-equation bodies become an if-expression of the branch residuals
3029 residual := match body
3030 ✗ case IF_EQUATION() then IfEquationBody.getResidualExp(body.body);
3031 65 else Equation.getResidualExp(body);
3032 end match;
3033 65 residual := Expression.map(residual, function Replacements.applySimpleExp(replacements = replacements));
3034
4/4
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 65 times.
73 residual := scalarizeElement(residual, list(Subscript.INDEX(Expression.INTEGER(l + 1)) for l in List.firstN(location, n_body)));
3035 65 residual := SimplifyExp.simplifyDump(residual, true, getInstanceName());
3036 end forArrayBodyRowResidual;
3037
3038 function singleSlice
3039 input Pointer<Equation> eqn_ptr "equation to slice";
3040 input Integer scal_idx "zero based scalar index";
3041 input list<Integer> sizes "frame sizes (innermost first)";
3042 input ComponentRef cref_to_solve "the cref to solve the body for (EMPTY() for already solved)";
3043 input UnorderedMap<ComponentRef, Expression> replacements "prepared replacement map";
3044 output Equation sliced_eqn "scalar sliced equation";
3045 input UnorderedMap<Path, Function> funcMap "func map for solving";
3046 output Solve.Status solve_status = NBSolve.Status.EXPLICIT "solve success status";
3047 protected
3048 Equation eqn;
3049 list<Integer> location;
3050 algorithm
3051 32 eqn := Pointer.access(eqn_ptr);
3052 (sliced_eqn, solve_status) := match eqn
3053
3054 // slice the equation
3055 case FOR_EQUATION() algorithm
3056 // get the frame location indices from single index
3057 32 location := Slice.indexToLocation(scal_idx, sizes);
3058 // create the replacement rules for this location
3059 32 Iterator.createLocationReplacements(eqn.iter, listArray(location), replacements);
3060 // replace iterators
3061 32 sliced_eqn := map(listHead(eqn.body), function Replacements.applySimpleExp(replacements = replacements));
3062 // solve the body if necessary
3063
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 if not ComponentRef.isEmpty(cref_to_solve) then
3064 32 (sliced_eqn, solve_status, _) := Solve.solveBody(sliced_eqn, cref_to_solve, funcMap);
3065 end if;
3066 32 then (sliced_eqn, solve_status);
3067
3068 // ToDo: arrays 'n stuff
3069
3070 // equation that does not need to be sliced
3071 else (eqn, NBSolve.Status.UNPROCESSED);
3072 end match;
3073 end singleSlice;
3074
3075 protected function makeInequality
3076 input tuple<ComponentRef, Expression> tpl;
3077 output Expression equality_exp;
3078 protected
3079 ComponentRef cref;
3080 Expression exp;
3081 algorithm
3082 ✗ (cref, exp) := tpl;
3083 ✗ equality_exp := Expression.RELATION(
3084 exp1 = Expression.fromCref(cref),
3085 operator = Operator.OPERATOR(ComponentRef.nodeType(cref), NFOperator.Op.NEQUAL),
3086 exp2 = SimplifyExp.simplifyDump(exp, true, getInstanceName()),
3087 index = -1
3088 );
3089 end makeInequality;
3090
3091 public function toStatement
3092 "expects for loops to be split with splitIterators(eqn)"
3093 input Equation eqn;
3094 output list<Statement> stmts = {};
3095 algorithm
3096 stmts := match eqn
3097 local
3098 list<ComponentRef> iter_lst;
3099 list<Expression> range_lst;
3100 list<Option<Iterator>> maps_lst;
3101 Option<Iterator> map_opt;
3102 list<tuple<ComponentRef, array<Expression>>> sub_iters_stmt;
3103 ComponentRef iter, lhs_rec, rhs_rec, iter_name;
3104 Expression range, lhs_exp, rhs_exp;
3105 array<Expression> iter_elems;
3106 list<Statement> body;
3107 Pointer<Variable> lhs, rhs;
3108 list<Pointer<Variable>> lhs_lst, rhs_lst;
3109 list<Subscript> lhs_subs, rhs_subs;
3110
3111 case SCALAR_EQUATION()
3112 29 then {Statement.ASSIGNMENT(eqn.lhs, eqn.rhs, eqn.ty, eqn.source)};
3113
3114 case ARRAY_EQUATION()
3115 ✗ then {Statement.ASSIGNMENT(eqn.lhs, eqn.rhs, eqn.ty, eqn.source)};
3116
3117 case RECORD_EQUATION(lhs = Expression.CREF(cref = lhs_rec), rhs = Expression.CREF(cref = rhs_rec)) algorithm
3118 56 lhs_lst := BVariable.getRecordChildren(BVariable.getVarPointer(lhs_rec, sourceInfo()));
3119 56 rhs_lst := BVariable.getRecordChildren(BVariable.getVarPointer(rhs_rec, sourceInfo()));
3120 56 lhs_subs := ComponentRef.subscriptsAllFlat(lhs_rec);
3121 56 rhs_subs := ComponentRef.subscriptsAllFlat(rhs_rec);
3122
3/4
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 55 times.
✗ Branch 7 not taken.
56 if List.compareLength(lhs_lst, rhs_lst) == 0 and not Type.isExternalObject(Type.arrayElementType(Expression.typeOf(eqn.lhs))) then
3123
2/2
✓ Branch 1 taken 135 times.
✓ Branch 2 taken 55 times.
190 for tpl in List.zip(lhs_lst, rhs_lst) loop
3124 135 (lhs, rhs) := tpl;
3125 135 lhs_exp := Expression.fromCref(ComponentRef.mergeSubscripts(lhs_subs, BVariable.getVarName(lhs), true));
3126 135 rhs_exp := Expression.fromCref(ComponentRef.mergeSubscripts(rhs_subs, BVariable.getVarName(rhs), true));
3127
4/6
✓ Branch 1 taken 135 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 134 times.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
135 if BVariable.isConst(lhs) then
3128 // constants have no storage and keep their value
3129 elseif BVariable.isRecord(lhs) and BVariable.isRecord(rhs) then
3130 // nested record, assign its children
3131 1 stmts := listAppend(toStatement(RECORD_EQUATION(Expression.typeOf(lhs_exp), lhs_exp, rhs_exp, eqn.source, eqn.attr,
3132 listLength(BVariable.getRecordChildren(lhs)))), stmts);
3133 else
3134 134 stmts := Statement.ASSIGNMENT(lhs_exp, rhs_exp, Expression.typeOf(lhs_exp), eqn.source) :: stmts;
3135 end if;
3136 end for;
3137 else
3138 1 stmts := {Statement.ASSIGNMENT(eqn.lhs, eqn.rhs, eqn.ty, eqn.source)};
3139 end if;
3140 then stmts;
3141
3142 case RECORD_EQUATION()
3143 12 then {Statement.ASSIGNMENT(eqn.lhs, eqn.rhs, eqn.ty, eqn.source)};
3144
3145 case FOR_EQUATION() algorithm
3146 37 (iter_lst, range_lst, maps_lst) := Equation.Iterator.getFrames(eqn.iter);
3147
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 37 times.
74 body := List.flatten(list(toStatement(body_eqn) for body_eqn in eqn.body));
3148
2/2
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 37 times.
85 for tpl in listReverse(List.zip3(iter_lst, range_lst, maps_lst)) loop
3149 48 (iter, range, map_opt) := tpl;
3150 sub_iters_stmt := match map_opt
3151 case SOME(Iterator.SINGLE(name = iter_name, range = Expression.ARRAY(elements = iter_elems), map = NONE()))
3152 ✗ then {(iter_name, iter_elems)};
3153 case SOME(_) then {};
3154 else {};
3155 end match;
3156 48 body := {Statement.FOR(
3157 iterator = ComponentRef.node(iter),
3158 range = SOME(range),
3159 body = body,
3160 forType = Statement.ForType.NORMAL(),
3161 source = eqn.source,
3162 sub_iters = sub_iters_stmt)};
3163 end for;
3164 then body;
3165
3166 4 case IF_EQUATION() then {Statement.IF(IfEquationBody.toStatement(eqn.body), eqn.source)};
3167
3168 ✗ case WHEN_EQUATION() then {Statement.WHEN(WhenEquationBody.toStatement(eqn.body), eqn.source)};
3169
3170 11 case ALGORITHM() then eqn.alg.statements;
3171
3172 else algorithm
3173 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed it is not yet supported for:\n" + toString(eqn)});
3174 ✗ then fail();
3175 end match;
3176 end toStatement;
3177 end Equation;
3178
3179 uniontype IfEquationBody
3180 record IF_EQUATION_BODY
3181 Expression condition "the if-condition";
3182 list<Pointer<Equation>> then_eqns "body equations";
3183 Option<IfEquationBody> else_if "optional elseif equation";
3184 end IF_EQUATION_BODY;
3185
3186 function toEquation
3187 "does not name the equation"
3188 input IfEquationBody body;
3189 input DAE.ElementSource source;
3190 input Boolean init;
3191 output Pointer<Equation> eqn;
3192 protected
3193 EquationAttributes attr;
3194 Boolean isAlgorithm;
3195 Equation e;
3196 Algorithm alg;
3197 Integer size;
3198 algorithm
3199 (attr, isAlgorithm) := match body.then_eqns
3200 local
3201 Pointer<Equation> then_eqn;
3202
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 24 times.
25 case {then_eqn} then (if Equation.isDiscrete(then_eqn)
3203 then EquationAttributes.default(EquationKind.DISCRETE, init)
3204 else EquationAttributes.default(EquationKind.CONTINUOUS, init), Equation.isAlgorithm(then_eqn));
3205 else algorithm
3206 ✗ if(Flags.isSet(Flags.FAILTRACE)) then
3207 ✗ Error.addMessage(Error.COMPILER_WARNING,{getInstanceName()
3208 + ": Creating if-equation with multiple body equations. Unsure of type:\n" + IfEquationBody.toString(body)});
3209 end if;
3210 ✗ then (EquationAttributes.default(EquationKind.CONTINUOUS, init), false);
3211 end match;
3212
3213 25 e := Equation.IF_EQUATION(IfEquationBody.size(body), body, source, attr);
3214 // convert to algorithm if the body is an algorithm. mainly used for asserts in if-equations
3215
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 21 times.
25 if isAlgorithm then
3216 4 alg := Algorithm.ALGORITHM(Equation.toStatement(e), {}, {}, NONE(), NFInstNode.NO_SCOPE, source);
3217 4 alg := Algorithm.setInputsOutputs(alg);
3218
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 size := sum(ComponentRef.size(out, false) for out in alg.outputs);
3219 4 eqn := Pointer.create(Equation.ALGORITHM(size, alg, alg.source, DAE.EXPAND(), attr));
3220 else
3221 21 eqn := Pointer.create(e);
3222 end if;
3223 end toEquation;
3224
3225 function makeIfEquation
3226 "similar to makeAssignment but for if-equations"
3227 input IfEquationBody body;
3228 input Pointer<Integer> idx;
3229 input String str;
3230 input Iterator iter;
3231 input DAE.ElementSource source;
3232 input EquationAttributes attr;
3233 output Pointer<Equation> eq;
3234 protected
3235 Equation e;
3236 algorithm
3237 ✗ e := makeIfEquationEqn(body, iter, source, attr);
3238 ✗ eq := Pointer.create(e);
3239 ✗ Equation.createName(eq, idx, str);
3240 end makeIfEquation;
3241
3242 protected function makeIfEquationEqn
3243 "similar to makeAssignmentEqn but for if-equations"
3244 input IfEquationBody body;
3245 input Iterator iter;
3246 input DAE.ElementSource source;
3247 input EquationAttributes attr;
3248 output Equation e;
3249 algorithm
3250 ✗ e := Equation.IF_EQUATION(
3251 size = IfEquationBody.size(body),
3252 body = body,
3253 source = source,
3254 attr = attr
3255 );
3256 // create for-loop around it if there is an iterator
3257 ✗ if not Iterator.isEmpty(iter) then
3258 ✗ e := FOR_EQUATION(
3259 size = IfEquationBody.size(body) * Iterator.size(iter),
3260 iter = iter,
3261 body = {e},
3262 source = source,
3263 attr = attr
3264 );
3265 // inline if it has size 1
3266 ✗ e := Inline.inlineForEquation(e);
3267 end if;
3268 end makeIfEquationEqn;
3269
3270 public
3271 function toString
3272 input IfEquationBody body;
3273 input String indent = "";
3274 input String elseStr = "";
3275 input Boolean selfCall = false;
3276 output String str;
3277 algorithm
3278 str := elseStr;
3279
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 8 times.
26 if not selfCall then
3280 18 str := str + indent;
3281 end if;
3282
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 6 times.
26 if not Expression.isEnd(body.condition) then
3283 20 str := str + "if " + Expression.toString(body.condition) + " then\n";
3284 else
3285 6 str := str + "\n";
3286 end if;
3287
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 26 times.
52 for eqn in body.then_eqns loop
3288 26 str := str + Equation.toString(Pointer.access(eqn), indent + " ") + "\n";
3289 end for;
3290
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 18 times.
26 if isSome(body.else_if) then
3291 8 str := str + toString(Util.getOption(body.else_if), indent, indent + "else", true);
3292 end if;
3293
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 18 times.
26 if not selfCall then
3294 18 str := str + indent + "end if;";
3295 end if;
3296 end toString;
3297
3298 function map
3299 input output IfEquationBody ifBody;
3300 input MapFuncExp funcExp;
3301 input Option<MapFuncCref> funcCrefOpt;
3302 input MapFuncExpWrapper mapFunc;
3303 algorithm
3304 311 ifBody := mapEqnExpCref(
3305 ifBody = ifBody,
3306 func = function Pointer.apply(func = function Equation.map(funcExp = funcExp, funcCrefOpt = funcCrefOpt, mapFunc = mapFunc)),
3307 funcExp = funcExp,
3308 funcCrefOpt = funcCrefOpt,
3309 mapFunc = mapFunc);
3310 end map;
3311
3312 function mapCondition
3313 "only maps the conditions and not the body"
3314 input output IfEquationBody ifBody;
3315 input MapFuncExp funcExp;
3316 input Option<MapFuncCref> funcCrefOpt;
3317 input MapFuncExpWrapper mapFunc;
3318 protected
3319 Expression condition;
3320 algorithm
3321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 condition := mapFunc(ifBody.condition, funcExp);
3322
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 9 times.
20 if not referenceEq(condition, ifBody.condition) then
3323 11 ifBody.condition := condition;
3324 end if;
3325
3326 // map else if
3327 40 ifBody.else_if := Util.applyOption(ifBody.else_if, function mapCondition(funcExp = funcExp, funcCrefOpt = funcCrefOpt, mapFunc = mapFunc));
3328 end mapCondition;
3329
3330 function mapEqnExpCref
3331 input output IfEquationBody ifBody;
3332 input MapFuncEqnPtr func;
3333 input MapFuncExp funcExp;
3334 input Option<MapFuncCref> funcCrefOpt;
3335 input MapFuncExpWrapper mapFunc;
3336 protected
3337 Expression condition;
3338 IfEquationBody else_if, old_else_if;
3339 algorithm
3340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 634 times.
634 condition := mapFunc(ifBody.condition, funcExp);
3341
2/2
✓ Branch 0 taken 316 times.
✓ Branch 1 taken 318 times.
634 if not referenceEq(condition, ifBody.condition) then
3342 316 ifBody.condition := condition;
3343 end if;
3344
3345 // referenceEq for lists?
3346 634 ifBody.then_eqns := List.map(ifBody.then_eqns, func);
3347
3348
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 634 times.
✓ Branch 2 taken 321 times.
✓ Branch 3 taken 313 times.
634 if isSome(ifBody.else_if) then
3349 321 old_else_if := Util.getOption(ifBody.else_if);
3350 321 else_if := mapEqnExpCref(old_else_if, func, funcExp, funcCrefOpt, mapFunc);
3351
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 321 times.
321 if not referenceEq(else_if, old_else_if) then
3352 321 ifBody.else_if := SOME(else_if);
3353 end if;
3354 end if;
3355 end mapEqnExpCref;
3356
3357 function size
3358 "only considers first branch"
3359 input IfEquationBody body;
3360 input Boolean resize = false;
3361 output Integer size = sum(Equation.size(eqn, resize) for eqn in body.then_eqns);
3362 end size;
3363
3364 function isEqual
3365 input IfEquationBody body1;
3366 input IfEquationBody body2;
3367 output Boolean b;
3368 algorithm
3369
10/14
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✓ Branch 13 taken 6 times.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 6 times.
12 b := List.all(list(Equation.isEqualPtr(b1, b2) threaded for b1 in body1.then_eqns, b2 in body2.then_eqns), Util.id) and Util.optionEqual(body1.else_if, body2.else_if, isEqual);
3370 end isEqual;
3371
3372 function createNames
3373 input IfEquationBody body;
3374 input Pointer<Integer> idx;
3375 input String context;
3376 algorithm
3377
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 for eqn in body.then_eqns loop
3378 20 Equation.createName(eqn, idx, context);
3379 end for;
3380
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 11 times.
20 if isSome(body.else_if) then
3381 11 createNames(Util.getOption(body.else_if), idx, context);
3382 end if;
3383 end createNames;
3384
3385 function toStatement
3386 "converts an if equation body to an algorithmic statement"
3387 input IfEquationBody body;
3388 output list<tuple<Expression, list<Statement>>> stmts;
3389 protected
3390 tuple<Expression, list<Statement>> stmt;
3391 Expression condition = if Expression.isEnd(body.condition) then Expression.BOOLEAN(true) else body.condition;
3392 algorithm
3393
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
8 stmt := (condition, List.flatten(list(Equation.toStatement(Pointer.access(eqn)) for eqn in body.then_eqns)));
3394
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if isSome(body.else_if) then
3395 ✗ stmts := stmt :: toStatement(Util.getOption(body.else_if));
3396 else
3397 stmts := {stmt};
3398 end if;
3399 end toStatement;
3400
3401 function createResidual
3402 "needs the if equation to be split"
3403 input IfEquationBody body;
3404 input ComponentRef res;
3405 input Boolean new = false "set to true if the resulting pointer should be a new one";
3406 input Boolean allowFail = false;
3407 output IfEquationBody body_res;
3408 protected
3409 Pointer<Equation> eqn_ptr;
3410 algorithm
3411 ✗ body_res := IF_EQUATION_BODY(body.condition, {}, Util.applyOption(body.else_if, function createResidual(res = res, new = new, allowFail = allowFail)));
3412 body_res := match body.then_eqns
3413 case {eqn_ptr} algorithm
3414 ✗ body_res.then_eqns := Equation.createResidual(eqn_ptr, SOME(res), new, allowFail) :: body_res.then_eqns;
3415 then body_res;
3416 else algorithm
3417 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for:\n" + toString(body)});
3418 ✗ then fail();
3419 end match;
3420 end createResidual;
3421
3422 function inline
3423 "only works if the LHS of each branch are equal, so if it was solved and only has a single equation each branch"
3424 input IfEquationBody body;
3425 input output Equation eqn;
3426 protected
3427 Expression lhs, rhs;
3428 Boolean success;
3429 algorithm
3430 12 (lhs, success) := getLHS(body);
3431
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 if success then
3432 4 rhs := SimplifyExp.simplify(getRHS(body));
3433 4 eqn := Equation.makeAssignmentUpdate(eqn, lhs, rhs, Equation.getForIterator(eqn), Equation.getAttributes(eqn));
3434 end if;
3435 end inline;
3436
3437 function getLHS
3438 "needs the if equation to be split and equal lhs"
3439 input IfEquationBody body;
3440 input output Expression exp = Expression.END();
3441 output Boolean success = true;
3442 protected
3443 Pointer<Equation> eqn_ptr;
3444 Expression new_exp;
3445 algorithm
3446 exp := match body.then_eqns
3447 case {eqn_ptr} algorithm
3448
2/4
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 46 times.
46 SOME(new_exp) := Equation.getLHS(Pointer.access(eqn_ptr));
3449
4/4
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 22 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 12 times.
46 if Expression.isEnd(exp) or Expression.isEqual(exp, new_exp) then
3450
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 10 times.
34 if isSome(body.else_if) then
3451 24 (new_exp, success) := getLHS(Util.getOption(body.else_if), new_exp);
3452 end if;
3453 else
3454
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if Flags.isSet(Flags.FAILTRACE) then
3455 ✗ Error.addCompilerWarning(getInstanceName() + " failed because of ambiguous LHS for:\n" + toString(body));
3456 end if;
3457 12 success := false;
3458 end if;
3459 then new_exp;
3460 else algorithm
3461 ✗ if Flags.isSet(Flags.FAILTRACE) then
3462 ✗ Error.addCompilerWarning(getInstanceName() + " failed because of un-split if-equation:\n" + toString(body));
3463 end if;
3464 ✗ success := false;
3465 then exp;
3466 end match;
3467 end getLHS;
3468
3469 function getResidualExp
3470 "if-expression of the branch residuals, needs a single equation per branch"
3471 input IfEquationBody body;
3472 output Expression exp;
3473 protected
3474 Pointer<Equation> eqn_ptr;
3475 algorithm
3476 exp := match body.then_eqns
3477 case {eqn_ptr} algorithm
3478 exp := match Pointer.access(eqn_ptr)
3479 local
3480 IfEquationBody nested;
3481 ✗ case IF_EQUATION(body = nested) then getResidualExp(nested);
3482 ✗ else Equation.getResidualExp(Pointer.access(eqn_ptr));
3483 end match;
3484 ✗ if isSome(body.else_if) then
3485 ✗ exp := Expression.IF(Expression.typeOf(exp), body.condition, exp, getResidualExp(Util.getOption(body.else_if)));
3486 end if;
3487 then exp;
3488 else algorithm
3489 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because a branch does not have a single equation:\n" + toString(body)});
3490 ✗ then fail();
3491 end match;
3492 end getResidualExp;
3493
3494 function getRHS
3495 "needs the if equation to be split"
3496 input IfEquationBody body;
3497 output Expression exp = Expression.END();
3498 output Boolean success;
3499 protected
3500 Pointer<Equation> eqn_ptr;
3501 Expression new_exp, new_exp2;
3502 algorithm
3503 exp := match body.then_eqns
3504 case {eqn_ptr} algorithm
3505
2/4
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
20 SOME(new_exp) := Equation.getRHS(Pointer.access(eqn_ptr));
3506
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 11 times.
20 if isSome(body.else_if) then
3507 11 (new_exp2, success) := getRHS(Util.getOption(body.else_if));
3508
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if success then
3509 11 new_exp := Expression.IF(Expression.typeOf(new_exp), body.condition, new_exp, new_exp2);
3510 else
3511 new_exp := Expression.END();
3512 end if;
3513 else
3514 9 success := true;
3515 end if;
3516 then new_exp;
3517 else algorithm
3518 ✗ if Flags.isSet(Flags.FAILTRACE) then
3519 ✗ Error.addCompilerWarning(getInstanceName() + " failed because of un-split if-equation:\n" + toString(body));
3520 end if;
3521 ✗ success := false;
3522 then exp;
3523 end match;
3524 end getRHS;
3525
3526 function split
3527 "splits an if equation body with multiple equations into multiple bodies of each one equation."
3528 input IfEquationBody body;
3529 output list<IfEquationBody> bodies = {};
3530 protected
3531 list<Expression> conditions = {};
3532 Integer s = listLength(body.then_eqns);
3533 array<list<Pointer<Equation>>> then_eqns;
3534 Expression condition;
3535 Pointer<Equation> eqn;
3536 Option<IfEquationBody> tmp;
3537 algorithm
3538
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 if isSplittable(body, s) then
3539 37 then_eqns := arrayCreate(s, {});
3540 37 (conditions, then_eqns) := splitCollect(sortForSplit(body), conditions, then_eqns);
3541
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
114 for i in 1:arrayLength(then_eqns) loop
3542 tmp := NONE();
3543
2/2
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 40 times.
94 for tpl in List.zip(conditions, then_eqns[i]) loop
3544 54 (condition, eqn) := tpl;
3545 54 tmp := SOME(IF_EQUATION_BODY(condition, {eqn}, tmp));
3546 end for;
3547 40 bodies := Util.getOption(tmp) :: bodies;
3548 end for;
3549 else
3550 bodies := {body};
3551 end if;
3552 end split;
3553
3554 function isSplittable
3555 "an if equation can be split if all branches have the same size"
3556 input IfEquationBody body;
3557 input Integer s;
3558 output Boolean b = listLength(body.then_eqns) == s;
3559 algorithm
3560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if b then
3561 48 b := Util.applyOptionOrDefault(body.else_if, function isSplittable(s = s), true);
3562 end if;
3563 end isSplittable;
3564
3565 function isSplit
3566 "an if equation is already split if all branches only have one equation"
3567 input IfEquationBody body;
3568 output Boolean b = isSplittable(body, 1);
3569 end isSplit;
3570
3571 function simplify
3572 "removes unreachable branches by looking at literal conditions"
3573 input output Option<IfEquationBody> body;
3574 algorithm
3575 body := match body
3576 local
3577 IfEquationBody b;
3578
3579 case SOME(b) algorithm
3580 // if the condition is True -> cut later unreachable branches
3581
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 34 times.
36 if Expression.isTrue(b.condition) then
3582 2 b.condition := Expression.END();
3583 2 b.else_if := NONE();
3584 else
3585 34 b.else_if := simplify(b.else_if);
3586 end if;
3587 // if the condition is False -> skip this unreachable branch
3588
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 32 times.
36 if Expression.isFalse(b.condition) then
3589 4 body := b.else_if;
3590 else
3591 body := SOME(b);
3592 end if;
3593 then body;
3594
3595 // NONE() stays NONE()
3596 else body;
3597 end match;
3598 end simplify;
3599
3600 function isRecordOrTupleEquation
3601 "only checks first layer body if it returns multiple variables"
3602 input IfEquationBody body;
3603 output Boolean b;
3604 algorithm
3605 b := match body.then_eqns
3606 local
3607 Pointer<Equation> eqn_ptr;
3608 // just a tuple itself
3609 23 case {eqn_ptr} then Equation.isRecordOrTupleEquation(eqn_ptr);
3610 // at least 2 body equations -> tuple return
3611 case _ :: _ :: _ then true;
3612 else false;
3613 end match;
3614 end isRecordOrTupleEquation;
3615
3616 function getType
3617 "only look at one branch, all should have the same type"
3618 input IfEquationBody body;
3619 output Type ty;
3620 protected
3621 list<Type> body_types;
3622 algorithm
3623
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 36 times.
72 body_types := list(Equation.getType(Pointer.access(b)) for b in body.then_eqns);
3624
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 ty := if listLength(body_types) == 1 then listHead(body_types) else Type.TUPLE(body_types, NONE());
3625 end getType;
3626
3627 protected
3628 function sortForSplit
3629 "sorts the body equations by discrete and continuous to correctly split them
3630 ToDo: make it full type safe sorting"
3631 input output IfEquationBody body;
3632 protected
3633 list<Pointer<Equation>> discretes, continuous;
3634
3635 function compareLHS
3636 "Heuristic: often the lhs is a cref. If all branches are solved for the lhs,
3637 sorting them in the same way makes the split nice without algebraic loops."
3638 input Pointer<Equation> eqn1;
3639 input Pointer<Equation> eqn2;
3640 output Boolean b = 0 < Expression.compare(
3641 Util.getOption(Equation.getLHS(Pointer.access(eqn1))),
3642 Util.getOption(Equation.getLHS(Pointer.access(eqn2))));
3643 end compareLHS;
3644 algorithm
3645 48 (discretes, continuous) := List.splitOnTrue(body.then_eqns, Equation.isDiscrete);
3646 48 discretes := List.sort(discretes, compareLHS);
3647 48 continuous := List.sort(continuous, compareLHS);
3648 48 body.then_eqns := listAppend(discretes, continuous);
3649 body.else_if := Util.applyOption(body.else_if, sortForSplit);
3650 end sortForSplit;
3651
3652 function splitCollect
3653 "collects the equations of each branch to create single branch equation bodies afterwards."
3654 input IfEquationBody body;
3655 input output list<Expression> conditions;
3656 input output array<list<Pointer<Equation>>> then_eqns;
3657 protected
3658 Integer i = 1;
3659 algorithm
3660 48 conditions := body.condition :: conditions;
3661
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 48 times.
102 for eqn in body.then_eqns loop
3662 108 then_eqns[i] := eqn :: then_eqns[i];
3663 54 i := i + 1;
3664 end for;
3665
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 11 times.
48 if isSome(body.else_if) then
3666 11 (conditions, then_eqns) := splitCollect(Util.getOption(body.else_if), conditions, then_eqns);
3667 end if;
3668 end splitCollect;
3669 end IfEquationBody;
3670
3671 uniontype WhenEquationBody
3672 record WHEN_EQUATION_BODY "equation when condition then cr = exp, reinit(...), terminate(...) or assert(...)"
3673 Expression condition "the when-condition";
3674 list<WhenStatement> when_stmts "body statements";
3675 Option<WhenEquationBody> else_when "optional elsewhen body";
3676 end WHEN_EQUATION_BODY;
3677
3678 function fromFlatList
3679 input list<tuple<Expression, list<WhenStatement>>> flat_list "given in reverse order";
3680 input output Option<WhenEquationBody> body = NONE();
3681 algorithm
3682 body := match flat_list
3683 local
3684 Expression condition;
3685 list<WhenStatement> stmts;
3686 list<tuple<Expression, list<WhenStatement>>> tail;
3687 248 case (condition, stmts) :: tail then fromFlatList(tail, SOME(WHEN_EQUATION_BODY(condition, stmts, body)));
3688 else body;
3689 end match;
3690 end fromFlatList;
3691
3692 function toString
3693 input WhenEquationBody body;
3694 input String indent = "";
3695 input String elseStr = "";
3696 input Boolean selfCall = false;
3697 output String str;
3698 algorithm
3699 str := elseStr;
3700
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if not selfCall then
3701 1 str := str + indent;
3702 end if;
3703 1 str := str + "when " + Expression.toString(body.condition) + " then\n";
3704
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 for stmt in body.when_stmts loop
3705 1 str := str + WhenStatement.toString(stmt, indent + " ") + "\n";
3706 end for;
3707
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 if isSome(body.else_when) then
3708 ✗ str := str + toString(Util.getOption(body.else_when), indent, indent + "else", true);
3709 end if;
3710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if not selfCall then
3711 1 str := str + indent + "end when;";
3712 end if;
3713 end toString;
3714
3715 function size
3716 "returns the size only considering first when branch."
3717 input WhenEquationBody body;
3718 input Boolean resize = false;
3719 output Integer s = sum(WhenStatement.size(stmt, resize) for stmt in body.when_stmts);
3720 end size;
3721
3722 function getType
3723 "only works if properly split up"
3724 input WhenEquationBody body;
3725 output Type ty;
3726 algorithm
3727 ty := match body.when_stmts
3728 local
3729 WhenStatement stmt;
3730 198 case {stmt} then WhenStatement.getType(stmt);
3731 // allow multiple statements for no-return-value when statements
3732 case _ guard(List.all(list(WhenStatement.getType(st) for st in body.when_stmts), Type.isAny)) then Type.ANY();
3733 else algorithm
3734 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of not properly split up when equation body: " + toString(body)});
3735 ✗ then fail();
3736 end match;
3737 end getType;
3738
3739 function isEqual
3740 input WhenEquationBody body1;
3741 input WhenEquationBody body2;
3742 output Boolean b;
3743 algorithm
3744 ✗ b := Expression.isEqual(body1.condition, body2.condition) and List.all(list(WhenStatement.isEqual(b1, b2) threaded for b1 in body1.when_stmts, b2 in body2.when_stmts), Util.id) and Util.optionEqual(body1.else_when, body2.else_when, isEqual);
3745 end isEqual;
3746
3747 function getBodyAttributes
3748 "gets all conditions crefs as a list (has to be applied AFTER Event module)"
3749 input WhenEquationBody body;
3750 output list<ComponentRef> conditions;
3751 output list<WhenStatement> when_stmts = body.when_stmts;
3752 output Option<WhenEquationBody> else_when = body.else_when;
3753 protected
3754 function getConditions
3755 input Expression cond;
3756 output list<ComponentRef> conditions;
3757 algorithm
3758 conditions := match cond
3759 local
3760 ComponentRef cref;
3761 case Expression.CREF(cref = cref) then {cref};
3762
4/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 9 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 9 times.
54 case Expression.ARRAY() then List.flatten(list(getConditions(elem) for elem in cond.elements));
3763 case Expression.CALL() guard(Call.isNamed(cond.call, "initial")) then {};
3764 else algorithm
3765 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for condition: " + Expression.toString(cond)});
3766 ✗ then fail();
3767 end match;
3768 end getConditions;
3769 algorithm
3770 105 conditions := getConditions(body.condition);
3771 end getBodyAttributes;
3772
3773 function toStatement
3774 input WhenEquationBody body;
3775 output list<tuple<Expression, list<Statement>>> stmts;
3776 protected
3777 tuple<Expression, list<Statement>> stmt;
3778 algorithm
3779 ✗ stmt := (body.condition, list(WhenStatement.toStatement(st) for st in body.when_stmts));
3780 ✗ if isSome(body.else_when) then
3781 ✗ stmts := stmt :: toStatement(Util.getOption(body.else_when));
3782 else
3783 stmts := {stmt};
3784 end if;
3785 end toStatement;
3786
3787 function map
3788 input output WhenEquationBody whenBody;
3789 input MapFuncExp funcExp;
3790 input Option<MapFuncCref> funcCrefOpt;
3791 input MapFuncExpWrapper mapFunc;
3792 protected
3793 Expression condition;
3794 algorithm
3795
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5532 times.
5532 condition := mapFunc(whenBody.condition, funcExp);
3796
2/2
✓ Branch 0 taken 5294 times.
✓ Branch 1 taken 238 times.
5532 if not referenceEq(condition, whenBody.condition) then
3797 5294 whenBody.condition := condition;
3798 end if;
3799
3800 // ToDo reference eq for lists?
3801 5532 whenBody.when_stmts := List.map(whenBody.when_stmts, function WhenStatement.map(funcExp = funcExp, funcCrefOpt = funcCrefOpt, mapFunc = mapFunc));
3802
3803 // map else when
3804 whenBody.else_when := Util.applyOption(whenBody.else_when, function map(funcExp = funcExp, funcCrefOpt = funcCrefOpt, mapFunc = mapFunc));
3805 end map;
3806
3807 function mapCondition
3808 "only maps the conditions and not the body"
3809 input output WhenEquationBody whenBody;
3810 input MapFuncExp funcExp;
3811 input Option<MapFuncCref> funcCrefOpt;
3812 input MapFuncExpWrapper mapFunc;
3813 protected
3814 Expression condition;
3815 algorithm
3816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 condition := mapFunc(whenBody.condition, funcExp);
3817
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 61 times.
248 if not referenceEq(condition, whenBody.condition) then
3818 187 whenBody.condition := condition;
3819 end if;
3820
3821 // map else when
3822 496 whenBody.else_when := Util.applyOption(whenBody.else_when, function mapCondition(funcExp = funcExp, funcCrefOpt = funcCrefOpt, mapFunc = mapFunc));
3823 end mapCondition;
3824
3825 function split
3826 "this function splits up when equations while respecting to keep
3827 correct branches for assigned discrete states and reinitialized states.
3828 it also keeps all no return branches as one."
3829 input WhenEquationBody body;
3830 output list<WhenEquationBody> bodies = {};
3831 protected
3832 UnorderedMap<ComponentRef, CrefSet> discr_map = UnorderedMap.new<CrefSet>(ComponentRef.hash, ComponentRef.isEqual);
3833 UnorderedSet<ComponentRef> state_set = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3834 UnorderedSet<ComponentRef> discr_marks = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3835 list<tuple<Expression, list<WhenStatement>>> flat_when;
3836 list<tuple<Expression, list<WhenStatement>>> flat_new;
3837 list<ComponentRef> discretes, states;
3838 CrefSet set;
3839 Expression condition, acc_condition = Expression.EMPTY(Type.INTEGER());
3840 list<WhenStatement> stmts, assigns;
3841 Option<WhenStatement> stmt;
3842 Option<WhenEquationBody> new_body;
3843 algorithm
3844 // collect all discretes and states contained in the when equation body
3845 // and also flatten the when equation to a list
3846 55 flat_when := collectForSplit(SOME(body), discr_map, state_set);
3847 55 discretes := UnorderedMap.keyList(discr_map);
3848 55 states := UnorderedSet.toList(state_set);
3849
3850 // create a when equation for each discrete state
3851
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 55 times.
123 for disc in discretes loop
3852
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 if not UnorderedSet.contains(disc, discr_marks) then
3853 68 set := UnorderedMap.getSafe(disc, discr_map, sourceInfo());
3854
2/2
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 68 times.
136 for marked in UnorderedSet.toList(set) loop
3855 68 UnorderedSet.add(marked, discr_marks);
3856 end for;
3857 flat_new := {};
3858
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 68 times.
186 for tpl in flat_when loop
3859 118 (condition, stmts) := tpl;
3860 118 assigns := getAssignments(set, stmts);
3861 // if there is a statement: create the when body and combine with previous
3862 // conditions. if there is no statement in this branch, save the condition
3863 // negated for the next branch
3864
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 if not listEmpty(assigns) then
3865 118 condition := combineConditions(acc_condition, condition, false);
3866 acc_condition := Expression.EMPTY(Type.INTEGER());
3867 118 flat_new := (condition, assigns) :: flat_new;
3868 else
3869 ✗ acc_condition := combineConditions(acc_condition, condition, true);
3870 end if;
3871 end for;
3872 // create body from flat list and add to new bodies
3873 68 new_body := fromFlatList(flat_new);
3874
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
68 if isSome(new_body) then
3875 68 bodies := Util.getOption(new_body) :: bodies;
3876 else
3877 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName()
3878 + " failed because when partition for: " + ComponentRef.toString(disc)
3879 + " could not be recovered."});
3880 end if;
3881 end if;
3882 end for;
3883
3884 // create a when equation for each state
3885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 for state in states loop
3886 flat_new := {};
3887 ✗ for tpl in flat_when loop
3888 ✗ (condition, stmts) := tpl;
3889 // get first reinit - each branch should only have one
3890 // reinit per state
3891 ✗ stmt := getFirstReinit(state, stmts);
3892 // if there is a statement: create the when body and combine with previous
3893 // conditions. if there is no statement in this branch, save the condition
3894 // negated for the next branch
3895 ✗ if isSome(stmt) then
3896 ✗ condition := combineConditions(acc_condition, condition, false);
3897 acc_condition := Expression.EMPTY(Type.INTEGER());
3898 ✗ flat_new := (condition, {Util.getOption(stmt)}) :: flat_new;
3899 else
3900 ✗ acc_condition := combineConditions(acc_condition, condition, true);
3901 end if;
3902 end for;
3903 // create body from flat list and add to new bodies
3904 ✗ new_body := fromFlatList(flat_new);
3905 ✗ if isSome(new_body) then
3906 ✗ bodies := Util.getOption(new_body) :: bodies;
3907 else
3908 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName()
3909 + " failed because when partition for: " + ComponentRef.toString(state)
3910 + " could not be recovered."});
3911 end if;
3912 end for;
3913
3914 flat_new := {};
3915 // collect all statements that are not assign or reinit and combine them
3916
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 55 times.
142 for tpl in flat_when loop
3917 87 (condition, stmts) := tpl;
3918
6/6
✓ Branch 1 taken 118 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 124 times.
✓ Branch 4 taken 87 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 87 times.
211 stmts := list(stmt for stmt guard(not WhenStatement.isAssignOrReinit(stmt)) in stmts);
3919 // if there is a statement: create the when body and combine with previous
3920 // conditions. if there is no statement in this branch, save the condition
3921 // negated for the next branch
3922
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 81 times.
87 if not listEmpty(stmts) then
3923 6 condition := combineConditions(acc_condition, condition, false);
3924 acc_condition := Expression.EMPTY(Type.INTEGER());
3925 6 flat_new := (condition, stmts) :: flat_new;
3926 // create body from flat list and add to new bodies
3927 6 new_body := fromFlatList(flat_new);
3928
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if isSome(new_body) then
3929 6 bodies := Util.getOption(new_body) :: bodies;
3930 end if;
3931 else
3932 81 acc_condition := combineConditions(acc_condition, condition, true);
3933 end if;
3934 end for;
3935
3936 55 bodies := listReverse(bodies);
3937 end split;
3938
3939 function simplify
3940 input output Option<WhenEquationBody> body;
3941 algorithm
3942 body := match body
3943 local
3944 WhenEquationBody b;
3945 Expression condition;
3946 list<Expression> conditions;
3947
3948 // if the condition is an array, skip surplus of literal elements
3949 case SOME(b as WHEN_EQUATION_BODY(condition = condition as Expression.ARRAY())) algorithm
3950 44 b.else_when := simplify(b.else_when);
3951
6/6
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 80 times.
✓ Branch 4 taken 88 times.
✓ Branch 5 taken 44 times.
✓ Branch 6 taken 80 times.
✓ Branch 7 taken 44 times.
256 conditions := list(elem for elem guard(not Expression.isBoolean(elem)) in condition.elements);
3952
1/2
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
44 if listEmpty(conditions) then
3953 body := b.else_when;
3954 elseif List.hasOneElement(conditions) then
3955 8 b.condition := listHead(conditions);
3956 body := SOME(b);
3957 else
3958 108 b.condition := Expression.makeArrayCheckLiteral(Type.ARRAY(Type.BOOLEAN(), {Dimension.fromInteger(listLength(conditions))}), listArray(conditions));
3959 body := SOME(b);
3960 end if;
3961 then body;
3962
3963 // simplify condition
3964 case SOME(b) algorithm
3965 356 b.else_when := simplify(b.else_when);
3966 // if the condition is a literal boolean -> skip this unreachable branch
3967
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 346 times.
356 if Expression.isBoolean(b.condition) then
3968 10 body := b.else_when;
3969 else
3970 body := SOME(b);
3971 end if;
3972 then body;
3973
3974 // NONE() stays NONE()
3975 else body;
3976 end match;
3977 end simplify;
3978
3979 function getAllAssigned
3980 "returns all assigned discrete variables as expressions.
3981 Note: only needs to iterate first body because all need to have the same
3982 variables assigned. ModelicaSpecification 3.6, Section 8.6"
3983 input WhenEquationBody body;
3984 output list<ComponentRef> assigned = {};
3985 algorithm
3986
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 52 times.
104 for stmt in body.when_stmts loop
3987 assigned := match stmt
3988 local
3989 ComponentRef lhs;
3990 case WhenStatement.ASSIGN(lhs = Expression.CREF(cref = lhs)) then lhs :: assigned;
3991 else assigned;
3992 end match;
3993 end for;
3994 end getAllAssigned;
3995
3996 function isRecordOrTupleEquation
3997 "only checks first layer body if it returns multiple variables"
3998 input WhenEquationBody body;
3999 output Boolean b;
4000 algorithm
4001 b := match body.when_stmts
4002 local
4003 ComponentRef cref;
4004 // just a record or tuple itself
4005 case {WhenStatement.ASSIGN(lhs = Expression.TUPLE())} then true;
4006 case {WhenStatement.ASSIGN(lhs = Expression.RECORD())} then true;
4007 case {WhenStatement.ASSIGN(lhs = Expression.CREF(cref = cref))}
4008 67 then BVariable.checkCref(cref, BVariable.isRecord, sourceInfo());
4009 // multiple body equations -> tuple return
4010 case _ guard(List.count(body.when_stmts, WhenStatement.isAssign) > 1) then true;
4011 else false;
4012 end match;
4013 end isRecordOrTupleEquation;
4014
4015 protected
4016 type CrefSet = UnorderedSet<ComponentRef>;
4017 function collectForSplit
4018 "collects all discrete states and regular states for splitting up
4019 of a when equation. also flattens it to a list"
4020 input Option<WhenEquationBody> body_opt;
4021 input UnorderedMap<ComponentRef, CrefSet> discr_map;
4022 input UnorderedSet<ComponentRef> state_set;
4023 output list<tuple<Expression, list<WhenStatement>>> flat_when;
4024 protected
4025 WhenEquationBody body;
4026 algorithm
4027
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 87 times.
✓ Branch 3 taken 55 times.
142 if isSome(body_opt) then
4028 87 body := Util.getOption(body_opt);
4029
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 87 times.
211 for stmt in body.when_stmts loop
4030 () := match stmt
4031 local
4032 ComponentRef cref;
4033 Expression tpl;
4034
4035 case WhenStatement.ASSIGN(lhs = Expression.CREF(cref = cref)) algorithm
4036 118 addCrefsMap(discr_map, {cref});
4037 then ();
4038 case WhenStatement.ASSIGN(lhs = tpl as Expression.TUPLE()) algorithm
4039 ✗ addCrefsMap(discr_map, UnorderedSet.toList(Expression.extractCrefs(tpl)));
4040 then ();
4041 case WhenStatement.REINIT(stateVar = cref) algorithm
4042 ✗ UnorderedSet.add(cref, state_set);
4043 then ();
4044 case WhenStatement.ASSIGN() algorithm
4045 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName()
4046 + " failed because lhs of statement is not a cref: " + WhenStatement.toString(stmt)});
4047 ✗ then fail();
4048 else ();
4049 end match;
4050 end for;
4051 87 flat_when := (body.condition, body.when_stmts) :: collectForSplit(body.else_when, discr_map, state_set);
4052 else
4053 flat_when := {};
4054 end if;
4055 end collectForSplit;
4056
4057 function addCrefsMap
4058 input UnorderedMap<ComponentRef, CrefSet> discr_map;
4059 input list<ComponentRef> crefs;
4060 protected
4061 CrefSet set_new, set = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
4062 algorithm
4063
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 118 times.
236 for c in crefs loop
4064
2/2
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 68 times.
118 if UnorderedMap.contains(c, discr_map) then
4065 50 set_new := UnorderedMap.getSafe(c, discr_map, sourceInfo());
4066
1/2
✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
50 if not referenceEq(set, set_new) then
4067 50 set := UnorderedSet.union(set, set_new);
4068 end if;
4069 else
4070 68 UnorderedSet.add(c, set);
4071 end if;
4072 end for;
4073
4074
2/2
✓ Branch 0 taken 118 times.
✓ Branch 1 taken 118 times.
236 for c in crefs loop
4075 118 UnorderedMap.add(c, set, discr_map);
4076 end for;
4077 end addCrefsMap;
4078
4079 function getAssignments
4080 "returns all assignments for the crefs in crefSet and merges if necessary"
4081 input UnorderedSet<ComponentRef> crefSet;
4082 input list<WhenStatement> stmts;
4083 output list<WhenStatement> assigns = {};
4084 algorithm
4085
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 118 times.
308 for stmt in stmts loop
4086 () := match stmt
4087 local
4088 ComponentRef cref;
4089 Expression tpl;
4090
4091 case WhenStatement.ASSIGN(lhs = Expression.CREF(cref = cref))
4092 guard(UnorderedSet.contains(cref, crefSet)) algorithm
4093 assigns := stmt :: assigns;
4094 then ();
4095
4096 case WhenStatement.ASSIGN(lhs = tpl as Expression.TUPLE())
4097 guard(List.any(list(UnorderedSet.contains(c, crefSet) for c in UnorderedSet.toList(Expression.extractCrefs(tpl))), Util.id)) algorithm
4098 assigns := stmt :: assigns;
4099 then ();
4100
4101 else ();
4102 end match;
4103 end for;
4104 end getAssignments;
4105
4106 function getFirstReinit
4107 "returns the first reinit in the list that reinitializes cref"
4108 input ComponentRef cref;
4109 input list<WhenStatement> stmts;
4110 output Option<WhenStatement> assign = NONE();
4111 algorithm
4112 ✗ for stmt in stmts loop
4113 () := match stmt
4114 case WhenStatement.REINIT()
4115 guard(ComponentRef.isEqual(cref, stmt.stateVar)) algorithm
4116 ✗ assign := SOME(stmt); break;
4117 then ();
4118 else ();
4119 end match;
4120 end for;
4121 end getFirstReinit;
4122
4123 function combineConditions
4124 "combines to conditions with an AND. Ignores first condition if EMPTY.
4125 May invert second condition."
4126 input Expression acc_condition;
4127 input output Expression condition;
4128 input Boolean invert;
4129 algorithm
4130
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 124 times.
205 if invert then
4131 81 condition := Expression.logicNegate(condition);
4132 end if;
4133
2/2
✓ Branch 1 taken 173 times.
✓ Branch 2 taken 32 times.
205 if not Expression.isEmpty(acc_condition) then
4134 32 condition := Expression.LBINARY(acc_condition, Operator.makeAnd(Type.BOOLEAN()), condition);
4135 end if;
4136 end combineConditions;
4137 end WhenEquationBody;
4138
4139 uniontype WhenStatement
4140 record ASSIGN " left_cr = right_exp"
4141 Expression lhs "left hand side of assignment";
4142 Expression rhs "right hand side of assignment";
4143 DAE.ElementSource source "origin of assignment";
4144 end ASSIGN;
4145
4146 record REINIT "Reinit Statement"
4147 ComponentRef stateVar "State variable to reinit";
4148 Expression value "Value after reinit";
4149 DAE.ElementSource source "origin of statement";
4150 end REINIT;
4151
4152 record ASSERT
4153 Expression condition;
4154 Expression message;
4155 Expression level;
4156 DAE.ElementSource source "origin of statement";
4157 end ASSERT;
4158
4159 record TERMINATE
4160 "The Modelica built-in terminate(msg)"
4161 Expression message;
4162 DAE.ElementSource source "the origin of the component/equation/algorithm";
4163 end TERMINATE;
4164
4165 record NORETCALL
4166 "call with no return value, i.e. no equation.
4167 Typically side effect call of external function but also
4168 Connections.* i.e. Connections.root(...) functions."
4169 Expression exp;
4170 DAE.ElementSource source "the origin of the component/equation/algorithm";
4171 end NORETCALL;
4172
4173 function toString
4174 input WhenStatement stmt;
4175 input output String str = "";
4176 algorithm
4177 str := match stmt
4178 local
4179 Expression lhs, rhs, value, condition, message, level;
4180 ComponentRef stateVar;
4181 1 case ASSIGN(lhs = lhs, rhs = rhs) then str + Expression.toString(lhs) + " := " + Expression.toString(rhs);
4182 ✗ case REINIT(stateVar = stateVar, value = value) then str + "reinit(" + ComponentRef.toString(stateVar) + ", " + Expression.toString(value) + ")";
4183 ✗ case ASSERT(condition = condition, message = message, level = level) then str + "assert(" + Expression.toString(condition) + ", " + Expression.toString(message) + ", " + Expression.toString(level) + ")";
4184 ✗ case TERMINATE(message = message) then str + "terminate(" + Expression.toString(message) + ")";
4185 ✗ case NORETCALL(exp = value) then str + Expression.toString(value);
4186 ✗ else str + getInstanceName() + " failed.";
4187 end match;
4188 end toString;
4189
4190 function isEqualTpl
4191 input tuple<WhenStatement, WhenStatement> tpl;
4192 output Boolean b;
4193 protected
4194 WhenStatement stmt1;
4195 WhenStatement stmt2;
4196 algorithm
4197 ✗ (stmt1, stmt2) := tpl;
4198 ✗ b := isEqual(stmt1, stmt2);
4199 end isEqualTpl;
4200
4201 function isEqual
4202 input WhenStatement stmt1;
4203 input WhenStatement stmt2;
4204 output Boolean b;
4205 algorithm
4206 b := match (stmt1, stmt2)
4207 ✗ case (ASSIGN(), ASSIGN()) then Expression.isEqual(stmt1.lhs, stmt2.lhs) and Expression.isEqual(stmt1.rhs, stmt2.rhs);
4208 ✗ case (REINIT(), REINIT()) then ComponentRef.isEqual(stmt1.stateVar, stmt2.stateVar) and Expression.isEqual(stmt1.value, stmt2.value);
4209 ✗ case (ASSERT(), ASSERT()) then Expression.isEqual(stmt1.condition, stmt2.condition) and Expression.isEqual(stmt1.message, stmt2.message) and Expression.isEqual(stmt1.level, stmt2.level);
4210 ✗ case (TERMINATE(), TERMINATE()) then Expression.isEqual(stmt1.message, stmt2.message);
4211 ✗ case (NORETCALL(), NORETCALL()) then Expression.isEqual(stmt1.exp, stmt2.exp);
4212 else false;
4213 end match;
4214 end isEqual;
4215
4216 function toStatement
4217 input WhenStatement wstmt;
4218 output Statement stmt;
4219 algorithm
4220 stmt := match wstmt
4221 15 case ASSIGN() then Statement.ASSIGNMENT(wstmt.lhs, wstmt.rhs, Expression.typeOf(wstmt.lhs), wstmt.source);
4222 ✗ case REINIT() then Statement.REINIT(Expression.fromCref(wstmt.stateVar), wstmt.value, wstmt.source);
4223 ✗ case ASSERT() then Statement.ASSERT(wstmt.condition, wstmt.message, wstmt.level, wstmt.source);
4224 ✗ case TERMINATE() then Statement.TERMINATE(wstmt.message, wstmt.source);
4225 ✗ case NORETCALL() then Statement.NORETCALL(wstmt.exp, wstmt.source);
4226 else algorithm
4227 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unrecognized statement: " + toString(wstmt)});
4228 ✗ then fail();
4229 end match;
4230 end toStatement;
4231
4232 function toEquation
4233 "make assignments for assignment statements and an algorithm otherwise"
4234 input WhenStatement stmt;
4235 input EquationAttributes attr;
4236 input Boolean init;
4237 output Equation eqn;
4238 algorithm
4239 eqn := match stmt
4240 8 case ASSIGN() then Equation.makeAssignmentEqn(stmt.lhs, stmt.rhs, Iterator.EMPTY(), attr);
4241 ✗ else Equation.setAttributes(Pointer.access(Equation.makeAlgorithm({toStatement(stmt)}, init)), attr);
4242 end match;
4243 end toEquation;
4244
4245 function size
4246 input WhenStatement stmt;
4247 input Boolean resize = false;
4248 output Integer s;
4249 algorithm
4250 s := match stmt
4251 414 case ASSIGN() then Type.sizeOf(Expression.typeOf(stmt.lhs), resize);
4252 else 0;
4253 end match;
4254 end size;
4255
4256 function isAssign
4257 input WhenStatement stmt;
4258 output Boolean b;
4259 algorithm
4260 b := match stmt
4261 case ASSIGN() then true;
4262 else false;
4263 end match;
4264 end isAssign;
4265
4266 function isAssignOrReinit
4267 input WhenStatement stmt;
4268 output Boolean b;
4269 algorithm
4270 b := match stmt
4271 case ASSIGN() then true;
4272 case REINIT() then true;
4273 else false;
4274 end match;
4275 end isAssignOrReinit;
4276
4277 function getType
4278 input WhenStatement stmt;
4279 output Type ty;
4280 algorithm
4281 ty := match stmt
4282 192 case ASSIGN() then Expression.typeOf(stmt.lhs);
4283 else Type.ANY();
4284 end match;
4285 end getType;
4286
4287 function map
4288 input output WhenStatement stmt;
4289 input MapFuncExp funcExp;
4290 input Option<MapFuncCref> funcCrefOpt;
4291 input MapFuncExpWrapper mapFunc;
4292 algorithm
4293 stmt := match stmt
4294 local
4295 MapFuncCref funcCref;
4296 Expression lhs, rhs, value, condition, message;
4297 ComponentRef stateVar;
4298
4299 case ASSIGN()
4300 algorithm
4301
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5426 times.
5426 lhs := mapFunc(stmt.lhs, funcExp);
4302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5426 times.
5426 rhs := mapFunc(stmt.rhs, funcExp);
4303
2/2
✓ Branch 0 taken 5183 times.
✓ Branch 1 taken 243 times.
5426 if not referenceEq(lhs, stmt.lhs) then
4304 5183 stmt.lhs := lhs;
4305 end if;
4306
2/2
✓ Branch 0 taken 3640 times.
✓ Branch 1 taken 1786 times.
5426 if not referenceEq(rhs, stmt.rhs) then
4307 3640 stmt.rhs := rhs;
4308 end if;
4309 then stmt;
4310
4311 case REINIT()
4312 algorithm
4313 ✗ if isSome(funcCrefOpt) then
4314 ✗ SOME(funcCref) := funcCrefOpt;
4315 ✗ stateVar := funcCref(stmt.stateVar);
4316 ✗ if not referenceEq(stateVar, stmt.stateVar) then
4317 ✗ stmt.stateVar := stateVar;
4318 end if;
4319 end if;
4320 ✗ value := mapFunc(stmt.value, funcExp);
4321 ✗ if not referenceEq(value, stmt.value) then
4322 ✗ stmt.value := value;
4323 end if;
4324 then stmt;
4325
4326 case ASSERT()
4327 algorithm
4328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106 times.
106 condition := mapFunc(stmt.condition, funcExp);
4329
1/2
✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
106 if not referenceEq(condition, stmt.condition) then
4330 106 stmt.condition := condition;
4331 end if;
4332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106 times.
106 message := mapFunc(stmt.message, funcExp);
4333
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 30 times.
106 if not referenceEq(message, stmt.message) then
4334 76 stmt.message := message;
4335 end if;
4336 then stmt;
4337
4338 case TERMINATE() then stmt;
4339
4340 case NORETCALL()
4341 algorithm
4342 ✗ value := mapFunc(stmt.exp, funcExp);
4343 ✗ if not referenceEq(value, stmt.exp) then
4344 ✗ stmt.exp := value;
4345 end if;
4346 then stmt;
4347
4348 else stmt;
4349 end match;
4350 end map;
4351
4352 function convert
4353 input WhenStatement stmt;
4354 output OldBackendDAE.WhenOperator oldStmt;
4355 algorithm
4356 oldStmt := match stmt
4357 99 case ASSIGN() then OldBackendDAE.ASSIGN(
4358 left = Expression.toDAE(stmt.lhs),
4359 right = Expression.toDAE(stmt.rhs),
4360 source = stmt.source
4361 );
4362
4363 ✗ case REINIT() then OldBackendDAE.REINIT(
4364 stateVar = ComponentRef.toDAE(stmt.stateVar),
4365 value = Expression.toDAE(stmt.value),
4366 source = stmt.source
4367 );
4368
4369 18 case ASSERT() then OldBackendDAE.ASSERT(
4370 condition = Expression.toDAE(stmt.condition),
4371 message = Expression.toDAE(stmt.message),
4372 level = Expression.toDAE(stmt.level),
4373 source = stmt.source
4374 );
4375
4376 ✗ case TERMINATE() then OldBackendDAE.TERMINATE(
4377 message = Expression.toDAE(stmt.message),
4378 source = stmt.source
4379 );
4380
4381 6 case NORETCALL() then OldBackendDAE.NORETCALL(
4382 exp = Expression.toDAE(stmt.exp),
4383 source = stmt.source
4384 );
4385
4386 else algorithm
4387 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unrecognized statement: " + toString(stmt)});
4388 ✗ then fail();
4389 end match;
4390 end convert;
4391 end WhenStatement;
4392
4393 uniontype EquationAttributes
4394 record EQUATION_ATTRIBUTES
4395 Option<Pointer<Equation>> derivative "if the equation has been differentiated w.r.t time already";
4396 Option<Pointer<Variable>> residualVar "also used to represent the equation itself";
4397 Option<Integer> clock_idx "only set if clocked eq";
4398 Boolean residual "true if in residual form";
4399 Boolean exclusively_initial "true if in initial equation block";
4400 Evaluation.Stages evalStages "evaluation stages (prior used for DAE mode, still necessary?)";
4401 EquationKind kind "continuous, clocked, discrete, empty";
4402 Option<OptimizerExpression> optimizerExpression "dynamic optimization component: Mayer, Lagrange, Path, Boundary";
4403 end EQUATION_ATTRIBUTES;
4404
4405 function toString
4406 input EquationAttributes attr;
4407 input String indent = "";
4408 output String str;
4409 algorithm
4410 str := match attr
4411 local
4412 Pointer<Variable> residualVar;
4413 case EQUATION_ATTRIBUTES(residualVar = SOME(residualVar))
4414 1130 then indent + "(" + ComponentRef.toString(BVariable.getVarName(residualVar)) + ")";
4415 else "";
4416 end match;
4417 end toString;
4418
4419 function setKind
4420 input output EquationAttributes attr;
4421 input EquationKind kind;
4422 input Option<Integer> clock_idx = NONE();
4423 algorithm
4424 24 attr.kind := kind;
4425 attr.clock_idx := clock_idx;
4426 end setKind;
4427
4428 function setResidualVar
4429 input output EquationAttributes attr;
4430 input Pointer<Variable> residualVar;
4431 algorithm
4432 11087 attr.residualVar := SOME(residualVar);
4433 end setResidualVar;
4434
4435 function getResidualVar
4436 input EquationAttributes attr;
4437 output Pointer<Variable> residualVar;
4438 algorithm
4439 try
4440
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 277975 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 277975 times.
277975 SOME(residualVar) := attr.residualVar;
4441 else
4442 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of missing residualVar!"});
4443 ✗ fail();
4444 end try;
4445 end getResidualVar;
4446
4447 function convert
4448 input EquationAttributes attributes;
4449 output OldBackendDAE.EquationAttributes oldAttributes;
4450 algorithm
4451
3/4
✗ Branch 2 not taken.
✓ Branch 3 taken 12003 times.
✓ Branch 4 taken 170 times.
✓ Branch 5 taken 11833 times.
12173 oldAttributes := OldBackendDAE.EQUATION_ATTRIBUTES(
4452 differentiated = isSome(attributes.derivative),
4453 kind = convertEquationKind(attributes.kind, attributes.clock_idx, attributes.exclusively_initial),
4454 evalStages = Evaluation.Stages.convert(attributes.evalStages));
4455 end convert;
4456 end EquationAttributes;
4457
4458 function default
4459 input EquationKind kind;
4460 input Boolean exclusively_initial;
4461 input Option<Integer> clock_idx = NONE();
4462 input Option<OptimizerExpression> optimizerExpression = NONE();
4463 output EquationAttributes attr;
4464 algorithm
4465
2/2
✓ Branch 0 taken 6900 times.
✓ Branch 1 taken 1729 times.
15529 attr := EQUATION_ATTRIBUTES(
4466 derivative = NONE(),
4467 residualVar = NONE(),
4468 clock_idx = clock_idx,
4469 residual = false,
4470 exclusively_initial = exclusively_initial,
4471 evalStages = NBEvaluation.DEFAULT_STAGES,
4472 kind = kind,
4473 optimizerExpression = optimizerExpression);
4474 end default;
4475
4476 type EquationKind = enumeration(CONTINUOUS, DISCRETE, CLOCKED, EMPTY, UNKNOWN);
4477
4478 function convertEquationKind
4479 input EquationKind eqKind;
4480 input Option<Integer> clock_idx;
4481 input Boolean exclusively_initial;
4482 output OldBackendDAE.EquationKind oldEqKind;
4483 algorithm
4484 oldEqKind := match (eqKind, clock_idx)
4485 local
4486 Integer clk;
4487 case (_, _) guard(exclusively_initial) then OldBackendDAE.INITIAL_EQUATION();
4488 case (EquationKind.CONTINUOUS, NONE()) then OldBackendDAE.DYNAMIC_EQUATION();
4489 24 case (EquationKind.CLOCKED, SOME(clk)) then OldBackendDAE.CLOCKED_EQUATION(clk);
4490 case (EquationKind.DISCRETE, NONE()) then OldBackendDAE.DISCRETE_EQUATION();
4491 case (EquationKind.EMPTY, NONE()) then OldBackendDAE.AUX_EQUATION();
4492 case (EquationKind.UNKNOWN, NONE()) then OldBackendDAE.UNKNOWN_EQUATION_KIND();
4493 case (_, SOME(_)) algorithm
4494 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the non-clock equation kind "
4495 + equationKindString(eqKind, clock_idx, exclusively_initial) + " has a clock index."});
4496 ✗ then fail();
4497 case (EquationKind.CLOCKED, NONE()) algorithm
4498 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because no clock index was provided for clocked equation."});
4499 ✗ then fail();
4500 else algorithm
4501 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " for an unknown reason."});
4502 ✗ then fail();
4503 end match;
4504 end convertEquationKind;
4505
4506 function equationKindString
4507 input EquationKind eqKind;
4508 input Option<Integer> clock_idx;
4509 input Boolean exclusively_initial;
4510 output String str;
4511 algorithm
4512 str := match eqKind
4513 case EquationKind.CONTINUOUS then "[CONT";
4514 case EquationKind.CLOCKED then "[CLCK";
4515 case EquationKind.DISCRETE then "[DISC";
4516 case EquationKind.EMPTY then "[EMTY";
4517 else "[UKWN";
4518 end match;
4519 ✗ str := if exclusively_initial then "[INI]" + str else "[DAE]" + str;
4520 ✗ if isSome(clock_idx) then
4521 ✗ str := str + "(" + intString(Util.getOption(clock_idx)) + ")]";
4522 else
4523 ✗ str := str + "]";
4524 end if;
4525 end equationKindString;
4526
4527 uniontype EquationPointers
4528 record EQUATION_POINTERS
4529 UnorderedMap<ComponentRef, Integer> map "Map for cref->index";
4530 ExpandableArray<Pointer<Equation>> eqArr;
4531 end EQUATION_POINTERS;
4532
4533 function toString
4534 input EquationPointers equations;
4535 input output String str = "";
4536 input Option<array<tuple<Integer,Integer>>> mapping_opt = NONE();
4537 input Boolean printEmpty = true;
4538 input Option<UnorderedSet<String>> filter_opt = NONE();
4539 protected
4540 Integer luI = lastUsedIndex(equations);
4541 Integer length, scal_start, current_index = 1;
4542 String index;
4543 Boolean useMapping = isSome(mapping_opt);
4544 Boolean filterEqs = isSome(filter_opt);
4545 array<tuple<Integer,Integer>> mapping = listArray({});
4546 UnorderedSet<String> filter = UnorderedSet.new(stringHashDjb2, stringEq);
4547 Pointer<Equation> eqn;
4548 algorithm
4549 // check if mapping is used
4550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if useMapping then
4551 length := 15;
4552 ✗ mapping := Util.getOption(mapping_opt);
4553 else
4554 length := 10;
4555 end if;
4556
4557 // check if filter is used
4558
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if filterEqs then
4559 ✗ filter := Util.getOption(filter_opt);
4560 ✗ str := "Filtered " + str;
4561 end if;
4562
4563
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if printEmpty or luI > 0 then
4564 2 str := StringUtil.headline_4(str + " Equations (" + intString(EquationPointers.size(equations)) + "/" + intString(scalarSize(equations, true)) + ")");
4565
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
7 for i in 1:luI loop
4566
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 if ExpandableArray.occupied(i, equations.eqArr) then
4567 5 eqn := ExpandableArray.get(i, equations.eqArr);
4568
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
5 if not filterEqs or UnorderedSet.contains(ComponentRef.toString(Equation.getEqnName(eqn)), filter) then
4569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if useMapping then
4570 ✗ (scal_start, _) := mapping[current_index];
4571 ✗ index := "(" + intString(current_index) + "|" + intString(scal_start) + ")";
4572 else
4573 5 index := "(" + intString(current_index) + ")";
4574 end if;
4575 5 index := index + StringUtil.repeat(" ", length - stringLength(index));
4576 5 str := str + Equation.toString(Pointer.access(eqn), index) + "\n";
4577 end if;
4578 5 current_index := current_index + 1;
4579 end if;
4580 end for;
4581 2 str := str + "\n";
4582 else
4583 str := "";
4584 end if;
4585 end toString;
4586
4587 function empty
4588 "Creates an empty EquationPointers using given size."
4589 input Integer size = BaseHashTable.bigBucketSize;
4590 output EquationPointers equationPointers;
4591 protected
4592 Integer arr_size, bucketSize;
4593 algorithm
4594 arr_size := max(size, BaseHashTable.lowBucketSize);
4595 13446 bucketSize := Util.nextPrime(arr_size);
4596 13446 equationPointers := EQUATION_POINTERS(UnorderedMap.new<Integer>(ComponentRef.hash, ComponentRef.isEqual, bucketSize), ExpandableArray.new(arr_size, Pointer.create(DUMMY_EQUATION())));
4597 end empty;
4598
4599 function clone
4600 input EquationPointers equations;
4601 input Boolean shallow = true;
4602 output EquationPointers new;
4603 algorithm
4604
2/2
✓ Branch 0 taken 188 times.
✓ Branch 1 taken 194 times.
382 if shallow then
4605 188 new := fromList(toList(equations));
4606 else
4607
4/4
✓ Branch 1 taken 4437 times.
✓ Branch 2 taken 194 times.
✓ Branch 3 taken 4437 times.
✓ Branch 4 taken 194 times.
4631 new := fromList(list(Pointer.create(Pointer.access(eqn)) for eqn in toList(equations)));
4608 end if;
4609 end clone;
4610
4611 function size
4612 "returns the number of elements, not the actual scalarized number of equations!"
4613 input EquationPointers equations;
4614 output Integer sz = ExpandableArray.getNumberOfElements(equations.eqArr);
4615 end size;
4616
4617 function scalarSize
4618 "returns the scalar size."
4619 input EquationPointers equations;
4620 input Boolean resize = false;
4621 output Integer sz = 0;
4622 algorithm
4623
2/2
✓ Branch 1 taken 8850 times.
✓ Branch 2 taken 438 times.
9288 for eqn_ptr in toList(equations) loop
4624 8850 sz := sz + Equation.size(eqn_ptr, resize);
4625 end for;
4626 end scalarSize;
4627
4628 function lastUsedIndex
4629 "returns the last used index != size!"
4630 input EquationPointers equations;
4631 output Integer sz = ExpandableArray.getLastUsedIndex(equations.eqArr);
4632 end lastUsedIndex;
4633
4634 function toList
4635 "Creates a EquationPointer list from EquationPointers."
4636 input EquationPointers equations;
4637 output list<Pointer<Equation>> eqn_lst;
4638 algorithm
4639 6679 eqn_lst := ExpandableArray.toList(equations.eqArr);
4640 end toList;
4641
4642 function fromList
4643 input list<Pointer<Equation>> eq_lst;
4644 output EquationPointers equations;
4645 algorithm
4646 13393 equations := empty(listLength(eq_lst));
4647 13393 equations := addList(eq_lst, equations);
4648 end fromList;
4649
4650 function addList
4651 input list<Pointer<Equation>> eq_lst;
4652 input output EquationPointers equations;
4653 algorithm
4654 27623 equations := List.fold(eq_lst, function add(), equations);
4655 end addList;
4656
4657 function removeList
4658 "Removes a list of equations from the EquationPointers structure."
4659 input list<Pointer<Equation>> eq_lst;
4660 input output EquationPointers equations;
4661 algorithm
4662 381 equations := List.fold(eq_lst, function remove(), equations);
4663 381 equations := compress(equations);
4664 end removeList;
4665
4666 function removeCheck
4667 input output EquationPointers equations;
4668 input checkEqn func;
4669 protected
4670 list<Pointer<Equation>> eqns;
4671 algorithm
4672
6/8
✗ Branch 1 not taken.
✓ Branch 2 taken 7212 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7212 times.
✓ Branch 7 taken 7212 times.
✓ Branch 8 taken 570 times.
✓ Branch 9 taken 7212 times.
✓ Branch 10 taken 570 times.
7782 eqns := list(eqn for eqn guard(not func(eqn)) in toList(equations));
4673 570 equations := fromList(eqns);
4674 end removeCheck;
4675
4676 function add
4677 input Pointer<Equation> eqn;
4678 input output EquationPointers equations;
4679 protected
4680 ComponentRef name;
4681 Integer index;
4682 algorithm
4683 151028 name := Equation.getEqnName(eqn);
4684 () := match UnorderedMap.get(name, equations.map)
4685 case SOME(index) guard(index > 0) algorithm
4686 619 ExpandableArray.update(index, eqn, equations.eqArr);
4687 then ();
4688 else algorithm
4689 150409 (_, index) := ExpandableArray.add(eqn, equations.eqArr);
4690 150409 UnorderedMap.add(name, index, equations.map);
4691 then ();
4692 end match;
4693 end add;
4694
4695 function remove
4696 "Removes an equation pointer identified by its (residual var) name from the set."
4697 input Pointer<Equation> eqn;
4698 input output EquationPointers equations "only an output for mapping";
4699 protected
4700 ComponentRef name;
4701 Integer index;
4702 algorithm
4703 92 name := Equation.getEqnName(eqn);
4704 () := match UnorderedMap.get(name, equations.map)
4705 case SOME(index) guard(index > 0) algorithm
4706 92 ExpandableArray.delete(index, equations.eqArr);
4707 // set the index to -1 to avoid removing entries
4708 92 UnorderedMap.add(name, -1, equations.map);
4709 then ();
4710 else ();
4711 end match;
4712 end remove;
4713
4714 function map
4715 "Traverses all equations and applies a function to them."
4716 input output EquationPointers equations;
4717 input MapFuncEqn func;
4718 protected
4719 Pointer<Equation> eq_ptr;
4720 Equation eq, new_eq;
4721 list<String> followEquations = Flags.getConfigStringList(Flags.DEBUG_FOLLOW_EQUATIONS);
4722 Boolean debug = not listEmpty(followEquations);
4723 UnorderedSet<String> debug_eqns = UnorderedSet.fromList(followEquations, stringHashDjb2, stringEq);
4724 algorithm
4725
4726
2/2
✓ Branch 1 taken 5564 times.
✓ Branch 2 taken 6125 times.
142458 for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop
4727
2/2
✓ Branch 1 taken 128852 times.
✓ Branch 2 taken 1917 times.
130769 if ExpandableArray.occupied(i, equations.eqArr) then
4728 128852 eq_ptr := ExpandableArray.get(i, equations.eqArr);
4729 128852 eq := Pointer.access(eq_ptr);
4730
2/2
✓ Branch 0 taken 128828 times.
✓ Branch 1 taken 24 times.
128852 new_eq := func(eq);
4731
2/2
✓ Branch 0 taken 43442 times.
✓ Branch 1 taken 85410 times.
128852 if not referenceEq(eq, new_eq) then
4732 // Do not update the expandable array entry, but the pointer itself
4733
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 43442 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
43442 if debug and (UnorderedSet.contains(ComponentRef.toString(Equation.getEqnName(eq_ptr)), debug_eqns)
4734 or UnorderedSet.contains(ComponentRef.toString(Equation.getEqnName(Pointer.create(new_eq))), debug_eqns))
4735 and not Equation.equalName(Pointer.create(eq), Pointer.create(new_eq)) then
4736 ✗ print("[debugFollowEquations] The equation:\n" + Equation.toString(eq) + "\nGets replaced by:\n" + Equation.toString(new_eq) + "\n");
4737 end if;
4738 43442 Pointer.update(eq_ptr, new_eq);
4739 end if;
4740 end if;
4741 end for;
4742 end map;
4743
4744 function mapPtr
4745 "Traverses all equations wrapped in pointers and applies a function to them.
4746 Note: the equation can only be updated if the function itself updates it!"
4747 input EquationPointers equations;
4748 input MapFuncEqnPtr func;
4749 algorithm
4750
2/2
✓ Branch 1 taken 727 times.
✓ Branch 2 taken 806 times.
15026 for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop
4751
2/2
✓ Branch 1 taken 13487 times.
✓ Branch 2 taken 6 times.
13493 if ExpandableArray.occupied(i, equations.eqArr) then
4752
2/2
✓ Branch 0 taken 9615 times.
✓ Branch 1 taken 3872 times.
13487 func(ExpandableArray.get(i, equations.eqArr));
4753 end if;
4754 end for;
4755 end mapPtr;
4756
4757 function mapExp
4758 "Traverses all expressions of all equations and applies a function to it.
4759 Optional second input to also traverse crefs, only needed for simple
4760 eqns, when eqns and algorithms."
4761 input output EquationPointers equations;
4762 input MapFuncExp funcExp;
4763 input Option<MapFuncCref> funcCrefOpt = NONE();
4764 input MapFuncExpWrapper mapFunc = Expression.map;
4765 protected
4766 Pointer<Equation> eq_ptr;
4767 Equation eq, new_eq;
4768 algorithm
4769
2/2
✓ Branch 1 taken 6217 times.
✓ Branch 2 taken 5491 times.
117046 for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop
4770
2/2
✓ Branch 1 taken 103433 times.
✓ Branch 2 taken 1905 times.
105338 if ExpandableArray.occupied(i, equations.eqArr) then
4771 103433 eq_ptr := ExpandableArray.get(i, equations.eqArr);
4772 103433 eq := Pointer.access(eq_ptr);
4773 103433 new_eq := Equation.map(eq, funcExp, funcCrefOpt, mapFunc);
4774
2/2
✓ Branch 0 taken 101487 times.
✓ Branch 1 taken 1946 times.
103433 if not referenceEq(eq, new_eq) then
4775 // Do not update the expandable array entry, but the pointer itself
4776 101487 Pointer.update(eq_ptr, new_eq);
4777 end if;
4778 end if;
4779 end for;
4780 end mapExp;
4781
4782 function mapRemovePtr
4783 "Traverses all equation pointers and may invoke to remove the equation pointer
4784 (does not affect other instances of the equation)"
4785 input output EquationPointers equations;
4786 input checkEqn func;
4787 protected
4788 Pointer<Equation> eq_ptr;
4789 algorithm
4790
2/2
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 7 times.
4127 for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop
4791
1/2
✓ Branch 1 taken 3920 times.
✗ Branch 2 not taken.
3920 if ExpandableArray.occupied(i, equations.eqArr) then
4792 3920 eq_ptr := ExpandableArray.get(i, equations.eqArr);
4793
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 3896 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 3896 times.
3920 if func(eq_ptr) then
4794 24 equations := remove(eq_ptr, equations);
4795 end if;
4796 end if;
4797 end for;
4798 207 equations := compress(equations);
4799 end mapRemovePtr;
4800
4801 function mapRes
4802 "maps the residual variable"
4803 input EquationPointers equations;
4804 input mapFunc func;
4805 partial function mapFunc
4806 input Pointer<Variable> var;
4807 end mapFunc;
4808 algorithm
4809
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
123 for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop
4810
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
108 if ExpandableArray.occupied(i, equations.eqArr) then
4811
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 func(Equation.getResidualVar(ExpandableArray.get(i, equations.eqArr)));
4812 end if;
4813 end for;
4814 end mapRes;
4815
4816 function fold<T>
4817 "Traverses all equations and applies a function to them to accumulate data.
4818 Cannot change equations."
4819 input EquationPointers equations;
4820 input MapFunc func;
4821 input output T extArg;
4822 partial function MapFunc
4823 input Equation e;
4824 input output T extArg;
4825 end MapFunc;
4826 algorithm
4827 ✗ for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop
4828 ✗ if ExpandableArray.occupied(i, equations.eqArr) then
4829 ✗ extArg := func(Pointer.access(ExpandableArray.get(i, equations.eqArr)), extArg);
4830 end if;
4831 end for;
4832 end fold;
4833
4834 function foldPtr<T>
4835 "Traverses all equations and applies a function to them to accumulate data.
4836 Can change the equation pointer."
4837 input EquationPointers equations;
4838 input MapFunc func;
4839 input output T extArg;
4840 partial function MapFunc
4841 input Pointer<Equation> e;
4842 input output T extArg;
4843 end MapFunc;
4844 algorithm
4845 ✗ for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop
4846 ✗ if ExpandableArray.occupied(i, equations.eqArr) then
4847 ✗ extArg := func(ExpandableArray.get(i, equations.eqArr), extArg);
4848 end if;
4849 end for;
4850 end foldPtr;
4851
4852 function foldRemovePtr<T>
4853 "Traverses all equation pointers and applies a function to them to accumulate data.
4854 Can invoke to delete the equation pointer. (also deletes other instances of the equation.
4855 Take care to keep a copy if you want to add it back later)"
4856 input output EquationPointers equations;
4857 input MapFunc func;
4858 input output T extArg;
4859 partial function MapFunc
4860 input Pointer<Equation> e;
4861 input output T extArg;
4862 output Boolean delete;
4863 end MapFunc;
4864 protected
4865 Pointer<Equation> eq_ptr;
4866 Boolean delete;
4867 algorithm
4868
2/2
✓ Branch 1 taken 185 times.
✓ Branch 2 taken 198 times.
5271 for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop
4869
1/2
✓ Branch 1 taken 4888 times.
✗ Branch 2 not taken.
4888 if ExpandableArray.occupied(i, equations.eqArr) then
4870 4888 eq_ptr := ExpandableArray.get(i, equations.eqArr);
4871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4888 times.
4888 (extArg, delete) := func(eq_ptr, extArg);
4872
2/2
✓ Branch 0 taken 1944 times.
✓ Branch 1 taken 2944 times.
4888 if delete then
4873 // change the pointer to point to an empty equation
4874 1944 Pointer.update(eq_ptr, DUMMY_EQUATION());
4875 // delete this pointer instance
4876 1944 equations.eqArr := ExpandableArray.delete(i, equations.eqArr);
4877 end if;
4878 end if;
4879 end for;
4880 end foldRemovePtr;
4881
4882 function getEqnAt "O(1)
4883 Returns the equation pointer at given index. If there is none it fails."
4884 input EquationPointers equations;
4885 input Integer index;
4886 output Pointer<Equation> eqn;
4887 algorithm
4888 75198 eqn := ExpandableArray.get(index, equations.eqArr);
4889 end getEqnAt;
4890
4891 function getEqnByName "O(1)
4892 Returns the equation with specified name, fails if it does not exist."
4893 input EquationPointers equations;
4894 input ComponentRef name;
4895 output Pointer<Equation> eqn;
4896 algorithm
4897 eqn := match UnorderedMap.get(name, equations.map)
4898 local
4899 Integer index;
4900 case SOME(index) guard(index > 0)
4901 6120 then getEqnAt(equations, index);
4902
4903 case SOME(_) algorithm
4904 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the equation with the name " + ComponentRef.toString(name) + " has already been deleted."});
4905 ✗ then fail();
4906
4907 else algorithm
4908 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because there is no equation with the name " + ComponentRef.toString(name) + "."});
4909 ✗ then fail();
4910 end match;
4911 end getEqnByName;
4912
4913 function getEqnIndex
4914 "Returns -1 if cref was deleted or cannot be found."
4915 input EquationPointers equations;
4916 input ComponentRef name;
4917 output Integer index = UnorderedMap.getOrDefault(name, equations.map, -1);
4918 end getEqnIndex;
4919
4920 function compress "O(n)
4921 Recollects the elements in order to remove all the gaps.
4922 Be careful: This changes the indices of the elements."
4923 input output EquationPointers equations;
4924 protected
4925 Pointer<Equation> eqn;
4926 list<Pointer<Equation>> eqns = {};
4927 algorithm
4928 // collect non-empty equations
4929
2/2
✓ Branch 1 taken 5291 times.
✓ Branch 2 taken 3811 times.
121956 for i in ExpandableArray.getLastUsedIndex(equations.eqArr):-1:1 loop
4930
2/2
✓ Branch 1 taken 110869 times.
✓ Branch 2 taken 1985 times.
112854 if ExpandableArray.occupied(i, equations.eqArr) then
4931 110869 eqn := ExpandableArray.get(i, equations.eqArr);
4932 () := match Pointer.access(eqn)
4933 local
4934 list<Equation> body;
4935 // todo: add for IF and WHEN
4936 case Equation.DUMMY_EQUATION() then ();
4937 case Equation.FOR_EQUATION(body = body) guard(List.all(body, Equation.isDummy)) then ();
4938 else algorithm
4939 eqns := eqn :: eqns;
4940 then ();
4941 end match;
4942 end if;
4943 end for;
4944 9102 equations := fromList(eqns);
4945 end compress;
4946
4947 function sort
4948 "author: kabdelhak
4949 Sorts the equations solely by cref and operator attributes and type hash.
4950 Does not use the name! Used for reproduceable heuristic behavior independent of names."
4951 input output EquationPointers equations;
4952 protected
4953 Integer size;
4954 list<tuple<Integer, Pointer<Equation>>> hash_lst;
4955 Pointer<list<tuple<Integer, Pointer<Equation>>>> hash_lst_ptr = Pointer.create({});
4956 Pointer<Equation> eqn_ptr;
4957 algorithm
4958 // use number of elements
4959 ✗ size := ExpandableArray.getNumberOfElements(equations.eqArr);
4960 // hash all equations and create hash - equation tpl list
4961 ✗ mapPtr(equations, function createSortHashTpl(mod = realInt(size * log(size)), hash_lst_ptr = hash_lst_ptr));
4962 ✗ hash_lst := List.sort(Pointer.access(hash_lst_ptr), BackendUtil.indexTplGt);
4963 // add the equations one by one in sorted order
4964 ✗ equations := empty(size);
4965 ✗ for tpl in hash_lst loop
4966 ✗ (_, eqn_ptr) := tpl;
4967 ✗ equations.eqArr := ExpandableArray.add(eqn_ptr, equations.eqArr);
4968 end for;
4969 end sort;
4970
4971 function getResiduals
4972 input EquationPointers equations;
4973 output VariablePointers residuals;
4974 algorithm
4975 ✗ residuals := VariablePointers.fromList(list(Equation.getResidualVar(eqn) for eqn in EquationPointers.toList(equations)));
4976 end getResiduals;
4977
4978 protected
4979 function createSortHashTpl
4980 "Helper function for sort(). Creates the hash value without considering the names and
4981 adds it as a tuple to the list in pointer."
4982 input output Pointer<Equation> eqn_ptr;
4983 input Integer mod;
4984 input Pointer<list<tuple<Integer, Pointer<Equation>>>> hash_lst_ptr;
4985 protected
4986 Equation eqn;
4987 Integer hash;
4988 algorithm
4989 ✗ eqn := Pointer.access(eqn_ptr);
4990 // create hash only from attributes
4991 ✗ hash := BackendUtil.noNameHashEq(eqn, mod);
4992 ✗ Pointer.update(hash_lst_ptr, (hash, eqn_ptr) :: Pointer.access(hash_lst_ptr));
4993 end createSortHashTpl;
4994 end EquationPointers;
4995
4996 uniontype EqData
4997 record EQ_DATA_SIM
4998 Pointer<Integer> uniqueIndex "current index to be used for new identifier";
4999 EquationPointers equations "All equations";
5000 EquationPointers simulation "All equations for simulation (without initial)";
5001 EquationPointers continuous "Continuous equations";
5002 EquationPointers clocked "Clocked equations";
5003 EquationPointers discretes "Discrete equations";
5004 EquationPointers initials "(Exclusively) Initial equations";
5005 EquationPointers auxiliaries "Auxiliary equations";
5006 EquationPointers removed "Removed equations (alias and no return value)";
5007 end EQ_DATA_SIM;
5008
5009 record EQ_DATA_JAC
5010 Pointer<Integer> uniqueIndex "current index to be used for new identifier";
5011 EquationPointers equations "All equations";
5012 EquationPointers results "Result equations";
5013 EquationPointers temporary "Temporary inner equations";
5014 EquationPointers auxiliaries "Auxiliary equations";
5015 EquationPointers removed "Removed equations (alias and no return value)";
5016 end EQ_DATA_JAC;
5017
5018 record EQ_DATA_HES
5019 Pointer<Integer> uniqueIndex "current index to be used for new identifier";
5020 EquationPointers equations "All equations";
5021 Pointer<Equation> result "Result equation";
5022 EquationPointers temporary "Temporary inner equations";
5023 EquationPointers auxiliaries "Auxiliary equations";
5024 EquationPointers removed "Removed equations (alias and no return value)";
5025 end EQ_DATA_HES;
5026
5027 record EQ_DATA_EMPTY end EQ_DATA_EMPTY;
5028
5029 function size
5030 input EqData eqData;
5031 output Integer s;
5032 algorithm
5033 s := match eqData
5034 ✗ case EQ_DATA_SIM() then EquationPointers.size(eqData.simulation);
5035 ✗ case EQ_DATA_JAC() then EquationPointers.size(eqData.equations);
5036 ✗ case EQ_DATA_HES() then EquationPointers.size(eqData.equations);
5037 end match;
5038 end size;
5039
5040 function scalarSize
5041 input EqData eqData;
5042 input Boolean resize = false;
5043 output Integer s;
5044 algorithm
5045 s := match eqData
5046 ✗ case EQ_DATA_SIM() then EquationPointers.scalarSize(eqData.simulation, resize);
5047 ✗ case EQ_DATA_JAC() then EquationPointers.scalarSize(eqData.equations, resize);
5048 ✗ case EQ_DATA_HES() then EquationPointers.scalarSize(eqData.equations, resize);
5049 end match;
5050 end scalarSize;
5051
5052 function map
5053 input output EqData eqData;
5054 input MapFuncEqn func;
5055 algorithm
5056 eqData := match eqData
5057 case EqData.EQ_DATA_SIM() algorithm
5058 // we do not want to traverse removed equations, otherwise we could break them
5059 1252 eqData.simulation := EquationPointers.map(eqData.simulation, func);
5060 1252 eqData.continuous := EquationPointers.map(eqData.continuous, func);
5061 1252 eqData.clocked := EquationPointers.map(eqData.clocked, func);
5062 1252 eqData.discretes := EquationPointers.map(eqData.discretes, func);
5063 1252 eqData.initials := EquationPointers.map(eqData.initials, func);
5064 1252 eqData.auxiliaries := EquationPointers.map(eqData.auxiliaries, func);
5065 then eqData;
5066
5067 case EqData.EQ_DATA_JAC() algorithm
5068 ✗ eqData.results := EquationPointers.map(eqData.results, func);
5069 ✗ eqData.temporary := EquationPointers.map(eqData.temporary, func);
5070 ✗ eqData.auxiliaries := EquationPointers.map(eqData.auxiliaries, func);
5071 then eqData;
5072
5073 case EqData.EQ_DATA_HES() algorithm
5074 ✗ Pointer.update(eqData.result, func(Pointer.access(eqData.result)));
5075 ✗ eqData.temporary := EquationPointers.map(eqData.temporary, func);
5076 ✗ eqData.auxiliaries := EquationPointers.map(eqData.auxiliaries, func);
5077 then eqData;
5078 end match;
5079 end map;
5080
5081 function mapExp
5082 input output EqData eqData;
5083 input MapFuncExp func;
5084 input Option<MapFuncCref> funcCrefOpt = NONE();
5085 algorithm
5086 eqData := match eqData
5087 case EqData.EQ_DATA_SIM() algorithm
5088 // we do not want to traverse removed equations, otherwise we could break them
5089 1286 eqData.simulation := EquationPointers.mapExp(eqData.simulation, func, funcCrefOpt);
5090 1286 eqData.continuous := EquationPointers.mapExp(eqData.continuous, func, funcCrefOpt);
5091 1286 eqData.clocked := EquationPointers.mapExp(eqData.clocked, func, funcCrefOpt);
5092 1286 eqData.discretes := EquationPointers.mapExp(eqData.discretes, func, funcCrefOpt);
5093 1286 eqData.initials := EquationPointers.mapExp(eqData.initials, func, funcCrefOpt);
5094 1286 eqData.auxiliaries := EquationPointers.mapExp(eqData.auxiliaries, func, funcCrefOpt);
5095 1286 eqData.removed := EquationPointers.mapExp(eqData.removed, func, funcCrefOpt);
5096 then eqData;
5097
5098 case EqData.EQ_DATA_JAC() algorithm
5099 ✗ eqData.results := EquationPointers.mapExp(eqData.results, func, funcCrefOpt);
5100 ✗ eqData.temporary := EquationPointers.mapExp(eqData.temporary, func, funcCrefOpt);
5101 ✗ eqData.auxiliaries := EquationPointers.mapExp(eqData.auxiliaries, func, funcCrefOpt);
5102 ✗ eqData.removed := EquationPointers.mapExp(eqData.removed, func, funcCrefOpt);
5103 then eqData;
5104
5105 case EqData.EQ_DATA_HES() algorithm
5106 ✗ Pointer.update(eqData.result, Equation.map(Pointer.access(eqData.result), func, funcCrefOpt));
5107 ✗ eqData.temporary := EquationPointers.mapExp(eqData.temporary, func, funcCrefOpt);
5108 ✗ eqData.auxiliaries := EquationPointers.mapExp(eqData.auxiliaries, func, funcCrefOpt);
5109 ✗ eqData.removed := EquationPointers.mapExp(eqData.removed, func, funcCrefOpt);
5110 then eqData;
5111 end match;
5112 end mapExp;
5113
5114 function toString
5115 input EqData eqData;
5116 input Integer level = 0;
5117 input Option<UnorderedSet<String>> filter_opt = NONE();
5118 output String str;
5119 algorithm
5120 str := match eqData
5121 local
5122 String tmp;
5123
5124 case EQ_DATA_SIM()
5125 algorithm
5126 ✗ tmp := "Equation Data Simulation (scalar simulation equations: " + intString(EquationPointers.scalarSize(eqData.simulation, true)) + ")";
5127 ✗ tmp := StringUtil.headline_2(tmp) + "\n";
5128 ✗ if level == 0 then
5129 ✗ tmp := tmp + EquationPointers.toString(eqData.equations, "Simulation", NONE(), false, filter_opt);
5130 else
5131 ✗ tmp := tmp + EquationPointers.toString(eqData.continuous, "Continuous", NONE(), false, filter_opt) +
5132 EquationPointers.toString(eqData.clocked, "Clocked", NONE(), false, filter_opt) +
5133 EquationPointers.toString(eqData.discretes, "Discrete", NONE(), false, filter_opt) +
5134 EquationPointers.toString(eqData.initials, "(Exclusively) Initial", NONE(), false, filter_opt) +
5135 EquationPointers.toString(eqData.auxiliaries, "Auxiliary", NONE(), false, filter_opt) +
5136 EquationPointers.toString(eqData.removed, "Removed", NONE(), false, filter_opt);
5137 end if;
5138 then tmp;
5139
5140 case EQ_DATA_JAC()
5141 algorithm
5142 ✗ if level == 0 then
5143 ✗ tmp := EquationPointers.toString(eqData.equations, "Jacobian", NONE(), false, filter_opt);
5144 else
5145 ✗ tmp := EquationPointers.toString(eqData.results, "Residual", NONE(), false, filter_opt) +
5146 EquationPointers.toString(eqData.temporary, "Inner", NONE(), false, filter_opt) +
5147 EquationPointers.toString(eqData.auxiliaries, "Auxiliary", NONE(), false, filter_opt);
5148 end if;
5149 then tmp;
5150
5151 case EQ_DATA_HES()
5152 algorithm
5153 ✗ if level == 0 then
5154 ✗ tmp := EquationPointers.toString(eqData.equations, "Hessian", NONE(), false, filter_opt);
5155 else
5156 ✗ tmp := StringUtil.headline_4("Result Equation") + "\n" +
5157 Equation.toString(Pointer.access(eqData.result)) + "\n" +
5158 EquationPointers.toString(eqData.temporary, "Temporary Inner", NONE(), false, filter_opt) +
5159 EquationPointers.toString(eqData.auxiliaries, "Auxiliary", NONE(), false, filter_opt);
5160 end if;
5161 then tmp;
5162
5163 case EQ_DATA_EMPTY() then "Empty equation Data!\n";
5164
5165 else getInstanceName() + " failed!\n";
5166 end match;
5167 end toString;
5168
5169 function getUniqueIndex
5170 input EqData eqData;
5171 output Pointer<Integer> uniqueIndex;
5172 algorithm
5173 uniqueIndex := match eqData
5174 415 case EqData.EQ_DATA_SIM() then eqData.uniqueIndex;
5175 ✗ case EqData.EQ_DATA_JAC() then eqData.uniqueIndex;
5176 ✗ case EqData.EQ_DATA_HES() then eqData.uniqueIndex;
5177 else algorithm
5178 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
5179 ✗ then fail();
5180 end match;
5181 end getUniqueIndex;
5182
5183 function getEquations
5184 input EqData eqData;
5185 output EquationPointers equations;
5186 algorithm
5187 equations := match eqData
5188 190 case EqData.EQ_DATA_SIM() then eqData.equations;
5189 ✗ case EqData.EQ_DATA_JAC() then eqData.equations;
5190 ✗ case EqData.EQ_DATA_HES() then eqData.equations;
5191 else algorithm
5192 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
5193 ✗ then fail();
5194 end match;
5195 end getEquations;
5196
5197 function setEquations
5198 input output EqData eqData;
5199 input EquationPointers equations;
5200 algorithm
5201 eqData := match eqData
5202 ✗ case EQ_DATA_SIM() algorithm eqData.equations := equations; then eqData;
5203 ✗ case EQ_DATA_JAC() algorithm eqData.equations := equations; then eqData;
5204 ✗ case EQ_DATA_HES() algorithm eqData.equations := equations; then eqData;
5205 end match;
5206 end setEquations;
5207
5208 type EqType = enumeration(CONTINUOUS, DISCRETE, CLOCKED, INITIAL);
5209
5210 function addTypedList
5211 input output EqData eqData;
5212 input list<Pointer<Equation>> eq_lst;
5213 input EqType eqType;
5214 input Boolean newName = true;
5215 algorithm
5216 eqData := match (eqData, eqType)
5217
5218 case (EQ_DATA_SIM(), EqType.CONTINUOUS) algorithm
5219
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 573 times.
616 if newName then
5220
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 43 times.
283 for eqn_ptr in eq_lst loop
5221 240 Equation.createName(eqn_ptr, eqData.uniqueIndex, SIMULATION_STR);
5222 end for;
5223 end if;
5224 616 eqData.equations := EquationPointers.addList(eq_lst, eqData.equations);
5225 616 eqData.simulation := EquationPointers.addList(eq_lst, eqData.simulation);
5226 616 eqData.continuous := EquationPointers.addList(eq_lst, eqData.continuous);
5227 then eqData;
5228
5229 case (EQ_DATA_SIM(), EqType.DISCRETE) algorithm
5230
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 386 times.
386 if newName then
5231 ✗ for eqn_ptr in eq_lst loop
5232 ✗ Equation.createName(eqn_ptr, eqData.uniqueIndex, SIMULATION_STR);
5233 end for;
5234 end if;
5235 386 eqData.equations := EquationPointers.addList(eq_lst, eqData.equations);
5236 386 eqData.simulation := EquationPointers.addList(eq_lst, eqData.simulation);
5237 386 eqData.discretes := EquationPointers.addList(eq_lst, eqData.discretes);
5238 then eqData;
5239
5240 case (EQ_DATA_SIM(), EqType.CLOCKED) algorithm
5241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 193 times.
193 if newName then
5242 ✗ for eqn_ptr in eq_lst loop
5243 ✗ Equation.createName(eqn_ptr, eqData.uniqueIndex, SIMULATION_STR);
5244 end for;
5245 end if;
5246 193 eqData.clocked := EquationPointers.addList(eq_lst, eqData.clocked);
5247 then eqData;
5248
5249 case (EQ_DATA_SIM(), EqType.INITIAL) algorithm
5250
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 193 times.
221 if newName then
5251
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 28 times.
82 for eqn_ptr in eq_lst loop
5252 54 Equation.createName(eqn_ptr, eqData.uniqueIndex, SIMULATION_STR);
5253 end for;
5254 end if;
5255 221 eqData.equations := EquationPointers.addList(eq_lst, eqData.equations);
5256 221 eqData.initials := EquationPointers.addList(eq_lst, eqData.initials);
5257 then eqData;
5258
5259 // ToDo: other cases
5260
5261 else algorithm
5262 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
5263 ✗ then fail();
5264 end match;
5265 end addTypedList;
5266
5267 function addUntypedList
5268 input output EqData eqData;
5269 input list<Pointer<Equation>> eq_lst;
5270 input Boolean newName = true;
5271 protected
5272 list<Pointer<Equation>> continuous_lst, clocked_lst, discretes_lst, initials_lst, auxiliaries_lst, simulation_lst, removed_lst;
5273 algorithm
5274
5275 eqData := match eqData
5276 case EQ_DATA_SIM() algorithm
5277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 573 times.
573 if newName then
5278 ✗ for eqn_ptr in eq_lst loop
5279 ✗ Equation.createName(eqn_ptr, eqData.uniqueIndex, SIMULATION_STR);
5280 end for;
5281 end if;
5282 573 (simulation_lst, continuous_lst, clocked_lst, discretes_lst, initials_lst, auxiliaries_lst, removed_lst) := typeList(eq_lst);
5283 573 eqData.equations := EquationPointers.addList(eq_lst, eqData.equations);
5284 573 eqData.simulation := EquationPointers.addList(simulation_lst, eqData.simulation);
5285 573 eqData.continuous := EquationPointers.addList(continuous_lst, eqData.continuous);
5286 573 eqData.clocked := EquationPointers.addList(clocked_lst, eqData.clocked);
5287 573 eqData.discretes := EquationPointers.addList(discretes_lst, eqData.discretes);
5288 573 eqData.initials := EquationPointers.addList(initials_lst, eqData.initials);
5289 573 eqData.auxiliaries := EquationPointers.addList(auxiliaries_lst, eqData.auxiliaries);
5290 573 eqData.removed := EquationPointers.addList(removed_lst, eqData.removed);
5291 then eqData;
5292
5293 // ToDo: other cases
5294
5295 else algorithm
5296 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
5297 ✗ then fail();
5298 end match;
5299 end addUntypedList;
5300
5301 function removeList
5302 input list<Pointer<Equation>> eq_lst;
5303 input output EqData eqData;
5304 algorithm
5305 eqData := match eqData
5306 case EQ_DATA_SIM() algorithm
5307 ✗ eqData.equations := EquationPointers.removeList(eq_lst, eqData.equations);
5308 ✗ eqData.simulation := EquationPointers.removeList(eq_lst, eqData.simulation);
5309 ✗ eqData.continuous := EquationPointers.removeList(eq_lst, eqData.continuous);
5310 ✗ eqData.discretes := EquationPointers.removeList(eq_lst, eqData.discretes);
5311 ✗ eqData.clocked := EquationPointers.removeList(eq_lst, eqData.clocked);
5312 ✗ eqData.initials := EquationPointers.removeList(eq_lst, eqData.initials);
5313 ✗ eqData.auxiliaries := EquationPointers.removeList(eq_lst, eqData.auxiliaries);
5314 ✗ eqData.removed := EquationPointers.removeList(eq_lst, eqData.removed);
5315 then eqData;
5316
5317 case EQ_DATA_JAC() algorithm
5318 ✗ eqData.equations := EquationPointers.removeList(eq_lst, eqData.equations);
5319 ✗ eqData.results := EquationPointers.removeList(eq_lst, eqData.results);
5320 ✗ eqData.temporary := EquationPointers.removeList(eq_lst, eqData.temporary);
5321 ✗ eqData.auxiliaries := EquationPointers.removeList(eq_lst, eqData.auxiliaries);
5322 ✗ eqData.removed := EquationPointers.removeList(eq_lst, eqData.removed);
5323 then eqData;
5324
5325 case EQ_DATA_HES() algorithm
5326 ✗ eqData.equations := EquationPointers.removeList(eq_lst, eqData.equations);
5327 ✗ eqData.temporary := EquationPointers.removeList(eq_lst, eqData.temporary);
5328 ✗ eqData.auxiliaries := EquationPointers.removeList(eq_lst, eqData.auxiliaries);
5329 ✗ eqData.removed := EquationPointers.removeList(eq_lst, eqData.removed);
5330 then eqData;
5331
5332 else algorithm
5333 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
5334 ✗ then fail();
5335 end match;
5336 end removeList;
5337
5338 function removeTypedCheck
5339 input output EqData eqData;
5340 input checkEqn func;
5341 input EqType eqType;
5342 algorithm
5343 eqData := match (eqData, eqType)
5344 case (EQ_DATA_SIM(), EqType.CONTINUOUS) algorithm
5345 ✗ eqData.equations := EquationPointers.removeCheck(eqData.equations, func);
5346 ✗ eqData.simulation := EquationPointers.removeCheck(eqData.simulation, func);
5347 ✗ eqData.continuous := EquationPointers.removeCheck(eqData.continuous, func);
5348 then eqData;
5349
5350 case (EQ_DATA_SIM(), EqType.DISCRETE) algorithm
5351 190 eqData.equations := EquationPointers.removeCheck(eqData.equations, func);
5352 190 eqData.simulation := EquationPointers.removeCheck(eqData.simulation, func);
5353 190 eqData.discretes := EquationPointers.removeCheck(eqData.discretes, func);
5354 then eqData;
5355
5356 case (EQ_DATA_SIM(), EqType.CLOCKED) algorithm
5357 ✗ eqData.clocked := EquationPointers.removeCheck(eqData.clocked, func);
5358 then eqData;
5359
5360 case (EQ_DATA_SIM(), EqType.INITIAL) algorithm
5361 ✗ eqData.equations := EquationPointers.removeCheck(eqData.equations, func);
5362 ✗ eqData.initials := EquationPointers.removeCheck(eqData.initials, func);
5363 then eqData;
5364
5365 // ToDo: other cases
5366
5367 else algorithm
5368 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
5369 ✗ then fail();
5370 end match;
5371 end removeTypedCheck;
5372
5373 function compress
5374 input output EqData eqData;
5375 algorithm
5376 eqData := match eqData
5377 case EQ_DATA_SIM() algorithm
5378 954 eqData.equations := EquationPointers.compress(eqData.equations);
5379 954 eqData.simulation := EquationPointers.compress(eqData.simulation);
5380 954 eqData.continuous := EquationPointers.compress(eqData.continuous);
5381 954 eqData.discretes := EquationPointers.compress(eqData.discretes);
5382 954 eqData.initials := EquationPointers.compress(eqData.initials);
5383 954 eqData.auxiliaries := EquationPointers.compress(eqData.auxiliaries);
5384 954 eqData.removed := EquationPointers.compress(eqData.removed);
5385 then eqData;
5386
5387 case EQ_DATA_JAC() algorithm
5388 ✗ eqData.equations := EquationPointers.compress(eqData.equations);
5389 ✗ eqData.results := EquationPointers.compress(eqData.results);
5390 ✗ eqData.temporary := EquationPointers.compress(eqData.temporary);
5391 ✗ eqData.auxiliaries := EquationPointers.compress(eqData.auxiliaries);
5392 ✗ eqData.removed := EquationPointers.compress(eqData.removed);
5393 then eqData;
5394
5395 case EQ_DATA_HES() algorithm
5396 ✗ eqData.equations := EquationPointers.compress(eqData.equations);
5397 ✗ eqData.temporary := EquationPointers.compress(eqData.temporary);
5398 ✗ eqData.auxiliaries := EquationPointers.compress(eqData.auxiliaries);
5399 ✗ eqData.removed := EquationPointers.compress(eqData.removed);
5400 then eqData;
5401
5402 else algorithm
5403 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
5404 ✗ then fail();
5405 end match;
5406 end compress;
5407 end EqData;
5408
5409 function typeList
5410 input list<Pointer<Equation>> equations;
5411 output list<Pointer<Equation>> simulation_lst = {};
5412 output list<Pointer<Equation>> continuous_lst = {};
5413 output list<Pointer<Equation>> clocked_lst = {};
5414 output list<Pointer<Equation>> discretes_lst = {};
5415 output list<Pointer<Equation>> initials_lst = {};
5416 output list<Pointer<Equation>> auxiliaries_lst = {};
5417 output list<Pointer<Equation>> removed_lst = {};
5418 algorithm
5419
2/2
✓ Branch 1 taken 4975 times.
✓ Branch 2 taken 766 times.
5741 for eq in equations loop
5420 () := match Equation.getAttributes(Pointer.access(eq))
5421 case EQUATION_ATTRIBUTES(exclusively_initial = true)
5422 algorithm
5423 initials_lst := eq :: initials_lst;
5424 then ();
5425
5426 case EQUATION_ATTRIBUTES(kind = EquationKind.CONTINUOUS)
5427 algorithm
5428 continuous_lst := eq :: continuous_lst;
5429 simulation_lst := eq :: simulation_lst;
5430 then ();
5431
5432 case EQUATION_ATTRIBUTES(kind = EquationKind.CLOCKED)
5433 algorithm
5434 clocked_lst := eq :: clocked_lst;
5435 then ();
5436
5437 case EQUATION_ATTRIBUTES(kind = EquationKind.DISCRETE)
5438 algorithm
5439 discretes_lst := eq :: discretes_lst;
5440 simulation_lst := eq :: simulation_lst;
5441 then ();
5442
5443 case EQUATION_ATTRIBUTES(kind = EquationKind.EMPTY)
5444 algorithm
5445 removed_lst := eq :: removed_lst;
5446 then ();
5447
5448 else
5449 algorithm
5450 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + Equation.toString(Pointer.access(eq))});
5451 ✗ then fail();
5452 end match;
5453 end for;
5454 end typeList;
5455
5456 annotation(__OpenModelica_Interface="nbackend");
5457 end NBEquation;
5458