Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 83.6% 455 / 0 / 544
Functions: -% 0 / 1 / 1
Branches: 69.1% 307 / 0 / 444

OMCompiler/Compiler/NFFrontEnd/NFSimplifyExp.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 NFSimplifyExp
37
38 import Expression = NFExpression;
39 import Operator = NFOperator;
40 import Type = NFType;
41 import Call = NFCall;
42 import Subscript = NFSubscript;
43 import NFOperator.Op;
44 import NFPrefixes.{Variability, Purity};
45 import NFInstNode.InstNode;
46
47 protected
48
49 import Dimension = NFDimension;
50 import Ceval = NFCeval;
51 import NFCeval.EvalTarget;
52 import NFFunction.Function;
53 import ComponentRef = NFComponentRef;
54 import ExpandExp = NFExpandExp;
55 import TypeCheck = NFTypeCheck;
56 import Absyn;
57 import AbsynUtil;
58 import ErrorExt;
59 import Flags;
60 import Debug;
61 import Array;
62 import MetaModelica.Dangerous.listReverseInPlace;
63 import UnorderedMap;
64
65 constant Integer MAX_CHAIN_TERMS = 32
66 "Same limit as Expression.MAX_SUM_CHAIN, for the n-ary node.";
67
68 public
69
70 function simplifyDump
71 "wrapper function for simplification to allow dumping before and afterwards"
72 input Expression exp;
73 input Boolean includeScope;
74 output Expression res;
75 input String name = "";
76 input String indent = "";
77 algorithm
78 71436 res := simplify(exp, includeScope);
79
4/4
✓ Branch 1 taken 71072 times.
✓ Branch 2 taken 364 times.
✓ Branch 4 taken 352 times.
✓ Branch 5 taken 12 times.
71436 if Flags.isSet(Flags.DUMP_SIMPLIFY) and not Expression.isEqual(exp, res) then
80 12 print(indent + "### dumpSimplify | " + name + " ###\n");
81 12 print(indent + "[BEFORE] " + Expression.toString(exp) + "\n");
82 12 print(indent + "[AFTER ] " + Expression.toString(res) + "\n\n");
83 end if;
84 end simplifyDump;
85
86 function simplify
87 input output Expression exp;
88 input Boolean includeScope = false;
89 protected
90 Type old, new;
91 algorithm
92 exp := match exp
93 case Expression.CREF()
94 algorithm
95 1290062 exp.cref := ComponentRef.simplifySubscripts(exp.cref);
96 1290062 exp.ty := ComponentRef.getSubscriptedType(exp.cref, includeScope);
97 then
98 exp;
99
100 case Expression.ARRAY()
101 guard not exp.literal
102 algorithm
103 103590 exp.elements := Array.map(exp.elements, function simplify(includeScope = false));
104 then
105 exp;
106
107 case Expression.RANGE()
108 14281 then simplifyRange(exp);
109
110 case Expression.RECORD()
111 algorithm
112
4/4
✓ Branch 0 taken 26665 times.
✓ Branch 1 taken 2106 times.
✓ Branch 2 taken 26665 times.
✓ Branch 3 taken 2106 times.
30877 exp.elements := list(simplify(e) for e in exp.elements);
113 then
114 exp;
115
116 189886 case Expression.CALL() then simplifyCall(exp);
117 16869 case Expression.SIZE() then simplifySize(exp);
118 78139 case Expression.MULTARY() then simplifyMultary(exp);
119 800628 case Expression.BINARY() then simplifyBinary(exp);
120 52427 case Expression.UNARY() then simplifyUnary(exp);
121 6493 case Expression.LBINARY() then simplifyLogicBinary(exp);
122 2044 case Expression.LUNARY() then simplifyLogicUnary(exp);
123 29860 case Expression.RELATION() then simplifyRelation(exp);
124 6760 case Expression.IF() then simplifyIf(exp);
125 11326 case Expression.CAST() then Expression.typeCast(simplify(exp.exp), exp.ty);
126 65 case Expression.UNBOX() then Expression.unbox(simplify(exp.exp));
127 7648 case Expression.SUBSCRIPTED_EXP() then simplifySubscriptedExp(exp);
128 107 case Expression.TUPLE_ELEMENT() then simplifyTupleElement(exp);
129 151 case Expression.RECORD_ELEMENT() then simplifyRecordElement(exp);
130 65 case Expression.BOX() then Expression.box(simplify(exp.exp));
131 22343 case Expression.MUTABLE() then simplify(Mutable.access(exp.exp));
132 1 case Expression.INSTANCE_NAME() then Ceval.evalGetInstanceName(exp.scope);
133 else exp;
134 end match;
135
136 // simplify dimensions
137 4609854 old := Expression.typeOf(exp);
138 4609854 new := Type.simplify(old);
139
2/2
✓ Branch 0 taken 4318057 times.
✓ Branch 1 taken 291797 times.
4609854 if not referenceEq(old, new) then
140 291797 exp := Expression.setType(new, exp);
141 end if;
142 end simplify;
143
144 function simplifyRange
145 input Expression range;
146 output Expression exp;
147 protected
148 Expression start_exp1, stop_exp1, start_exp2, stop_exp2;
149 Option<Expression> step_exp1, step_exp2;
150 Type ty, ty2;
151 algorithm
152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14281 times.
14281 Expression.RANGE(ty = ty, start = start_exp1, step = step_exp1, stop = stop_exp1) := range;
153
154 14281 start_exp2 := simplify(start_exp1);
155 14281 step_exp2 := Util.applyOption(step_exp1, function simplify(includeScope = false));
156 14281 stop_exp2 := simplify(stop_exp1);
157 14281 ty2 := Type.simplify(ty);
158
159
3/4
✓ Branch 0 taken 11158 times.
✓ Branch 1 taken 3123 times.
✓ Branch 2 taken 11158 times.
✗ Branch 3 not taken.
14281 if referenceEq(start_exp1, start_exp2) and
160 referenceEq(step_exp1, step_exp2) and
161 referenceEq(stop_exp1, stop_exp2) and
162 referenceEq(ty, ty2) then
163 exp := range;
164 else
165
2/2
✓ Branch 1 taken 13830 times.
✓ Branch 2 taken 451 times.
14281 if not Type.isResizable(ty) then
166 13830 ty := TypeCheck.keepRangeSize(
167 TypeCheck.getRangeType(start_exp2, step_exp2, stop_exp2,
168 Type.arrayElementType(ty), Absyn.dummyInfo), ty);
169 else
170 ty := ty2;
171 end if;
172 14281 exp := Expression.RANGE(ty, start_exp2, step_exp2, stop_exp2);
173 end if;
174 end simplifyRange;
175
176 function simplifyCall
177 input output Expression callExp;
178 protected
179 Call call;
180 list<Expression> args;
181 Boolean builtin, is_pure, scalarize;
182 algorithm
183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 189886 times.
189886 Expression.CALL(call = call) := callExp;
184
185 callExp := match call
186 case Call.TYPED_CALL(arguments = args) guard not Call.isExternal(call)
187 algorithm
188
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 186974 times.
186974 if Flags.isSet(Flags.NF_EXPAND_FUNC_ARGS) then
189 ✗ args := list(if Expression.hasArrayCall(arg) then arg else ExpandExp.expand(arg) for arg in args);
190 end if;
191
192
4/4
✓ Branch 0 taken 368446 times.
✓ Branch 1 taken 186974 times.
✓ Branch 2 taken 368446 times.
✓ Branch 3 taken 186974 times.
555420 args := list(simplify(arg) for arg in args);
193 186974 call.arguments := args;
194 186974 builtin := Function.isBuiltin(call.fn);
195 186974 is_pure := not Function.isImpure(call.fn);
196
197 // Use Ceval for builtin pure functions with literal arguments.
198
2/2
✓ Branch 0 taken 147256 times.
✓ Branch 1 taken 39718 times.
186974 if builtin then
199 147256 scalarize := Flags.isSet(Flags.NF_SCALARIZE);
200
201
8/8
✓ Branch 0 taken 146393 times.
✓ Branch 1 taken 863 times.
✓ Branch 3 taken 84700 times.
✓ Branch 4 taken 61693 times.
✓ Branch 5 taken 2255 times.
✓ Branch 6 taken 82445 times.
✓ Branch 8 taken 98 times.
✓ Branch 9 taken 2157 times.
147256 if is_pure and List.all(args, Expression.isLiteral) and (scalarize or Type.isScalar(call.ty)) then
202 try
203 82543 callExp := Ceval.evalCall(call, NFCeval.noTarget);
204 else
205 2 callExp := Expression.CALL(call);
206 end try;
207 else
208 64713 callExp := simplifyBuiltinCall(Function.nameConsiderBuiltin(call.fn), args, call, expand = scalarize);
209 end if;
210 elseif Flags.isSet(Flags.NF_EVAL_CONST_ARG_FUNCS) and is_pure and List.all(args, Expression.isLiteral) then
211 4111 callExp := simplifyCall2(call);
212 else
213 35607 callExp := Expression.CALL(call);
214 end if;
215 then
216 callExp;
217
218 case Call.TYPED_CALL(arguments = args)
219 algorithm
220
4/4
✓ Branch 0 taken 1594 times.
✓ Branch 1 taken 539 times.
✓ Branch 2 taken 1594 times.
✓ Branch 3 taken 539 times.
2133 args := list(simplify(arg) for arg in args);
221 539 call.arguments := args;
222 539 then
223 Expression.CALL(call);
224
225 2027 case Call.TYPED_ARRAY_CONSTRUCTOR() then simplifyArrayConstructor(call);
226 346 case Call.TYPED_REDUCTION() then simplifyReduction(call);
227 else callExp;
228 end match;
229 end simplifyCall;
230
231 function simplifyCall2
232 input Call call;
233 output Expression outExp;
234 algorithm
235 4111 ErrorExt.setCheckpoint(getInstanceName());
236
237 try
238 4111 outExp := Ceval.evalCall(call, NFCeval.noTarget);
239 4106 ErrorExt.delCheckpoint(getInstanceName());
240 else
241
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if Flags.isSet(Flags.FAILTRACE) then
242 ✗ ErrorExt.delCheckpoint(getInstanceName());
243 ✗ Debug.traceln("- " + getInstanceName() + " failed to evaluate " + Call.toString(call) + "\n");
244 else
245 5 ErrorExt.rollBack(getInstanceName());
246 end if;
247
248 5 outExp := Expression.CALL(call);
249 end try;
250 end simplifyCall2;
251
252 function simplifyBuiltinCall
253 input Absyn.Path name;
254 input list<Expression> args;
255 input Call call;
256 input Boolean expand;
257 output Expression exp;
258 algorithm
259 exp := match AbsynUtil.pathFirstIdent(name)
260 case "cat" algorithm
261
4/4
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 5619 times.
✓ Branch 4 taken 84 times.
✓ Branch 5 taken 136 times.
5839 if(not Flags.getConfigBool(Flags.NEW_BACKEND) or List.all(args, Expression.isLiteral)) then
262 5703 exp := ExpandExp.expandBuiltinCat(args, call, false);
263 else
264 136 exp := simplifyCat(args, call);
265 end if;
266 then exp;
267
268 case "pre" then match args
269 case {exp as Expression.BOOLEAN()} then exp;
270 1237 else Expression.CALL(call);
271 end match;
272
273 29 case "delay" then simplifyDelay(args, call);
274 9607 case "der" then simplifyDer(listHead(args), call);
275 3871 case "fill" then simplifyFill(listHead(args), listRest(args), call, expand);
276 253 case "homotopy" then simplifyHomotopy(args, call);
277 16361 case "max" then simplifyMinMax(args, call, isMin = false);
278 954 case "min" then simplifyMinMax(args, call, isMin = true);
279 ✗ case "ones" then simplifyFill(Expression.INTEGER(1), args, call, expand);
280 3 case "product" then simplifySumProduct(listHead(args), call, expand, isSum = false);
281 796 case "sum" then simplifySumProduct(listHead(args), call, expand, isSum = true);
282 413 case "transpose" then simplifyTranspose(listHead(args), call, expand);
283 934 case "vector" then simplifyVector(listHead(args), call);
284 ✗ case "zeros" then simplifyFill(Expression.INTEGER(0), args, call, expand);
285 421 case "semiLinear" then simplifySemiLinear(args, call);
286 1588 case "$OMC$PositiveMax" then simplifyPositiveMax(args, call);
287 361 case "$OMC$inStreamDiv" then simplifyInStreamDiv(args, call);
288 2 case "OpenModelica_uriToFilename" then simplifyURIToFilename(listHead(args), call);
289
290 22044 else Expression.CALL(call);
291 end match;
292 end simplifyBuiltinCall;
293
294 function simplifyCat
295 input list<Expression> args;
296 input Call call;
297 output Expression exp;
298 protected
299 list<Expression> nonempty_args = list(arg for arg guard(not Expression.sizeZero(arg)) in args);
300 algorithm
301 // first argument is always the dimension to concatenate over
302
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 134 times.
136 if listLength(nonempty_args) == 2 then
303 // if there are two nonempty arguments, take the second as the other does not matter
304
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
2 {_, exp} := nonempty_args;
305 elseif listLength(nonempty_args) == 1 then
306 // if there is only one nonempty argument, its the dimension, so return any of the empty arguments (first one here)
307 ✗ _ :: exp :: _ := args;
308 else
309 // do nothing, just return original call without the empty arguments
310 134 exp := Expression.CALL(Call.setArguments(call, nonempty_args));
311 end if;
312 end simplifyCat;
313
314 function simplifySemiLinear
315 input list<Expression> args;
316 input Call call;
317 output Expression exp;
318 protected
319 Expression x, m1, m2;
320 Type ty;
321 algorithm
322
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 421 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 421 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 421 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 421 times.
421 {x, m1, m2} := args;
323 421 ty := Expression.typeOf(x);
324
5/6
✓ Branch 1 taken 421 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 411 times.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 4 times.
421 if Expression.isZero(x) or (Expression.isZero(m1) and Expression.isZero(m2)) then
325 // both slopes x*m1, x*m2 return 0
326 6 exp := Expression.makeZero(ty);
327 elseif Expression.isEqual(m1, m2) then
328 // both slopes x*m1, x*m2 are equal
329 ✗ exp := Expression.BINARY(x, Operator.makeMul(ty), m1);
330 else
331 // no simplification, just return
332 415 exp := Expression.CALL(call);
333 end if;
334 end simplifySemiLinear;
335
336 function simplifyMinMax
337 input list<Expression> args;
338 input Call call;
339 input Boolean isMin;
340 output Expression exp;
341 protected
342 Expression arg;
343 Type ty;
344 algorithm
345
2/2
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 17247 times.
17315 if listLength(args) == 1 then
346 68 arg := listHead(args);
347 68 ty := Expression.typeOf(arg);
348
349
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 52 times.
68 if Type.isEmptyArray(ty) then
350 16 ty := Type.arrayElementType(ty);
351
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 exp := if isMin then Expression.makeMaxValue(ty) else
352 Expression.makeMinValue(ty);
353 else
354 52 exp := simplifyReducedArrayConstructor(arg, call);
355 end if;
356 else
357 17247 exp := Expression.CALL(call);
358 end if;
359 end simplifyMinMax;
360
361 function simplifyPositiveMax
362 "Simplifies internal `$OMC$PositiveMax`-call if min/max attributes allow it.
363 This is needed because some min/max attributes are updated after alias removal."
364 input list<Expression> args;
365 input Call call;
366 output Expression exp;
367 protected
368 Expression flow_exp, eps;
369 algorithm
370
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1588 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1588 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1588 times.
1588 {flow_exp, eps} := args;
371
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1588 times.
1588 if Expression.isNonPositive(flow_exp) then
372 // positiveMax(flow_exp, eps) = 0 if flow_exp <= 0
373 ✗ exp := Expression.makeZero(Expression.typeOf(flow_exp));
374 elseif Expression.isGreaterOrEqual(flow_exp, eps) then
375 // positiveMax(flow_exp, eps) = flow_exp if flow_exp >= eps
376 exp := flow_exp;
377 else
378 1588 exp := Expression.CALL(call);
379 end if;
380 end simplifyPositiveMax;
381
382 function simplifyInStreamDiv
383 "Simplifies internal `$OMC$inStreamDiv`-call if first argument is `0/0`."
384 input list<Expression> args;
385 input Call call;
386 input Boolean removeStream = false;
387 output Expression exp;
388 protected
389 Expression stream_exp, fallback;
390 algorithm
391
1/2
✓ Branch 1 taken 434 times.
✗ Branch 2 not taken.
434 if listLength(args) == 2 then
392
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 434 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 434 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 434 times.
434 {stream_exp, fallback} := args;
393 else
394 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because inStreamDiv needs to have exactly two arguments:\n "
395 + List.toString(args, Expression.toString)});
396 ✗ fail();
397 end if;
398
399
1/2
✓ Branch 1 taken 434 times.
✗ Branch 2 not taken.
434 if Expression.isNaN(stream_exp) then
400 // inStreamDiv(0/0, fallback) = fallback
401 exp := fallback;
402 elseif removeStream then
403 // inStreamDiv(stream_exp, fallback) = stream_exp in the general case
404 exp := stream_exp;
405 else
406 361 exp := Expression.CALL(call);
407 end if;
408 end simplifyInStreamDiv;
409
410 function removeStream
411 "Removes all internal calls related to stream connectors,
412 i.e. $OMC$inStreamDiv and $OMC$PositiveMax."
413 input output Expression exp;
414 algorithm
415 8353 exp := Expression.mapReverse(exp, removeInStreamDiv);
416 end removeStream;
417
418 function removeInStreamDiv
419 input output Expression exp;
420 algorithm
421 exp := match exp
422 local
423 Call call;
424 Expression arg;
425 list<Expression> rest;
426
427 case Expression.CALL(call = call as Call.TYPED_CALL(arguments = arg::rest))
428 guard("$OMC$inStreamDiv" == AbsynUtil.pathFirstIdent(Function.nameConsiderBuiltin(call.fn)))
429 algorithm
430 73 arg := simplify(Expression.map(arg, removePositiveMax), true);
431 73 then simplifyInStreamDiv(arg :: rest, call, true);
432 else exp;
433 end match;
434 end removeInStreamDiv;
435
436 function removePositiveMax
437 input output Expression exp;
438 algorithm
439 exp := match exp
440 local
441 Call call;
442 Expression res, arg;
443
444 case Expression.CALL(call = call as Call.TYPED_CALL(arguments = arg::_))
445 guard "$OMC$PositiveMax" == AbsynUtil.pathFirstIdent(Function.nameConsiderBuiltin(call.fn))
446 algorithm
447 // positiveMax(flow_exp, eps) = max(flow_exp, eps) in the general case
448 318 res := Expression.CALL(Call.makeTypedCall(
449 fn = NFBuiltinFuncs.MAX_REAL,
450 args = call.arguments,
451 variability = Expression.variability(arg),
452 purity = NFPrefixes.Purity.PURE
453 ));
454 then res;
455 else exp;
456 end match;
457 end removePositiveMax;
458
459 function simplifySumProduct
460 input Expression arg;
461 input Call call;
462 input Boolean expand;
463 input Boolean isSum;
464 output Expression exp;
465 protected
466 Boolean expanded;
467 list<Expression> args;
468 Type ty, ety;
469 Operator op;
470 algorithm
471 799 ty := Expression.typeOf(arg);
472
473
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 780 times.
799 if Type.isEmptyArray(ty) then
474 19 ety := Type.arrayElementType(ty);
475
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 exp := if isSum then Expression.makeZero(ety) else Expression.makeOne(ety);
476 elseif expand then
477 590 (exp, expanded) := ExpandExp.expand(arg);
478
479
2/2
✓ Branch 0 taken 489 times.
✓ Branch 1 taken 101 times.
590 if expanded then
480 489 args := Expression.arrayScalarElements(exp);
481 489 ety := Type.arrayElementType(ty);
482
483
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 489 times.
489 if listEmpty(args) then
484 ✗ exp := if isSum then Expression.makeZero(ety) else Expression.makeOne(ety);
485 else
486
2/2
✓ Branch 0 taken 487 times.
✓ Branch 1 taken 2 times.
489 op := if isSum then Operator.makeAdd(ety) else
487 Operator.makeMul(ety);
488 489 exp := Expression.MULTARY(args, {}, op);
489 489 exp := simplify(exp);
490 end if;
491 else
492 101 exp := simplifyReducedArrayConstructor(arg, call);
493 end if;
494 else
495 190 exp := simplifyReducedArrayConstructor(arg, call);
496 end if;
497 end simplifySumProduct;
498
499 function simplifyReducedArrayConstructor
500 input Expression arg;
501 input Call call;
502 output Expression exp;
503 algorithm
504 exp := match arg
505 local
506 Call arr_call;
507 Function fn;
508 Type ty;
509 Variability var;
510 Purity purity;
511
512 case Expression.CALL(call = arr_call as Call.TYPED_ARRAY_CONSTRUCTOR())
513 guard Type.dimensionCount(arr_call.ty) == 1
514 algorithm
515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 Call.TYPED_CALL(fn = fn, ty = ty, var = var, purity = purity) := call;
516 10 then
517 Expression.CALL(Call.makeTypedReduction(fn, ty, var, purity, arr_call.exp, arr_call.iters, Absyn.dummyInfo));
518
519 333 else Expression.CALL(call);
520 end match;
521 end simplifyReducedArrayConstructor;
522
523 function simplifyTranspose
524 input Expression arg;
525 input Call call;
526 input Boolean expand;
527 output Expression exp;
528 protected
529 Expression e;
530 algorithm
531
4/4
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 29 times.
✓ Branch 3 taken 266 times.
✓ Branch 4 taken 118 times.
413 e := if not expand or Expression.hasArrayCall(arg) then arg else ExpandExp.expand(arg);
532
533 exp := match e
534 case Expression.ARRAY()
535 guard Array.all(e.elements, Expression.isArray)
536 268 then Expression.transposeArray(e);
537
538 145 else Expression.CALL(call);
539 end match;
540 end simplifyTranspose;
541
542 function simplifyVector
543 input Expression arg;
544 input Call call;
545 output Expression exp;
546 protected
547 list<Expression> expl;
548 Boolean is_literal;
549 Type ty;
550 algorithm
551 934 expl := Expression.arrayScalarElements(arg);
552 934 is_literal := Expression.isLiteral(arg);
553
554
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 934 times.
934 if is_literal then
555 // Ranges count as literals, make sure they're expanded.
556 ✗ expl := ExpandExp.expandList(expl);
557 end if;
558
559
3/4
✓ Branch 0 taken 934 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 882 times.
✓ Branch 4 taken 52 times.
934 if is_literal or List.all(expl, Expression.isScalar) then
560 882 ty := Type.arrayElementType(Expression.typeOf(arg));
561 882 exp := Expression.makeExpArray(listArray(expl), ty);
562 else
563 52 exp := Expression.CALL(call);
564 end if;
565 end simplifyVector;
566
567 function simplifyFill
568 input Expression fillArg;
569 input list<Expression> dimArgs;
570 input Call call;
571 input Boolean expand;
572 output Expression exp;
573 algorithm
574
4/4
✓ Branch 1 taken 2674 times.
✓ Branch 2 taken 1197 times.
✓ Branch 3 taken 507 times.
✓ Branch 4 taken 2167 times.
3871 if List.all(dimArgs, Expression.isLiteral) and expand then
575 507 exp := Expression.fillArgs(fillArg, dimArgs);
576 else
577 3364 exp := Expression.CALL(call);
578 end if;
579 end simplifyFill;
580
581 function simplifyHomotopy
582 input list<Expression> args;
583 input Call call;
584 output Expression exp;
585 algorithm
586 exp := match Flags.getConfigString(Flags.REPLACE_HOMOTOPY)
587 1 case "actual" then listHead(args);
588 1 case "simplified" then listHead(listRest(args));
589 251 else Expression.CALL(call);
590 end match;
591 end simplifyHomotopy;
592
593 function simplifyDelay
594 input list<Expression> args;
595 input Call call;
596 output Expression callExp;
597 protected
598 Expression exp, delayTime;
599 algorithm
600
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
29 exp :: delayTime :: _ := args;
601
602
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 if Expression.variability(delayTime) <= Variability.PARAMETER then
603 29 delayTime := Ceval.tryEvalExp(delayTime);
604
605
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 28 times.
29 if Expression.isZero(delayTime) then
606 callExp := exp;
607 1 return;
608 end if;
609 end if;
610
611 28 callExp := Expression.CALL(call);
612 end simplifyDelay;
613
614 function simplifyDer
615 input Expression arg;
616 input Call call;
617 output Expression exp;
618 algorithm
619
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 9606 times.
9607 if Call.variability(call) < Variability.DISCRETE then
620 1 exp := Expression.makeZero(Expression.typeOf(arg));
621 else
622 9606 exp := Expression.CALL(call);
623 end if;
624 end simplifyDer;
625
626 function simplifyArrayConstructor
627 input Call call;
628 output Expression outExp;
629 protected
630 Type ty;
631 Variability var;
632 Purity pur;
633 Expression exp, e;
634 list<tuple<InstNode, Expression>> iters;
635 InstNode iter;
636 Dimension dim;
637 Integer dim_size;
638 Boolean expanded;
639 algorithm
640
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2027 times.
2027 Call.TYPED_ARRAY_CONSTRUCTOR(ty, var, pur, exp, iters) := call;
641
4/4
✓ Branch 0 taken 2037 times.
✓ Branch 1 taken 2027 times.
✓ Branch 2 taken 2037 times.
✓ Branch 3 taken 2027 times.
4064 iters := list((Util.tuple21(i), simplify(Util.tuple22(i))) for i in iters);
642
643 outExp := matchcontinue iters
644 case {(iter, e)}
645 algorithm
646
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 2019 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2019 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2019 times.
2019 Type.ARRAY(dimensions = {dim}) := Expression.typeOf(e);
647 2019 dim_size := Dimension.size(dim);
648
649
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1988 times.
1990 if dim_size == 0 then
650 // Result is Array[0], return empty array expression.
651 2 outExp := Expression.makeEmptyArray(ty);
652 elseif dim_size == 1 then
653 // Result is Array[1], return array with the single element.
654 239 e := ExpandExp.expand(e);
655 239 e := Expression.arrayScalarElement(e);
656 239 exp := Expression.replaceIterator(exp, iter, e);
657 239 exp := Expression.makeArray(ty, listArray({exp}));
658 239 outExp := simplify(exp);
659 elseif Expression.isLiteral(e) and isIteratorSubscriptedArray(exp, iter) then
660 // If the iterator is only used to subscript array expressions like
661 // {{1, 2, 3}[i] for i in 1:3}, then we might as well expand it.
662 3 (outExp, expanded) := ExpandExp.expandArrayConstructor(exp, ty, iters);
663
664
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if expanded then
665 3 outExp := simplify(outExp);
666 end if;
667 else
668 1746 fail();
669 end if;
670 then
671 outExp;
672
673 else
674 algorithm
675 1783 exp := simplify(exp);
676 1783 ty := Type.simplify(ty);
677 1783 then
678 Expression.CALL(Call.TYPED_ARRAY_CONSTRUCTOR(ty, var, pur, exp, iters));
679 end matchcontinue;
680 end simplifyArrayConstructor;
681
682 function isIteratorSubscriptedArray
683 input Expression exp;
684 input InstNode iterator;
685 output Boolean res;
686 algorithm
687 res := match exp
688 case Expression.SUBSCRIPTED_EXP()
689
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
3 then Expression.isArray(exp.exp) and
690 List.all(exp.subscripts, function Subscript.equalsIterator(iterator = iterator));
691 else false;
692 end match;
693 end isIteratorSubscriptedArray;
694
695 function simplifyReduction
696 input Call call;
697 output Expression outExp;
698 algorithm
699 outExp := match call
700 local
701 Expression exp, e;
702 list<tuple<InstNode, Expression>> iters;
703 InstNode iter;
704 Dimension dim;
705 Integer dim_size;
706
707 case Call.TYPED_REDUCTION()
708 algorithm
709
4/4
✓ Branch 0 taken 347 times.
✓ Branch 1 taken 346 times.
✓ Branch 2 taken 347 times.
✓ Branch 3 taken 346 times.
693 iters := list((Util.tuple21(i), simplify(Util.tuple22(i))) for i in call.iters);
710 then matchcontinue iters
711 case {(iter, e)}
712 algorithm
713
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 345 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 345 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 345 times.
345 Type.ARRAY(dimensions = {dim}) := Expression.typeOf(e);
714 345 dim_size := Dimension.size(dim);
715
716
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 313 times.
325 if dim_size == 0 then
717 // Iteration range is empty, return default value for reduction.
718
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
12 SOME(outExp) := call.defaultExp;
719 elseif dim_size == 1 then
720 // Iteration range is one, return reduction expression with iterator value applied.
721 6 e := ExpandExp.expand(e);
722 6 e := Expression.arrayScalarElement(e);
723 6 outExp := Expression.replaceIterator(call.exp, iter, e);
724 6 outExp := simplify(outExp);
725 else
726 307 fail();
727 end if;
728 then
729 outExp;
730
731 case _
732 guard call.var <= Variability.STRUCTURAL_PARAMETER
733 13 then Ceval.tryEvalExp(Expression.CALL(call));
734
735 case _
736 guard Flags.isSet(Flags.NF_SCALARIZE)
737 234 then simplifyReduction2(AbsynUtil.pathString(Function.name(call.fn)), call.exp, iters);
738
739 else
740 algorithm
741 96 call.exp := simplify(call.exp);
742 96 call.iters := iters;
743 96 then
744 Expression.CALL(call);
745
746 end matchcontinue;
747 end match;
748 end simplifyReduction;
749
750 function simplifyReduction2
751 input String name;
752 input Expression exp;
753 input list<tuple<InstNode, Expression>> iterators;
754 output Expression outExp;
755 protected
756 InstNode iter;
757 Expression range, default_exp;
758 list<tuple<InstNode, Expression>> iters = {};
759 Type ty;
760 Operator op;
761 algorithm
762 234 ty := Expression.typeOf(exp);
763 // Operator records are problematic since the start value isn't simplified
764 // away currently.
765
2/2
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 233 times.
234 false := Type.isRecord(Type.arrayElementType(ty));
766
767 (default_exp, op) := match name
768 233 case "sum" then (Expression.makeZero(ty), Operator.makeAdd(ty));
769 ✗ case "product" then (Expression.makeOne(ty), Operator.makeMul(ty));
770 end match;
771
772
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 219 times.
451 for i in iterators loop
773 232 (iter, range) := i;
774
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 219 times.
232 (range, true) := ExpandExp.expand(range);
775 219 iters := (iter, range) :: iters;
776 end for;
777
778 219 outExp := Expression.foldReduction(simplify(exp), listReverseInPlace(iters),
779 default_exp, function simplify(includeScope = false), function simplifyBinaryOp(op = op));
780 end simplifyReduction2;
781
782 function simplifySize
783 input output Expression sizeExp;
784 algorithm
785 sizeExp := match sizeExp
786 local
787 Expression exp, index;
788 Dimension dim;
789 list<Dimension> dims;
790
791 case Expression.SIZE(exp, SOME(index))
792 algorithm
793 16866 index := simplify(index);
794
795
2/2
✓ Branch 1 taken 16865 times.
✓ Branch 2 taken 1 time.
16866 if Expression.isLiteral(index) then
796 16865 dim := listGet(Type.arrayDims(Expression.typeOf(exp)), Expression.toInteger(index));
797
798
2/2
✓ Branch 1 taken 468 times.
✓ Branch 2 taken 16397 times.
16865 if Dimension.isKnown(dim) then
799 468 exp := Expression.INTEGER(Dimension.size(dim));
800 else
801 16397 exp := Expression.SIZE(exp, SOME(index));
802 end if;
803 else
804 1 exp := Expression.SIZE(exp, SOME(index));
805 end if;
806 then
807 exp;
808
809 case Expression.SIZE()
810 algorithm
811 3 dims := Type.arrayDims(Expression.typeOf(sizeExp.exp));
812
813
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
3 if List.all(dims, function Dimension.isKnown(allowExp = true)) then
814 ✗ exp := Expression.makeArray(Type.ARRAY(Type.INTEGER(), {Dimension.fromInteger(listLength(dims))}),
815 listArray(list(Dimension.sizeExp(d) for d in dims)));
816 else
817 exp := sizeExp;
818 end if;
819 then
820 exp;
821
822 end match;
823 end simplifySize;
824
825 function simplifyMultary
826 input output Expression exp;
827 algorithm
828 exp := match exp
829 local
830 Operator operator;
831 list<Expression> arguments, inv_arguments, const_args, inv_const_args;
832 Expression new_const, tmp, result;
833 Operator.MathClassification mcl;
834 Boolean neutralConst, isNegative;
835
836 // empty multary with addition -> 0
837 case Expression.MULTARY(arguments = {}, inv_arguments = {}, operator = operator)
838 guard(Operator.isDashClassification(Operator.getMathClassification(operator)))
839 16 then Expression.makeZero(operator.ty);
840
841 // empty multary with multiplication -> 1
842 case Expression.MULTARY(arguments = {}, inv_arguments = {}, operator = operator)
843 ✗ then Expression.makeOne(operator.ty);
844
845 // multary with only one argument
846 case Expression.MULTARY(arguments = {tmp}, inv_arguments = {}) algorithm
847 1139 then simplify(tmp);
848
849 // non-empty multaries
850 case Expression.MULTARY(arguments = arguments, inv_arguments = inv_arguments, operator = operator) algorithm
851 // get math classification
852 76984 mcl := Operator.getMathClassification(operator);
853
854 // simplify arguments first
855
4/4
✓ Branch 0 taken 140286 times.
✓ Branch 1 taken 76984 times.
✓ Branch 2 taken 140286 times.
✓ Branch 3 taken 76984 times.
217270 arguments := list(simplify(arg) for arg in arguments);
856
4/4
✓ Branch 0 taken 24696 times.
✓ Branch 1 taken 76984 times.
✓ Branch 2 taken 24696 times.
✓ Branch 3 taken 76984 times.
101680 inv_arguments := list(simplify(arg) for arg in inv_arguments);
857 76984 (arguments, inv_arguments, isNegative) := simplifyMultarySigns(arguments, inv_arguments, mcl);
858
859 // split them into constant and non constant arguments
860 76984 (const_args, arguments) := List.splitOnTrue(arguments, isEvaluableLiteral);
861 76984 (inv_const_args, inv_arguments) := List.splitOnTrue(inv_arguments, isEvaluableLiteral);
862
863 // combine the constants
864
2/2
✓ Branch 0 taken 56439 times.
✓ Branch 1 taken 20545 times.
76984 if mcl == NFOperator.MathClassification.ADDITION then
865 56439 (new_const, neutralConst) := Ceval.evalMultaryAddSub(const_args, inv_const_args, Operator.typeOf(operator));
866 elseif mcl == NFOperator.MathClassification.MULTIPLICATION then
867 20545 (new_const, neutralConst) := Ceval.evalMultaryMulDiv(const_args, inv_const_args, Operator.typeOf(operator));
868 else
869 ✗ Error.terminate(getInstanceName() + " detected non-commutative operator in MULTARY(): [" + Operator.mathSymbol(mcl) +
870 "]\n with following arguments: " + stringDelimitList(list(Expression.toString(e) for e in const_args), ", ") +
871 "\n and following inverse arguments: " + stringDelimitList(list(Expression.toString(e) for e in inv_const_args), ", "),
872 sourceInfo());
873 ✗ fail();
874 end if;
875
876 // remove expressions that are in both arguments and inv_arguments
877 76984 (arguments, inv_arguments) := cancelTermsInMultary(arguments, inv_arguments);
878
879 // a neutral constant can not be removed if it is the only source of the dimensions, e.g. s * {1.0}
880
6/6
✓ Branch 0 taken 52541 times.
✓ Branch 1 taken 24443 times.
✓ Branch 2 taken 47883 times.
✓ Branch 3 taken 4658 times.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 47877 times.
76984 if neutralConst and not listEmpty(arguments) and Type.dimensionCount(Expression.typeOf(new_const)) >
881 List.fold(listAppend(arguments, inv_arguments), maxDimensionCount, 0) then
882 6 neutralConst := false;
883 end if;
884
885 result := match (mcl, arguments, inv_arguments)
886 // const + {} - {} = const
887 case (NFOperator.MathClassification.ADDITION, {}, {})
888
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 12846 times.
12848 then if Expression.isEmpty(new_const) then Expression.makeZero(Expression.typeOf(new_const)) else new_const;
889
890 // const * {} / {} = const
891 case (NFOperator.MathClassification.MULTIPLICATION, {}, {})
892
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1110 times.
1110 then if Expression.isEmpty(new_const) then Expression.makeOne(Expression.typeOf(new_const)) else new_const;
893
894 // 0 + {cr} - {} = cr
895 // 1 * {cr} / {} = cr
896 case (_, {tmp}, {}) guard(neutralConst) then tmp;
897
898 // 0 + {} - {cr} = - cr
899 case (NFOperator.MathClassification.ADDITION, {}, {tmp}) guard(neutralConst)
900 1723 then Expression.negate(tmp);
901
902 // 0 * {...} / {...} = 0
903 case (NFOperator.MathClassification.MULTIPLICATION, _, _) guard(Expression.isZero(new_const) and not Type.isArray(Operator.typeOf(operator))) then new_const;
904 case (NFOperator.MathClassification.MULTIPLICATION, _, _) guard(Expression.isZero(new_const) and Type.hasKnownSize(Operator.typeOf(operator)))
905 42 then Expression.makeZero(Operator.typeOf(operator));
906
907
2/2
✓ Branch 0 taken 44182 times.
✓ Branch 1 taken 9485 times.
53667 else Expression.MULTARY(
908 arguments = if neutralConst then arguments else new_const :: arguments,
909 inv_arguments = inv_arguments,
910 operator = operator
911 );
912 end match;
913
914 // negate the expression if there was an odd number of negative arguments (only multiplication)
915
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 76792 times.
76984 then if isNegative then Expression.negate(result) else result;
916
917 else algorithm
918 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for expression: " + Expression.toString(exp)});
919 ✗ then fail();
920 end match;
921 end simplifyMultary;
922
923 function simplifyMultarySigns
924 input list<Expression> arguments;
925 input list<Expression> inv_arguments;
926 input Operator.MathClassification mcl;
927 output list<Expression> new_arguments = {};
928 output list<Expression> new_inv_arguments = {};
929 output Boolean isNegative = false; // only relevant for multiplication
930 algorithm
931 () := match mcl
932 case NFOperator.MathClassification.ADDITION algorithm
933 // check if arguments are negative
934 // negate them and swap them to the other list
935
2/2
✓ Branch 1 taken 100998 times.
✓ Branch 2 taken 56439 times.
157437 for arg in listReverse(arguments) loop
936
2/2
✓ Branch 1 taken 12797 times.
✓ Branch 2 taken 88201 times.
100998 if Expression.isNegated(arg) then
937 12797 new_inv_arguments := Expression.negate(arg) :: new_inv_arguments;
938 else
939 new_arguments := arg :: new_arguments;
940 end if;
941 end for;
942
2/2
✓ Branch 1 taken 21482 times.
✓ Branch 2 taken 56439 times.
77921 for arg in listReverse(inv_arguments) loop
943
2/2
✓ Branch 1 taken 270 times.
✓ Branch 2 taken 21212 times.
21482 if Expression.isNegated(arg) then
944 270 new_arguments := Expression.negate(arg) :: new_arguments;
945 else
946 new_inv_arguments := arg :: new_inv_arguments;
947 end if;
948 end for;
949 then ();
950
951 case NFOperator.MathClassification.MULTIPLICATION algorithm
952 // check if arguments are negative and negate them.
953 // track if there is an even or odd number of negative arguments
954
2/2
✓ Branch 1 taken 39288 times.
✓ Branch 2 taken 20545 times.
59833 for arg in listReverse(arguments) loop
955
2/2
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 39093 times.
39288 if Expression.isNegated(arg) then
956 195 new_arguments := Expression.negate(arg) :: new_arguments;
957 195 isNegative := not isNegative;
958 else
959 new_arguments := arg :: new_arguments;
960 end if;
961 end for;
962
2/2
✓ Branch 1 taken 3214 times.
✓ Branch 2 taken 20545 times.
23759 for arg in listReverse(inv_arguments) loop
963
2/2
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 3203 times.
3214 if Expression.isNegated(arg) then
964 11 new_inv_arguments := Expression.negate(arg) :: new_inv_arguments;
965 11 isNegative := not isNegative;
966 else
967 new_inv_arguments := arg :: new_inv_arguments;
968 end if;
969 end for;
970 then ();
971
972 else algorithm
973 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
974 ✗ then fail();
975 end match;
976 end simplifyMultarySigns;
977
978 function simplifyBinary
979 input output Expression binaryExp;
980 protected
981 Expression e1, e2, se1, se2;
982 Operator op;
983 algorithm
984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 800628 times.
800628 Expression.BINARY(e1, op, e2) := binaryExp;
985 800628 se1 := simplify(e1);
986 800628 se2 := simplify(e2);
987
988 800628 binaryExp := simplifyBinaryOp(se1, op, se2);
989
990
4/4
✓ Branch 1 taken 26073 times.
✓ Branch 2 taken 774555 times.
✓ Branch 4 taken 4675 times.
✓ Branch 5 taken 769880 times.
800628 if Flags.isSet(Flags.NF_EXPAND_OPERATIONS) and not Expression.hasArrayCall(binaryExp) then
991 769880 binaryExp := ExpandExp.expand(binaryExp);
992 end if;
993 end simplifyBinary;
994
995 function simplifyBinaryOp
996 input Expression exp1;
997 input Operator op;
998 input Expression exp2;
999 output Expression outExp;
1000
1001 import NFOperator.Op;
1002 algorithm
1003
4/4
✓ Branch 1 taken 184971 times.
✓ Branch 2 taken 714201 times.
✓ Branch 4 taken 32249 times.
✓ Branch 5 taken 152722 times.
899172 if Expression.isLiteral(exp1) and Expression.isLiteral(exp2) then
1004 32249 outExp := Ceval.evalBinaryOp(ExpandExp.expand(exp1), op, ExpandExp.expand(exp2));
1005 elseif Expression.isArray(exp1) and Expression.isArray(exp2) then
1006 outExp := match op.op
1007 962 case Op.ADD then simplifyBinaryEW(exp1, op, exp2);
1008 30 case Op.SUB then simplifyBinaryEW(exp1, op, exp2);
1009 ✗ case Op.ADD_EW then simplifyBinaryEW(exp1, op, exp2);
1010 ✗ case Op.SUB_EW then simplifyBinaryEW(exp1, op, exp2);
1011 1 case Op.MUL_EW then simplifyBinaryEW(exp1, op, exp2);
1012 ✗ case Op.DIV_EW then simplifyBinaryEW(exp1, op, exp2);
1013 ✗ case Op.POW_EW then simplifyBinaryEW(exp1, op, exp2);
1014 1038 else Expression.BINARY(exp1, op, exp2);
1015 end match;
1016 else
1017 outExp := match op.op
1018 210659 case Op.ADD then simplifyBinaryAdd(exp1, op, exp2);
1019 118266 case Op.SUB then simplifyBinarySub(exp1, op, exp2);
1020 448344 case Op.MUL then simplifyBinaryMul(exp1, op, exp2);
1021 55063 case Op.DIV then simplifyBinaryDiv(exp1, op, exp2);
1022 25273 case Op.POW then simplifyBinaryPow(exp1, op, exp2);
1023 2 case Op.POW_SCALAR_ARRAY then simplifyBinaryPow(exp1, op, exp2);
1024 28 case Op.POW_ARRAY_SCALAR then simplifyBinaryPow(exp1, op, exp2);
1025 18 case Op.SCALAR_PRODUCT guard(Expression.isZero(exp1) or Expression.isZero(exp2)) then Expression.makeZero(op.ty);
1026 7239 else Expression.BINARY(exp1, op, exp2);
1027 end match;
1028 end if;
1029 end simplifyBinaryOp;
1030
1031 function simplifyBinaryAdd
1032 input Expression exp1;
1033 input Operator op;
1034 input Expression exp2;
1035 output Expression outExp;
1036 algorithm
1037
2/2
✓ Branch 1 taken 217326 times.
✓ Branch 2 taken 3368 times.
220694 if Expression.isZero(exp1) then
1038 // 0 + e = e
1039 outExp := exp2;
1040 elseif Expression.isZero(exp2) then
1041 // e + 0 = e
1042 outExp := exp1;
1043 elseif Expression.isNegated(exp1) then
1044
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 35211 times.
35211 if Expression.isNegated(exp2) then
1045 // (-e1) + (-e2) = -(e1 + e2)
1046 ✗ outExp := Expression.negate(Expression.BINARY(Expression.negate(exp1), op, Expression.negate(exp2)));
1047 else
1048 // (-e1) + e2 = e2 - e1
1049 35211 outExp := simplifyBinarySub(exp2, Operator.invert(op), Expression.negate(exp1));
1050 end if;
1051 elseif Expression.isNegated(exp2) then
1052 // e1 + (-e2) = e1 - e2
1053 293 outExp := simplifyBinarySub(exp1, Operator.invert(op), Expression.negate(exp2));
1054 else
1055 175199 outExp := Expression.BINARY(exp1, op, exp2);
1056 end if;
1057 end simplifyBinaryAdd;
1058
1059 function simplifyBinarySub
1060 input Expression exp1;
1061 input Operator op;
1062 input Expression exp2;
1063 output Expression outExp;
1064 algorithm
1065
2/2
✓ Branch 1 taken 332 times.
✓ Branch 2 taken 153438 times.
153770 if Expression.isZero(exp1) then
1066 // 0 - e = -e
1067 332 outExp := Expression.negate(exp2);
1068 elseif Expression.isZero(exp2) then
1069 // e - 0 = e
1070 outExp := exp1;
1071 elseif Expression.isEqual(exp1, exp2) then
1072 // e - e = 0
1073 9 outExp := Expression.makeZero(Operator.typeOf(op));
1074 elseif Expression.isNegated(exp1) then
1075
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10017 times.
10017 if Expression.isNegated(exp2) then
1076 // (-e1) - (-e2) = e2 - e1
1077 ✗ outExp := Expression.BINARY(Expression.negate(exp2), op, Expression.negate(exp1));
1078 else
1079 // (-e1) - e2 = -(e1 + e2)
1080 10017 outExp := Expression.negate(simplifyBinaryAdd(Expression.negate(exp1), Operator.invert(op), exp2));
1081 end if;
1082 elseif Expression.isNegated(exp2) then
1083 // e1 - (-e2) = e1 + e2
1084 18 outExp := simplifyBinaryAdd(exp1, Operator.invert(op), Expression.negate(exp2));
1085 else
1086 141874 outExp := Expression.BINARY(exp1, op, exp2);
1087 end if;
1088 end simplifyBinarySub;
1089
1090 function simplifyBinaryMul
1091 input Expression exp1;
1092 input Operator op;
1093 input Expression exp2;
1094 input Boolean switched = false;
1095 output Expression outExp;
1096 algorithm
1097 outExp := match exp1
1098 // 0 * e = 0, the zero has to keep the dimensions if e is an array
1099 case Expression.INTEGER(value = 0) guard(not Type.isArray(Operator.typeOf(op))) then exp1;
1100 case Expression.REAL(value = 0.0) guard(not Type.isArray(Operator.typeOf(op))) then exp1;
1101 ✗ case Expression.INTEGER(value = 0) guard(Type.hasKnownSize(Operator.typeOf(op))) then Expression.makeZero(Operator.typeOf(op));
1102 ✗ case Expression.REAL(value = 0.0) guard(Type.hasKnownSize(Operator.typeOf(op))) then Expression.makeZero(Operator.typeOf(op));
1103
1104 // 1 * e = e
1105 case Expression.INTEGER(value = 1) then exp2;
1106 case Expression.REAL(value = 1.0) then exp2;
1107
1108
2/2
✓ Branch 0 taken 427111 times.
✓ Branch 1 taken 439109 times.
866220 else
1109 if switched then
1110 Expression.BINARY(exp2, op, exp1)
1111 else
1112 simplifyBinaryMul(exp2, op, exp1, true);
1113 end match;
1114 end simplifyBinaryMul;
1115
1116 function simplifyBinaryDiv
1117 input Expression exp1;
1118 input Operator op;
1119 input Expression exp2;
1120 output Expression outExp;
1121 algorithm
1122 // fix constants
1123 // e / 1 = e
1124 // e / (-1) = -e
1125 // 0 / e = 0 (e <> 0)
1126
6/8
✓ Branch 1 taken 54741 times.
✓ Branch 2 taken 322 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 54741 times.
✓ Branch 8 taken 93 times.
✓ Branch 9 taken 54648 times.
✓ Branch 11 taken 93 times.
✗ Branch 12 not taken.
55063 outExp :=
1127 if Expression.isOne(exp2) then exp1
1128 elseif Expression.isMinusOne(exp2) then Expression.negate(exp1)
1129 elseif Expression.isZero(exp1) and Expression.isNonZero(exp2) then exp1
1130 // fix minus signs
1131 // (-e1)/(-e2) = e1/e2
1132 // e1/(-e2) = -(e1/e2)
1133 // (-e1)/e2 = -(e1/e2)
1134 // e1/e2 = e1/e2
1135 else match (Expression.isNegated(exp1), Expression.isNegated(exp1))
1136 220 case (true, true) then Expression.BINARY(Expression.negate(exp1), op, Expression.negate(exp2));
1137 ✗ case (false, true) then Expression.negate(Expression.BINARY(exp1, op, Expression.negate(exp2)));
1138 ✗ case (true, false) then Expression.negate(Expression.BINARY(Expression.negate(exp1), op, exp2));
1139 54521 case (false, false) then Expression.BINARY(exp1, op, exp2);
1140 end match;
1141 end simplifyBinaryDiv;
1142
1143 function simplifyBinaryPow
1144 input Expression exp1;
1145 input Operator op;
1146 input Expression exp2;
1147 output Expression outExp;
1148 algorithm
1149
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 25295 times.
25303 if Expression.isZero(exp2) then
1150 8 outExp := Expression.makeOne(Operator.typeOf(op));
1151 elseif Expression.isOne(exp2) then
1152 outExp := exp1; // FIXME cast to type of `op`
1153 elseif Expression.isZero(exp1) and Expression.isPositive(exp2) then
1154 ✗ outExp := Expression.makeZero(Operator.typeOf(op));
1155 elseif Expression.isOne(exp1) then
1156 ✗ outExp := Expression.makeOne(Operator.typeOf(op));
1157 else
1158 25190 outExp := Expression.BINARY(exp1, op, exp2);
1159 end if;
1160 end simplifyBinaryPow;
1161
1162 function simplifyBinaryEW
1163 input Expression exp1;
1164 input Operator op;
1165 input Expression exp2;
1166 output Expression outExp;
1167 algorithm
1168 993 outExp := Expression.makeArray(Operator.typeOf(op),
1169 Array.threadMap(Expression.arrayElements(exp1), Expression.arrayElements(exp2),
1170 function simplifyBinaryOp(op = Operator.stripEW(Operator.unlift(op)))));
1171 end simplifyBinaryEW;
1172
1173 function simplifyUnary
1174 input output Expression unaryExp;
1175 protected
1176 Expression e, se;
1177 Operator op;
1178 algorithm
1179 unaryExp := match unaryExp
1180 case Expression.UNARY(_, Expression.UNARY(_, e))
1181 337 then simplify(e);
1182
1183 case Expression.UNARY(op, e) algorithm
1184 52090 se := simplify(e);
1185 52090 then simplifyUnaryOp(se, op);
1186
1187 else algorithm
1188 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
1189 ✗ then fail();
1190 end match;
1191
1192
4/4
✓ Branch 1 taken 4925 times.
✓ Branch 2 taken 47502 times.
✓ Branch 4 taken 256 times.
✓ Branch 5 taken 47246 times.
52427 if Flags.isSet(Flags.NF_EXPAND_OPERATIONS) and not Expression.hasArrayCall(unaryExp) then
1193 47246 unaryExp := ExpandExp.expand(unaryExp);
1194 end if;
1195 end simplifyUnary;
1196
1197 function simplifyUnaryOp
1198 input Expression exp;
1199 input Operator op;
1200 output Expression outExp;
1201 algorithm
1202
2/2
✓ Branch 1 taken 7624 times.
✓ Branch 2 taken 96663 times.
104287 if Expression.isLiteral(exp) then
1203 7624 outExp := Ceval.evalUnaryOp(exp, op);
1204 else
1205 96663 outExp := simplifyUnarySign(exp, true);
1206 end if;
1207 end simplifyUnaryOp;
1208
1209 function simplifyUnarySign
1210 input output Expression unaryExp;
1211 input Boolean isNegative = false;
1212 algorithm
1213 unaryExp := match unaryExp
1214 15 case Expression.UNARY() then simplifyUnarySign(unaryExp.exp, not isNegative);
1215
2/2
✓ Branch 0 taken 96648 times.
✓ Branch 1 taken 15 times.
96663 else if isNegative then Expression.negate(unaryExp) else unaryExp;
1216 end match;
1217 end simplifyUnarySign;
1218
1219 function simplifyLogicBinary
1220 input output Expression binaryExp;
1221 protected
1222 Expression e1, e2, se1, se2;
1223 Operator op;
1224 algorithm
1225
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6493 times.
6493 Expression.LBINARY(e1, op, e2) := binaryExp;
1226 6493 se1 := simplify(e1);
1227 6493 se2 := simplify(e2);
1228
1229 binaryExp := match op.op
1230 3918 case Op.AND then simplifyLogicBinaryAnd(se1, op, se2);
1231 2575 case Op.OR then simplifyLogicBinaryOr(se1, op, se2);
1232 end match;
1233 end simplifyLogicBinary;
1234
1235 function simplifyLogicBinaryAnd
1236 input Expression exp1;
1237 input Operator op;
1238 input Expression exp2;
1239 output Expression exp;
1240 algorithm
1241 exp := match (exp1, exp2)
1242 local
1243 Operator o;
1244 array<Expression> arr;
1245
1246 // false and e => false
1247 case (Expression.BOOLEAN(false), _) then exp1;
1248 // e and false => false
1249 case (_, Expression.BOOLEAN(false)) then exp2;
1250 // true and e => e
1251 case (Expression.BOOLEAN(true), _) then exp2;
1252 // e and true => e
1253 case (_, Expression.BOOLEAN(true)) then exp1;
1254
1255 case (Expression.ARRAY(), Expression.ARRAY())
1256 algorithm
1257 1 o := Operator.unlift(op);
1258 1 arr := Array.threadMap(exp1.elements, exp2.elements,
1259 function simplifyLogicBinaryAnd(op = o));
1260 1 then
1261 Expression.makeArray(Operator.typeOf(op), arr);
1262
1263 3088 else Expression.LBINARY(exp1, op, exp2);
1264 end match;
1265 end simplifyLogicBinaryAnd;
1266
1267 function simplifyLogicBinaryOr
1268 input Expression exp1;
1269 input Operator op;
1270 input Expression exp2;
1271 output Expression exp;
1272 algorithm
1273 exp := match (exp1, exp2)
1274 local
1275 Operator o;
1276 array<Expression> arr;
1277
1278 // true or e => true
1279 case (Expression.BOOLEAN(true), _) then exp1;
1280 // e or true => true
1281 case (_, Expression.BOOLEAN(true)) then exp2;
1282 // false or e => e
1283 case (Expression.BOOLEAN(false), _) then exp2;
1284 // e or false => e
1285 case (_, Expression.BOOLEAN(false)) then exp1;
1286
1287 case (Expression.ARRAY(), Expression.ARRAY())
1288 algorithm
1289 1 o := Operator.unlift(op);
1290 1 arr := Array.threadMap(exp1.elements, exp2.elements,
1291 function simplifyLogicBinaryOr(op = o));
1292 1 then
1293 Expression.makeArray(Operator.typeOf(op), arr);
1294
1295 1459 else Expression.LBINARY(exp1, op, exp2);
1296 end match;
1297 end simplifyLogicBinaryOr;
1298
1299 function simplifyLogicUnary
1300 input output Expression unaryExp;
1301 protected
1302 Expression e, se, newExp;
1303 Operator op;
1304 algorithm
1305 unaryExp := match unaryExp
1306 case Expression.LUNARY(_, Expression.LUNARY(_, e))
1307 8 then simplify(e);
1308
1309 case Expression.LUNARY(op, e) algorithm
1310 2036 se := simplify(e);
1311
1312
2/2
✓ Branch 1 taken 801 times.
✓ Branch 2 taken 1235 times.
2036 if Expression.isLiteral(se) then
1313 801 newExp := Ceval.evalLogicUnaryOp(se, op);
1314 elseif not referenceEq(e, se) then
1315 1235 newExp := Expression.LUNARY(op, se);
1316 else
1317 newExp := unaryExp;
1318 end if;
1319 then newExp;
1320 end match;
1321 end simplifyLogicUnary;
1322
1323 function simplifyRelation
1324 input output Expression relationExp;
1325 protected
1326 Expression e1, e2, se1, se2;
1327 Operator op;
1328 Integer index;
1329 algorithm
1330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29860 times.
29860 Expression.RELATION(e1, op, e2, index) := relationExp;
1331 29860 se1 := simplify(e1);
1332 29860 se2 := simplify(e2);
1333
1334
4/4
✓ Branch 1 taken 4494 times.
✓ Branch 2 taken 25366 times.
✓ Branch 4 taken 4472 times.
✓ Branch 5 taken 22 times.
29860 if Expression.isLiteral(se1) and Expression.isLiteral(se2) then
1335 4472 relationExp := Ceval.evalRelationOp(se1, op, se2);
1336 elseif not (referenceEq(e1, se1) and referenceEq(e2, se2)) then
1337 25388 relationExp := Expression.RELATION(se1, op, se2, index);
1338 end if;
1339 end simplifyRelation;
1340
1341 function simplifyIf
1342 input output Expression ifExp;
1343 protected
1344 Type ty;
1345 Expression cond, tb, fb;
1346 Boolean tb_val;
1347 algorithm
1348
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6760 times.
6760 Expression.IF(ty, cond, tb, fb) := ifExp;
1349 6760 cond := simplify(cond);
1350
1351 ifExp := match cond
1352 case Expression.BOOLEAN()
1353
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 96 times.
240 then simplify(if cond.value then tb else fb);
1354
1355 else
1356 algorithm
1357 6592 tb := simplify(tb);
1358 6592 fb := simplify(fb);
1359
1360
2/2
✓ Branch 1 taken 6557 times.
✓ Branch 2 taken 35 times.
6592 if Expression.isEqual(tb, fb) then
1361 // if cond then x else x => x
1362 ifExp := tb;
1363 elseif Expression.isBoolean(tb) and Expression.isBoolean(fb) then
1364 // if cond then true else false => cond
1365 // if cond then false else true => not cond
1366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 Expression.BOOLEAN(value = tb_val) := tb;
1367
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 ifExp := if tb_val then cond else Expression.logicNegate(cond);
1368 else
1369
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6551 times.
6551 ty := if Type.isConditionalArray(ty) then
1370 Type.setConditionalArrayTypes(ty, Expression.typeOf(tb), Expression.typeOf(fb)) else
1371 Expression.typeOf(tb);
1372 6551 ifExp := Expression.IF(ty, cond, tb, fb);
1373 end if;
1374 then
1375 ifExp;
1376
1377 end match;
1378 end simplifyIf;
1379
1380 function isEvaluableLiteral
1381 "literals that can be combined by constant evaluation, records need their operator functions"
1382 input Expression exp;
1383 output Boolean b = Expression.isLiteral(exp) and not Type.isComplex(Type.arrayElementType(Expression.typeOf(exp)));
1384 end isEvaluableLiteral;
1385
1386 function maxDimensionCount
1387 input Expression exp;
1388 input output Integer count;
1389 algorithm
1390 100022 count := max(count, Type.dimensionCount(Expression.typeOf(exp)));
1391 end maxDimensionCount;
1392
1393 function simplifySubscriptedExp
1394 input output Expression subscriptedExp;
1395 protected
1396 Expression e;
1397 list<Subscript> subs;
1398 Type ty;
1399 Boolean split;
1400 algorithm
1401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7648 times.
7648 Expression.SUBSCRIPTED_EXP(e, subs, ty, split) := subscriptedExp;
1402 7648 subscriptedExp := simplify(e);
1403 7648 subs := Subscript.simplifyList(subs, Type.arrayDims(Expression.typeOf(e)));
1404
1405
6/6
✓ Branch 0 taken 7249 times.
✓ Branch 1 taken 399 times.
✓ Branch 3 taken 2036 times.
✓ Branch 4 taken 5213 times.
✓ Branch 6 taken 2034 times.
✓ Branch 7 taken 2 times.
7648 if not split and not List.all(subs, Subscript.isLiteral) and Type.isScalar(ty) then
1406 // Select the first element as long as the subscripted expression is an
1407 // array where all elements are equal, unless all the subscripts are literal
1408 // in which case it's cheaper to just apply them.
1409
7/8
✓ Branch 0 taken 2035 times.
✓ Branch 1 taken 488 times.
✓ Branch 3 taken 2029 times.
✓ Branch 4 taken 6 times.
✓ Branch 6 taken 2029 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 489 times.
✓ Branch 11 taken 1540 times.
2523 while not listEmpty(subs) and Expression.isArray(subscriptedExp) and not Expression.isEmptyArray(subscriptedExp) and
1410 Array.allEqual(Expression.arrayElements(subscriptedExp), Expression.isEqual) loop
1411 489 subs := listRest(subs);
1412 489 subscriptedExp := arrayGet(Expression.arrayElements(subscriptedExp), 1);
1413 end while;
1414
1415
2/2
✓ Branch 0 taken 488 times.
✓ Branch 1 taken 1546 times.
2034 if listEmpty(subs) then
1416 488 return;
1417 end if;
1418 end if;
1419
1420
1421
2/2
✓ Branch 0 taken 399 times.
✓ Branch 1 taken 6761 times.
7160 if split then
1422 399 subscriptedExp := Expression.SUBSCRIPTED_EXP(subscriptedExp, subs, ty, split);
1423 else
1424 6761 subscriptedExp := Expression.applySubscripts(subs, subscriptedExp);
1425 end if;
1426 end simplifySubscriptedExp;
1427
1428 function simplifyTupleElement
1429 input output Expression tupleExp;
1430 protected
1431 Expression e;
1432 Integer index;
1433 algorithm
1434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 107 times.
107 Expression.TUPLE_ELEMENT(tupleExp = e, index = index) := tupleExp;
1435 107 e := simplify(e);
1436 107 tupleExp := Expression.tupleElement(e, index);
1437 end simplifyTupleElement;
1438
1439 function simplifyRecordElement
1440 input output Expression exp;
1441 protected
1442 Expression e, e2;
1443 Integer idx;
1444 Type ty;
1445 algorithm
1446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 Expression.RECORD_ELEMENT(e, idx, _, ty) := exp;
1447 151 e2 := simplify(e);
1448
1449
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 151 times.
151 if not referenceEq(e, e2) then
1450 151 exp := Expression.nthRecordElement(idx, e2);
1451 end if;
1452 end simplifyRecordElement;
1453
1454 public function combineConstantNumbers
1455 input list<Expression> const "has to be a list of REAL(), INTEGER() and/or CAST()";
1456 input list<Expression> inv_const "has to be a list of REAL(), INTEGER() and/or CAST()";
1457 input Operator.MathClassification mcl;
1458 input Type ty;
1459 output Expression res;
1460 protected
1461 Real tmp, result;
1462 algorithm
1463 res := match mcl
1464
1465 case NFOperator.MathClassification.ADDITION algorithm
1466 result := 0.0;
1467 // sum all constants
1468 ✗ for exp in const loop
1469 ✗ tmp := getConstantValue(exp);
1470 ✗ result := result + tmp;
1471 end for;
1472 // subtract all inverse constants
1473 ✗ for exp in inv_const loop
1474 ✗ tmp := getConstantValue(exp);
1475 ✗ result := result - tmp;
1476 end for;
1477 ✗ res := if Type.isInteger(ty) then Expression.INTEGER(realInt(result))
1478 else Expression.REAL(result);
1479 then res;
1480
1481 case NFOperator.MathClassification.MULTIPLICATION algorithm
1482 result := 1.0;
1483 // multiply all constants
1484 ✗ for exp in const loop
1485 ✗ tmp := getConstantValue(exp);
1486 ✗ result := result * tmp;
1487 end for;
1488 ✗ if result == 0.0 then
1489 // numerator is zero
1490 ✗ if List.any(inv_const, Expression.isZero) then
1491 ✗ res := Expression.makeNaN(ty);
1492 else
1493 ✗ res := Expression.makeZero(ty);
1494 end if;
1495 else
1496 // divide all inverse constants
1497 ✗ for exp in inv_const loop
1498 ✗ tmp := getConstantValue(exp);
1499 ✗ result := result / tmp;
1500 end for;
1501 ✗ res := if Type.isInteger(ty) then Expression.INTEGER(realInt(result))
1502 else Expression.REAL(result);
1503 end if;
1504 then res;
1505
1506 else algorithm
1507 ✗ Error.terminate(getInstanceName() + " detected non-commutative operator in MULTARY(): [" + Operator.mathSymbol(mcl) +
1508 "]\n with following arguments: " + stringDelimitList(list(Expression.toString(e) for e in const), ", ") +
1509 "\n and following inverse arguments: " + stringDelimitList(list(Expression.toString(e) for e in inv_const), ", "),
1510 sourceInfo());
1511 ✗ then fail();
1512
1513 end match;
1514 end combineConstantNumbers;
1515
1516 protected function getConstantValue
1517 input Expression exp;
1518 output Real value;
1519 algorithm
1520 try
1521 ✗ value := Expression.realValue(Ceval.evalExp(exp));
1522 else
1523 ✗ Error.addInternalError(getInstanceName() + " expression is not known to be a constant number: " + Expression.toString(exp), sourceInfo());
1524 ✗ fail();
1525 end try;
1526 end getConstantValue;
1527
1528 function cancelTermsInMultary
1529 input list<Expression> inArguments;
1530 input list<Expression> inInv_arguments;
1531 output list<Expression> outArguments = {};
1532 output list<Expression> outInv_arguments = {};
1533 protected
1534 UnorderedMap<Expression, Integer> counter;
1535 Expression arg;
1536 Integer count;
1537
1538 function inc
1539 input Option<Integer> oldValue;
1540 input Integer step;
1541 output Integer value;
1542 algorithm
1543 value := match oldValue
1544 20 case SOME(value) then value + step;
1545 else step;
1546 end match;
1547 end inc;
1548 algorithm
1549
4/4
✓ Branch 0 taken 60014 times.
✓ Branch 1 taken 16970 times.
✓ Branch 2 taken 40163 times.
✓ Branch 3 taken 19851 times.
76984 if listEmpty(inArguments) or listEmpty(inInv_arguments) then
1550 // nothing can cancel
1551 outArguments := inArguments;
1552 outInv_arguments := inInv_arguments;
1553 57133 return;
1554 end if;
1555
1556 // count occurences of expressions (numerator +1, denominator -1)
1557 19851 counter := UnorderedMap.new<Integer>(Expression.hash, Expression.isEqual);
1558
2/2
✓ Branch 0 taken 24240 times.
✓ Branch 1 taken 19851 times.
44091 for arg in inArguments loop
1559 24240 UnorderedMap.addUpdate(arg, function inc(step = 1), counter);
1560 end for;
1561
2/2
✓ Branch 0 taken 20322 times.
✓ Branch 1 taken 19851 times.
40173 for arg in inInv_arguments loop
1562 20322 UnorderedMap.addUpdate(arg, function inc(step = -1), counter);
1563 end for;
1564
1565 // reconstruct numerator and denominator with remaining terms
1566
2/2
✓ Branch 1 taken 44542 times.
✓ Branch 2 taken 19851 times.
64393 for tpl in UnorderedMap.toList(counter) loop
1567 44542 (arg, count) := tpl;
1568
2/2
✓ Branch 0 taken 24224 times.
✓ Branch 1 taken 20318 times.
44542 if count > 0 then
1569 24224 for i in 1:count loop
1570 outArguments := arg :: outArguments;
1571 end for;
1572 elseif count < 0 then
1573 40608 for i in 1:-count loop
1574 outInv_arguments := arg :: outInv_arguments;
1575 end for;
1576 end if;
1577 end for;
1578 19851 outArguments := listReverseInPlace(outArguments);
1579 19851 outInv_arguments := listReverseInPlace(outInv_arguments);
1580 end cancelTermsInMultary;
1581
1582 public function combineBinaries
1583 "just a wrapper to remove the interface for traversal"
1584 input output Expression exp;
1585 algorithm
1586 34615 exp := Expression.map(exp, removeTrivialScalarProduct);
1587 34615 exp := combineBinariesExp(exp);
1588 end combineBinaries;
1589
1590 public function splitMultary
1591 "inverse functionality to combineBinaries.
1592 returns a multary to its binary representation, as a balanced tree."
1593 input output Expression exp;
1594 algorithm
1595 exp := match exp
1596 local
1597 Expression new_exp, rhs;
1598 list<Expression> args, inv_args;
1599 Operator inv_op;
1600 Boolean is_add;
1601
1602 case Expression.MULTARY() algorithm
1603 42336 args := exp.arguments;
1604 42336 inv_args := exp.inv_arguments;
1605 42336 inv_op := Operator.invert(exp.operator);
1606 42336 is_add := Operator.getMathClassification(exp.operator) == NFOperator.MathClassification.ADDITION;
1607
1608
2/2
✓ Branch 0 taken 306 times.
✓ Branch 1 taken 42030 times.
42336 if listEmpty(args) then
1609
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 306 times.
306 if listEmpty(inv_args) then
1610 ✗ new_exp := if is_add then Expression.makeZero(Operator.typeOf(exp.operator))
1611 else Expression.makeOne(Operator.typeOf(exp.operator));
1612 elseif is_add then
1613 // -a - b becomes -(a + b)
1614 253 new_exp := Expression.negate(chainBinaries(inv_args, exp.operator));
1615 inv_args := {};
1616 else
1617 // create an artificial 1 to divide by the inverse arguments
1618 53 new_exp := Expression.makeOne(Operator.typeOf(exp.operator));
1619 end if;
1620 else
1621 42030 new_exp := chainBinaries(args, exp.operator);
1622 end if;
1623
1624
1/2
✓ Branch 1 taken 42336 times.
✗ Branch 2 not taken.
42336 if listLength(inv_args) > MAX_CHAIN_TERMS then
1625 // a - b - c becomes a - (b + c): one level, not one per term
1626 ✗ rhs := chainBinaries(inv_args, exp.operator);
1627 ✗ new_exp := Expression.BINARY(new_exp,
1628 Operator.repairBinary(inv_op, Expression.typeOf(new_exp), Expression.typeOf(rhs)), rhs);
1629 else
1630
2/2
✓ Branch 0 taken 16372 times.
✓ Branch 1 taken 42336 times.
58708 for arg in inv_args loop
1631 16372 new_exp := Expression.BINARY(new_exp,
1632 Operator.repairBinary(inv_op, Expression.typeOf(new_exp), Expression.typeOf(arg)), arg);
1633 end for;
1634 end if;
1635 then new_exp;
1636
1637 else exp;
1638 end match;
1639 end splitMultary;
1640
1641 public function chainBinaries
1642 "Chains the expressions with the given operator. A chain of more than
1643 MAX_CHAIN_TERMS is instead paired up level by level, keeping their order, so
1644 that the result is log2(N) deep instead of N."
1645 input list<Expression> args;
1646 input Operator op;
1647 output Expression exp;
1648 protected
1649 list<Expression> level = args, next;
1650 Expression e1, e2;
1651 Operator fixed_op;
1652 algorithm
1653
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 42283 times.
42283 if listLength(args) <= MAX_CHAIN_TERMS then
1654
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42283 times.
42283 exp :: level := args;
1655
1656
2/2
✓ Branch 0 taken 36983 times.
✓ Branch 1 taken 42283 times.
79266 for e in level loop
1657 36983 exp := Expression.BINARY(exp,
1658 Operator.repairBinary(op, Expression.typeOf(exp), Expression.typeOf(e)), e);
1659 end for;
1660
1661 42283 return;
1662 end if;
1663
1664 ✗ while not listEmpty(level) and not listEmpty(listRest(level)) loop
1665 next := {};
1666 ✗ while not listEmpty(level) loop
1667 ✗ e1 :: level := level;
1668 ✗ if listEmpty(level) then
1669 next := e1 :: next;
1670 else
1671 ✗ e2 :: level := level;
1672 ✗ fixed_op := Operator.repairBinary(op, Expression.typeOf(e1), Expression.typeOf(e2));
1673 ✗ next := Expression.BINARY(e1, fixed_op, e2) :: next;
1674 end if;
1675 end while;
1676 ✗ level := listReverseInPlace(next);
1677 end while;
1678 ✗ exp := listHead(level);
1679 end chainBinaries;
1680
1681 protected function combineBinariesExp
1682 "author: kabdelhak 09-2020
1683 Combines binaries for better handling in the backend.
1684 NOTE: 1. does not do any other simplification
1685 2. also combines inverse operations
1686 e.g. BINARY(BINARY(2, /, y^2), *, BINARY(3, *, x))
1687 --> MULTARY({2, 3, x}, {y^2},*)"
1688 input Expression exp;
1689 input Option<Operator> optOperator = NONE();
1690 input output Expression result = Expression.EMPTY(Expression.typeOf(exp));
1691 input Boolean inverse = false;
1692 algorithm
1693 result := match (optOperator, exp)
1694 local
1695 Operator op;
1696 Expression new_exp;
1697 ComponentRef cref;
1698 Call call;
1699
1700 // #######################################################
1701 // Building MULTARY() recursively
1702 // #######################################################
1703
1704 // case 1.0 binary SOME(op) same operator (+, *)
1705 case (SOME(op), Expression.BINARY()) guard(Operator.compare(op, exp.operator) == 0) algorithm
1706 158 result := combineBinariesExp(exp.exp1, SOME(op), result, inverse);
1707 158 result := combineBinariesExp(exp.exp2, SOME(op), result, inverse);
1708 then result;
1709
1710 // case 1.1 multary SOME(op) same operator (+, *)
1711 case (SOME(op), Expression.MULTARY()) guard(Operator.compare(op, exp.operator) == 0) algorithm
1712
2/2
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 154 times.
467 for arg in exp.arguments loop
1713 313 result := combineBinariesExp(arg, SOME(exp.operator), result, inverse);
1714 end for;
1715
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 154 times.
161 for arg in exp.inv_arguments loop
1716 7 result := combineBinariesExp(arg, SOME(exp.operator), result, not inverse);
1717 end for;
1718 then result;
1719
1720 // case 2.0 binary SOME(op) inverse operator (-, :)
1721 case (SOME(op), Expression.BINARY()) guard(Operator.isCombineable(op, exp.operator)) algorithm
1722 24 result := combineBinariesExp(exp.exp1, SOME(op), result, inverse);
1723 24 result := combineBinariesExp(exp.exp2, SOME(op), result, not inverse);
1724 then result;
1725
1726 // case 2.1 multary SOME(op) inverse operator (-, :)
1727 case (SOME(op), Expression.MULTARY()) guard(Operator.isCombineable(op, exp.operator)) algorithm
1728 ✗ for arg in exp.arguments loop
1729 ✗ result := combineBinariesExp(arg, SOME(exp.operator), result, inverse);
1730 end for;
1731 ✗ for arg in exp.inv_arguments loop
1732 ✗ result := combineBinariesExp(arg, SOME(exp.operator), result, not inverse);
1733 end for;
1734 then result;
1735
1736 // ##########################################################
1737 // Starts a new MULTARY()
1738 // previous not compatible or no MULTARY on the stack at all
1739 // ##########################################################
1740
1741 // case 3.0 _ binary | commutative operator (+, *)
1742 case (_, Expression.BINARY()) guard(Operator.isCommutative(exp.operator)) algorithm
1743 3246 new_exp := Expression.MULTARY({}, {}, exp.operator);
1744 3246 new_exp := combineBinariesExp(exp.exp2, SOME(exp.operator), new_exp, false);
1745 3246 new_exp := combineBinariesExp(exp.exp1, SOME(exp.operator), new_exp, false);
1746 3246 then addArgument(result, new_exp, inverse);
1747
1748 // case 3.1 _ multary | commutative operator (+, *)
1749 case (_, Expression.MULTARY()) guard(Operator.isCommutative(exp.operator)) algorithm
1750 2231 new_exp := Expression.MULTARY({}, {}, exp.operator);
1751
2/2
✓ Branch 0 taken 4172 times.
✓ Branch 1 taken 2231 times.
6403 for arg in exp.arguments loop
1752 4172 new_exp := combineBinariesExp(arg, SOME(exp.operator), new_exp, false);
1753 end for;
1754
2/2
✓ Branch 0 taken 562 times.
✓ Branch 1 taken 2231 times.
2793 for arg in exp.inv_arguments loop
1755 562 new_exp := combineBinariesExp(arg, SOME(exp.operator), new_exp, true);
1756 end for;
1757 2231 then addArgument(result, new_exp, inverse);
1758
1759 // case 4.0 _ binary | soft commutative operator (-, :)
1760 case (_, Expression.BINARY()) guard(Operator.isSoftCommutative(exp.operator)) algorithm
1761 1522 op := Operator.invert(exp.operator);
1762 1522 new_exp := Expression.MULTARY({}, {}, op);
1763 1522 new_exp := combineBinariesExp(exp.exp1, SOME(op), new_exp, false);
1764 1522 new_exp := combineBinariesExp(exp.exp2, SOME(op), new_exp, true);
1765 1522 then addArgument(result, new_exp, inverse);
1766
1767 // case 4.1 _ multary soft | commutative operator (-, :)
1768 // THIS IS NOT ALLOWED TO EXIST!
1769
1770 // #######################################################
1771 // Other expressions that do not get combined
1772 // #######################################################
1773
1774 // going deeper on the different expression types
1775
1776 case (_, Expression.CREF(cref = cref as ComponentRef.CREF())) algorithm
1777
4/4
✓ Branch 0 taken 3719 times.
✓ Branch 1 taken 19900 times.
✓ Branch 2 taken 3719 times.
✓ Branch 3 taken 19900 times.
43519 cref.subscripts := list(combineBinariesSubscript(sub) for sub in cref.subscripts);
1778 19900 exp.cref := cref;
1779 19900 then addArgument(result, exp, inverse);
1780
1781 case (_, Expression.ARRAY()) algorithm
1782
2/2
✓ Branch 0 taken 2091 times.
✓ Branch 1 taken 669 times.
2760 if not exp.literal then
1783 4182 exp.elements := Array.map(exp.elements,
1784 function combineBinariesExp(optOperator = NONE(),
1785 result = Expression.EMPTY(Expression.typeOf(exp)), inverse = false));
1786 end if;
1787 2760 then addArgument(result, exp, inverse);
1788
1789 case (_, Expression.RANGE()) algorithm
1790 682 exp.start := combineBinariesExp(exp.start);
1791 682 exp.stop := combineBinariesExp(exp.stop);
1792
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 341 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 336 times.
341 if isSome(exp.step) then
1793 15 exp.step := SOME(combineBinariesExp(Util.getOption(exp.step)));
1794 end if;
1795 341 then addArgument(result, exp, inverse);
1796
1797 case (_, Expression.TUPLE()) algorithm
1798
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 3 times.
16 exp.elements := list(combineBinariesExp(element) for element in exp.elements);
1799 3 then addArgument(result, exp, inverse);
1800
1801 case (_, Expression.RECORD()) algorithm
1802
4/4
✓ Branch 0 taken 364 times.
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 364 times.
✓ Branch 3 taken 130 times.
624 exp.elements := list(combineBinariesExp(element) for element in exp.elements);
1803 130 then addArgument(result, exp, inverse);
1804
1805 case (_, Expression.CALL(call = call as Call.TYPED_CALL())) algorithm
1806
4/4
✓ Branch 0 taken 10926 times.
✓ Branch 1 taken 5763 times.
✓ Branch 2 taken 10926 times.
✓ Branch 3 taken 5763 times.
22452 call.arguments := list(combineBinariesExp(arg) for arg in call.arguments);
1807 5763 exp.call := call;
1808 5763 then addArgument(result, exp, inverse);
1809
1810 case (_, Expression.SIZE()) algorithm
1811 ✗ exp.exp := combineBinariesExp(exp.exp);
1812 ✗ if isSome(exp.dimIndex) then
1813 ✗ exp.dimIndex := SOME(combineBinariesExp(Util.getOption(exp.dimIndex)));
1814 end if;
1815 ✗ then addArgument(result, exp, inverse);
1816
1817 case (_, Expression.UNARY()) algorithm
1818 3540 exp.exp := combineBinariesExp(exp.exp);
1819 1770 then addArgument(result, exp, inverse);
1820
1821 // ToDo: rules for logical operators (LMULTARY ?)
1822 // For now leave them as is and traverse branches
1823 case (_, Expression.LBINARY()) algorithm
1824 184 exp.exp1 := combineBinariesExp(exp.exp1);
1825 184 exp.exp2 := combineBinariesExp(exp.exp2);
1826 92 then addArgument(result, exp, inverse);
1827
1828 case (_, Expression.LUNARY()) algorithm
1829 90 exp.exp := combineBinariesExp(exp.exp);
1830 45 then addArgument(result, exp, inverse);
1831
1832 case (_, Expression.RELATION()) algorithm
1833 1134 exp.exp1 := combineBinariesExp(exp.exp1);
1834 1134 exp.exp2 := combineBinariesExp(exp.exp2);
1835 567 then addArgument(result, exp, inverse);
1836
1837 case (_, Expression.IF()) algorithm
1838 264 exp.condition := combineBinariesExp(exp.condition);
1839 264 exp.trueBranch := combineBinariesExp(exp.trueBranch);
1840 264 exp.falseBranch := combineBinariesExp(exp.falseBranch);
1841 132 then addArgument(result, exp, inverse);
1842
1843 case (_, Expression.CAST()) algorithm
1844 196 exp.exp := combineBinariesExp(exp.exp);
1845 98 then addArgument(result, exp, inverse);
1846
1847 case (_, Expression.BOX()) algorithm
1848 74 exp.exp := combineBinariesExp(exp.exp);
1849 37 then addArgument(result, exp, inverse);
1850
1851 case (_, Expression.UNBOX()) algorithm
1852 ✗ exp.exp := combineBinariesExp(exp.exp);
1853 ✗ then addArgument(result, exp, inverse);
1854
1855 case (_, Expression.SUBSCRIPTED_EXP()) algorithm
1856 200 exp.exp := combineBinariesExp(exp.exp);
1857
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 100 times.
308 exp.subscripts := list(combineBinariesSubscript(sub) for sub in exp.subscripts);
1858 100 then addArgument(result, exp, inverse);
1859
1860 case (_, Expression.TUPLE_ELEMENT()) algorithm
1861 ✗ exp.tupleExp := combineBinariesExp(exp.tupleExp);
1862 ✗ then addArgument(result, exp, inverse);
1863
1864 case (_, Expression.RECORD_ELEMENT()) algorithm
1865 74 exp.recordExp := combineBinariesExp(exp.recordExp);
1866 37 then addArgument(result, exp, inverse);
1867
1868 case (_, Expression.MUTABLE()) algorithm
1869 ✗ Mutable.update(exp.exp, combineBinariesExp(Mutable.access(exp.exp)));
1870 ✗ then addArgument(result, exp, inverse);
1871
1872 case (_, Expression.PARTIAL_FUNCTION_APPLICATION()) algorithm
1873
4/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 9 times.
55 exp.args := list(combineBinariesExp(arg) for arg in exp.args);
1874 9 then addArgument(result, exp, inverse);
1875
1876 // done on this branch
1877 33014 else addArgument(result, exp, inverse);
1878 end match;
1879 end combineBinariesExp;
1880
1881 protected function combineBinariesSubscript
1882 input output Subscript subscript;
1883 algorithm
1884 subscript := match subscript
1885 case Subscript.UNTYPED() algorithm
1886 ✗ subscript.exp := combineBinariesExp(subscript.exp);
1887 then subscript;
1888
1889 case Subscript.INDEX() algorithm
1890 7538 subscript.index := combineBinariesExp(subscript.index);
1891 then subscript;
1892
1893 case Subscript.SLICE() algorithm
1894 76 subscript.slice := combineBinariesExp(subscript.slice);
1895 then subscript;
1896
1897 case Subscript.EXPANDED_SLICE() algorithm
1898 ✗ subscript.indices := list(combineBinariesSubscript(sub) for sub in subscript.indices);
1899 then subscript;
1900
1901 else subscript;
1902 end match;
1903 end combineBinariesSubscript;
1904
1905 protected function addArgument
1906 input output Expression exp;
1907 input Expression arg;
1908 input Boolean inverse;
1909 algorithm
1910 exp := match exp
1911 // add to inverse arguments
1912 case Expression.MULTARY() guard(inverse) algorithm
1913 4468 exp.inv_arguments := arg :: exp.inv_arguments;
1914 then exp;
1915
1916 // add to arguments
1917 case Expression.MULTARY() algorithm
1918 24768 exp.arguments := arg :: exp.arguments;
1919 then exp;
1920
1921 // no multary on the stack, just return the expression
1922 case Expression.EMPTY() then arg;
1923
1924 // cannot be parsed
1925 else algorithm
1926 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to add : " +
1927 Expression.toString(arg) + " to " + Expression.toString(exp) + ". Only works for MULTARY()!"});
1928 ✗ then fail();
1929 end match;
1930 end addArgument;
1931
1932 function removeTrivialScalarProduct
1933 "removes trivial scalar products of size 1 vectors"
1934 input output Expression exp;
1935 protected
1936 Type ty;
1937 Expression exp1, exp2;
1938 list<Subscript> subs;
1939 algorithm
1940 exp := match exp
1941 // only do something for scalar products of size 1 vectors
1942 case Expression.BINARY(operator = Operator.OPERATOR(ty = ty, op = NFOperator.Op.SCALAR_PRODUCT))
1943 guard(Type.sizeOf(Expression.typeOf(exp.exp1)) == 1 and Type.sizeOf(Expression.typeOf(exp.exp2)) == 1) algorithm
1944 // generate "1" subscript for each dimension of the vector and apply them to left and right binary argument
1945
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 8 times.
16 subs := list(Subscript.INDEX(index = Expression.INTEGER(1)) for d in Type.arrayDims(Expression.typeOf(exp.exp1)));
1946 8 exp1 := Expression.applySubscripts(subs, exp.exp1);
1947
2/2
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 8 times.
16 subs := list(Subscript.INDEX(index = Expression.INTEGER(1)) for d in Type.arrayDims(Expression.typeOf(exp.exp2)));
1948 8 exp2 := Expression.applySubscripts(subs, exp.exp2);
1949 8 then Expression.BINARY(exp1, Operator.OPERATOR(ty, op = NFOperator.Op.MUL), exp2);
1950 else exp;
1951 end match;
1952 end removeTrivialScalarProduct;
1953
1954 function simplifyURIToFilename
1955 input Expression arg;
1956 input Call call;
1957 output Expression outExp;
1958 algorithm
1959
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if Flags.getConfigBool(Flags.BUILDING_FMU) then
1960 ✗ outExp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.FMU_LOAD_RESOURCE, {arg}, Call.variability(call), NFPrefixes.Purity.IMPURE));
1961 else
1962 2 outExp := Expression.CALL(call);
1963 end if;
1964 end simplifyURIToFilename;
1965
1966 annotation(__OpenModelica_Interface="nf_frontend");
1967 end NFSimplifyExp;
1968