Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 69.5% 707 / 0 / 1017
Functions: -% 0 / 1 / 1
Branches: 61.4% 616 / 0 / 1003

OMCompiler/Compiler/NBackEnd/Util/NBAdjacency.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 encapsulated package NBAdjacency
36 "file: NBAdjacency.mo
37 package: NBAdjacency
38 description: This file contains the functions which will create adjacency matrices.
39 "
40 public
41 // self import
42 import Adjacency = NBAdjacency;
43
44 protected
45 // OF imports
46 import Absyn.Path;
47
48 // Old Simcode imports
49 import OldSimCode = SimCode;
50
51 // NF imports
52 import Call = NFCall;
53 import ComponentRef = NFComponentRef;
54 import Dimension = NFDimension;
55 import Expression = NFExpression;
56 import NFFunction.Function;
57 import SimplifyExp = NFSimplifyExp;
58 import Statement = NFStatement;
59 import Subscript = NFSubscript;
60 import Type = NFType;
61 import Operator = NFOperator;
62 import NFOperator.Op;
63 import Variable = NFVariable;
64
65 // NB imports
66 import Differentiate = NBDifferentiate;
67 import NBDifferentiate.{DifferentiationArguments, DifferentiationType};
68 import BEquation = NBEquation;
69 import NBEquation.{Equation, EquationAttributes, EquationPointers, Iterator, IfEquationBody, WhenEquationBody, WhenStatement};
70 import Solve = NBSolve;
71 import BVariable = NBVariable;
72 import NBVariable.{VariablePointers, VarData};
73 import StrongComponent = NBStrongComponent;
74 import Partition = NBPartition;
75
76 // Util import
77 import Array;
78 import BackendUtil = NBBackendUtil;
79 import BuiltinSystem = System;
80 import Slice = NBSlice;
81 import StringUtil;
82 import Vector;
83
84 public
85 type MatrixStrictness = enumeration(LINEAR, MATCHING, SORTING, FULL);
86
87 function strictnessString
88 input MatrixStrictness s;
89 output String str;
90 algorithm
91 str := match s
92 case MatrixStrictness.LINEAR then "linear";
93 case MatrixStrictness.MATCHING then "matching";
94 case MatrixStrictness.SORTING then "sorting";
95 case MatrixStrictness.FULL then "full";
96 else "unknown";
97 end match;
98 end strictnessString;
99
100 uniontype Mapping
101 record MAPPING
102 array<Integer> eqn_StA "eqn: scal_idx -> arr_idx";
103 array<Integer> var_StA "var: scal_idx -> arr_idx";
104 array<tuple<Integer,Integer>> eqn_AtS "eqn: arr_idx -> start_idx/length";
105 array<tuple<Integer,Integer>> var_AtS "var: arr_idx -> start_idx/length";
106 end MAPPING;
107
108 function toString
109 input Mapping mapping;
110 output String str;
111 protected
112 Integer start, size;
113 algorithm
114 ✗ str := StringUtil.headline_4("Equation Index Mapping (ARR) -> START | SIZE");
115 ✗ for i in 1:arrayLength(mapping.eqn_AtS) loop
116 ✗ (start, size) := mapping.eqn_AtS[i];
117 ✗ str := str + "(" + intString(i) + ")\t" + intString(start) + " | " + intString(size) + "\n";
118 end for;
119 ✗ str := str + StringUtil.headline_4("Variable Index Mapping (ARR) -> START | SIZE");
120 ✗ for i in 1:arrayLength(mapping.var_AtS) loop
121 ✗ (start, size) := mapping.var_AtS[i];
122 ✗ str := str + "(" + intString(i) + ")\t" + intString(start) + " | " + intString(size) + "\n";
123 end for;
124 end toString;
125
126 function empty
127 output Mapping mapping = MAPPING(arrayCreate(0, 0), arrayCreate(0, 0),arrayCreate(0, (0,0)),arrayCreate(0, (0,0)));
128 end empty;
129
130 function create
131 input EquationPointers eqns;
132 input VariablePointers vars;
133 output Mapping mapping;
134 protected
135 list<Pointer<Equation>> eqn_lst = EquationPointers.toList(eqns);
136 list<Pointer<Variable>> var_lst = VariablePointers.toList(vars);
137 array<Integer> eqn_StA, var_StA;
138 array<tuple<Integer,Integer>> eqn_AtS, var_AtS;
139 Integer eqn_scalar_size, var_scalar_size;
140 Integer eqn_idx_scal = 1, eqn_idx_arr = 1, var_idx_scal = 1, var_idx_arr = 1;
141 algorithm
142 // prepare the mappings
143
4/4
✓ Branch 0 taken 15038 times.
✓ Branch 1 taken 2000 times.
✓ Branch 2 taken 15038 times.
✓ Branch 3 taken 2000 times.
17038 eqn_scalar_size := sum(Equation.size(eqn, true) for eqn in eqn_lst);
144
4/4
✓ Branch 0 taken 11905 times.
✓ Branch 1 taken 2000 times.
✓ Branch 2 taken 11905 times.
✓ Branch 3 taken 2000 times.
13905 var_scalar_size := sum(BVariable.size(var, true) for var in var_lst);
145 2000 eqn_StA := arrayCreate(eqn_scalar_size, -1);
146 2000 var_StA := arrayCreate(var_scalar_size, -1);
147 2000 eqn_AtS := arrayCreate(EquationPointers.size(eqns), (-1, -1));
148 2000 var_AtS := arrayCreate(VariablePointers.size(vars), (-1, -1));
149
150 // fill the arrays
151 2000 (eqn_StA, var_StA, eqn_AtS, var_AtS) := fill_(eqn_StA, var_StA, eqn_AtS, var_AtS, eqn_lst, var_lst, eqn_idx_scal, eqn_idx_arr, var_idx_scal, var_idx_arr);
152
153 // compile mapping
154 2000 mapping := MAPPING(eqn_StA, var_StA, eqn_AtS, var_AtS);
155 end create;
156
157 function expand
158 input output Mapping mapping;
159 input list<Pointer<Equation>> eqn_lst;
160 input list<Pointer<Variable>> var_lst;
161 protected
162 array<Integer> eqn_StA, var_StA;
163 array<tuple<Integer,Integer>> eqn_AtS, var_AtS;
164 Integer eqn_scalar_size, var_scalar_size;
165 Integer neqn_scal = sum(Equation.size(eqn, true) for eqn in eqn_lst);
166 Integer nvar_scal = sum(BVariable.size(var, true) for var in var_lst);
167 Integer neqn_arr = listLength(eqn_lst);
168 Integer nvar_arr = listLength(var_lst);
169 Integer eqn_idx_scal = arrayLength(mapping.eqn_StA) + 1, eqn_idx_arr = arrayLength(mapping.eqn_AtS) + 1;
170 Integer var_idx_scal = arrayLength(mapping.var_StA) + 1, var_idx_arr = arrayLength(mapping.var_AtS) + 1;
171 algorithm
172
173 // copy all data
174 28 eqn_StA := Array.expandToSize(eqn_idx_scal - 1 + neqn_scal, mapping.eqn_StA, -1);
175 28 var_StA := Array.expandToSize(var_idx_scal - 1 + nvar_scal, mapping.var_StA, -1);
176 28 eqn_AtS := Array.expandToSize(eqn_idx_arr - 1 + neqn_arr, mapping.eqn_AtS, (-1, -1));
177 28 var_AtS := Array.expandToSize(var_idx_arr - 1 + nvar_arr, mapping.var_AtS, (-1, -1));
178
179 // fill the new sections
180 28 (eqn_StA, var_StA, eqn_AtS, var_AtS) := fill_(eqn_StA, var_StA, eqn_AtS, var_AtS, eqn_lst, var_lst, eqn_idx_scal, eqn_idx_arr, var_idx_scal, var_idx_arr);
181
182 // compile mapping
183 28 mapping := MAPPING(eqn_StA, var_StA, eqn_AtS, var_AtS);
184 end expand;
185
186 function getEqnScalIndices
187 input Integer arr_idx;
188 input Mapping mapping;
189 input Boolean reverse = false;
190 output list<Integer> scal_indices;
191 protected
192 Integer start, length;
193 algorithm
194 ✗ (start, length) := mapping.eqn_AtS[arr_idx];
195 ✗ scal_indices := if reverse then
196 List.intRange2(start + length - 1, start) else
197 List.intRange2(start, start + length - 1);
198 end getEqnScalIndices;
199
200 function getVarScalIndices
201 input Integer arr_idx;
202 input Mapping mapping;
203 input list<Subscript> subs;
204 input list<Dimension> dims;
205 input Boolean reverse = false;
206 output list<Integer> scal_indices;
207 protected
208 Integer start, length;
209 function subscriptedIndices
210 input Integer start;
211 input Integer length;
212 input list<Integer> slice;
213 output list<Integer> scal_indices;
214 algorithm
215 ✗ scal_indices := List.intRange2(start, start + length - 1);
216 ✗ if not listEmpty(slice) then
217 ✗ scal_indices := List.keepPositions(scal_indices, slice);
218 end if;
219 end subscriptedIndices;
220 algorithm
221 ✗ (start, length) := mapping.var_AtS[arr_idx];
222
223 scal_indices := match subs
224 local
225 Subscript sub;
226 list<list<Subscript>> subs_lst;
227 list<Integer> slice = {}, dim_sizes, values;
228
229 // no subscripts -> create full index list
230 ✗ case {} then subscriptedIndices(start, length, {});
231
232 // all subscripts are whole -> create full index list
233 ✗ case _ guard(List.all(subs, Subscript.isWhole)) then subscriptedIndices(start, length, {});
234
235 // only one subscript -> apply simple rule
236 case {sub} algorithm
237 ✗ slice := Subscript.toIndexList(sub, length);
238 ✗ then subscriptedIndices(start, length, slice);
239
240 // multiple subscripts -> apply location to index mapping rules
241 case _ algorithm
242 ✗ subs_lst := Subscript.scalarizeList(subs, dims, true);
243 ✗ subs_lst := List.combination(subs_lst);
244 ✗ dim_sizes := list(Dimension.size(dim) for dim in dims);
245 ✗ for sub_lst in listReverse(subs_lst) loop
246 ✗ values := list(Subscript.toInteger(s) for s in sub_lst);
247 ✗ slice := Slice.locationToIndex(dim_sizes, values, start) :: slice;
248 end for;
249 then slice;
250
251 else fail();
252 end match;
253
254 ✗ if reverse then
255 ✗ scal_indices := listReverse(scal_indices);
256 end if;
257 end getVarScalIndices;
258
259 protected
260 function fill_
261 input output array<Integer> eqn_StA;
262 input output array<Integer> var_StA;
263 input output array<tuple<Integer,Integer>> eqn_AtS;
264 input output array<tuple<Integer,Integer>> var_AtS;
265 input list<Pointer<Equation>> eqn_lst;
266 input list<Pointer<Variable>> var_lst;
267 input Integer eqn_idx_scal_start;
268 input Integer eqn_idx_arr_start;
269 input Integer var_idx_scal_start;
270 input Integer var_idx_arr_start;
271 protected
272 Integer size;
273 Integer eqn_idx_scal = eqn_idx_scal_start;
274 Integer eqn_idx_arr = eqn_idx_arr_start;
275 Integer var_idx_scal = var_idx_scal_start;
276 Integer var_idx_arr= var_idx_arr_start;
277 algorithm
278 // fill equation mapping
279
2/2
✓ Branch 0 taken 15092 times.
✓ Branch 1 taken 2028 times.
17120 for eqn_ptr in eqn_lst loop
280 15092 size := Equation.size(eqn_ptr, true);
281 15092 eqn_AtS[eqn_idx_arr] := (eqn_idx_scal, size);
282
2/2
✓ Branch 0 taken 14771 times.
✓ Branch 1 taken 321 times.
44329 for i in eqn_idx_scal:eqn_idx_scal+size-1 loop
283 29237 eqn_StA[i] := eqn_idx_arr;
284 end for;
285 eqn_idx_scal := eqn_idx_scal + size;
286 15092 eqn_idx_arr := eqn_idx_arr + 1;
287 end for;
288 // fill variable mapping
289
2/2
✓ Branch 0 taken 11905 times.
✓ Branch 1 taken 2028 times.
13933 for var_ptr in var_lst loop
290 11905 size := BVariable.size(var_ptr, true);
291 11905 var_AtS[var_idx_arr] := (var_idx_scal, size);
292
2/2
✓ Branch 0 taken 11904 times.
✓ Branch 1 taken 1 time.
41925 for i in var_idx_scal:var_idx_scal+size-1 loop
293 30020 var_StA[i] := var_idx_arr;
294 end for;
295 var_idx_scal := var_idx_scal + size;
296 11905 var_idx_arr := var_idx_arr + 1;
297 end for;
298 end fill_;
299 end Mapping;
300
301 uniontype Mode
302 record MODE
303 "most of the time this will only have one cref. if there are multiple crefs
304 representing the same variable its a multi mode and the equation needs to
305 be split when solved for it"
306 ComponentRef eqn_name "the equation name";
307 list<ComponentRef> crefs "the cref(s) to solve for";
308 Boolean scalarize "true if the equation needs to be scalarized to find the cref to solve for";
309 end MODE;
310
311 function toString
312 input Mode mode;
313 output String str = "[eqn: " + ComponentRef.toString(mode.eqn_name) + ", crefs: " + List.toString(mode.crefs, ComponentRef.toString) + ", scal: " + boolString(mode.scalarize) + "]";
314 end toString;
315
316 function hash
317 input Mode mode;
318 output Integer hash = ComponentRef.hash(mode.eqn_name);
319 end hash;
320
321 function isEqual
322 input Mode mode1;
323 input Mode mode2;
324 output Boolean b = ComponentRef.isEqual(mode1.eqn_name, mode2.eqn_name) and mode1.scalarize == mode2.scalarize
325 and List.isEqualOnTrue(mode1.crefs, mode2.crefs, ComponentRef.isEqual);
326 end isEqual;
327
328 function create
329 input ComponentRef eqn_name;
330 input list<ComponentRef> crefs;
331 input Boolean scalarize;
332 output Mode mode = MODE(eqn_name, list(ComponentRef.simplifySubscripts(cref) for cref in crefs), scalarize);
333 end create;
334
335 function merge
336 input Mode mode1;
337 input Mode mode2;
338 output Mode oMode = MODE(mode1.eqn_name, listAppend(mode1.crefs, mode2.crefs), mode1.scalarize or mode2.scalarize);
339 end merge;
340
341 end Mode;
342
343 type ModeTable = Vector<Mode>
344 "the distinct causalization modes. a matrix entry refers to one by its index
345 in here (0 for none), kept in the matrix payload instead of in a map keyed
346 on the (equation, variable) pair.";
347
348 package Modes
349 function new
350 output ModeTable modes = Vector.new<Mode>(0);
351 end new;
352
353 function add
354 input ModeTable modes;
355 input Mode mode;
356 output Integer id;
357 algorithm
358 24366 Vector.push(modes, mode);
359 24366 id := Vector.size(modes);
360 end add;
361
362 function get
363 "the mode of the (eqn, var) entry. duplicate entries are merged the way
364 UnorderedMap.addMerge did, newest first, which is the row order."
365 input ModeTable modes;
366 input IntMatrix m;
367 input array<Integer> data;
368 input array<Integer> ids;
369 input Integer eqn;
370 input Integer var;
371 output Option<Mode> res = NONE();
372 protected
373 Integer first = m.start[eqn];
374 Mode mode;
375 algorithm
376
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18231 times.
60330 for k in first:first + m.len[eqn] - 1 loop
377
4/4
✓ Branch 1 taken 18231 times.
✓ Branch 2 taken 23868 times.
✓ Branch 4 taken 18110 times.
✓ Branch 5 taken 121 times.
42099 if data[k] == var and ids[k] > 0 then
378 18110 mode := Vector.getNoBounds(modes, ids[k]);
379 res := match res
380 local Mode acc;
381 ✗ case SOME(acc) then SOME(Mode.merge(acc, mode));
382 else SOME(mode);
383 end match;
384 end if;
385 end for;
386 end get;
387 end Modes;
388
389 uniontype IntMatrix
390 "Adjacency rows stored flat: every row is a slice of one append-only integer
391 buffer. Nothing in here is a pointer, so the collector does not have to walk
392 the nonzeros. aux carries one extra integer per entry (the causalization
393 mode id of the normal matrix), and is empty where it is not used."
394
395 record INT_MATRIX
396 array<Integer> start "row -> 1-based index of its first entry in data";
397 array<Integer> len "row -> number of entries";
398 Vector<Integer> data "entry buffer, only appended to";
399 Vector<Integer> aux "payload parallel to data, empty if unused";
400 end INT_MATRIX;
401
402 uniontype Builder
403 "The matrix is filled by collecting (row, entry) pairs in any order;
404 fromBuilder() then groups them by row in one counting sort."
405 record BUILDER
406 Vector<Integer> pairs;
407 Vector<Integer> aux;
408 Boolean hasAux;
409 end BUILDER;
410 end Builder;
411
412 function new
413 input Integer rows;
414 output IntMatrix m = INT_MATRIX(arrayCreate(rows, 1), arrayCreate(rows, 0), Vector.new<Integer>(0), Vector.new<Integer>(0));
415 end new;
416
417 function rows
418 input IntMatrix m;
419 output Integer n = arrayLength(m.start);
420 end rows;
421
422 function nonZeroCount
423 input IntMatrix m;
424 output Integer count = sum(l for l in m.len);
425 end nonZeroCount;
426
427 function entries
428 "the raw entry buffer, indexed by start[row] .. start[row]+len[row]-1.
429 invalidated by anything that adds entries"
430 input IntMatrix m;
431 output array<Integer> data = Vector.rawArray(m.data);
432 end entries;
433
434 function payload
435 input IntMatrix m;
436 output array<Integer> aux = Vector.rawArray(m.aux);
437 end payload;
438
439 function toList
440 input IntMatrix m;
441 input Integer row;
442 output list<Integer> lst = {};
443 protected
444 array<Integer> data = Vector.rawArray(m.data);
445 Integer first = m.start[row];
446 algorithm
447 ✗ for k in first + m.len[row] - 1:-1:first loop
448 ✗ lst := data[k] :: lst;
449 end for;
450 end toList;
451
452 function setRow
453 "replaces a row by appending its new entries to the buffer. the payload,
454 if any, is not maintained"
455 input IntMatrix m;
456 input Integer row;
457 input list<Integer> values;
458 algorithm
459 ✗ arrayUpdate(m.start, row, Vector.size(m.data) + 1);
460 ✗ arrayUpdate(m.len, row, listLength(values));
461 ✗ for v in values loop
462 ✗ Vector.push(m.data, v);
463 end for;
464 end setRow;
465
466 function setRowFromArray
467 "setRow with the first n entries of values"
468 input IntMatrix m;
469 input Integer row;
470 input array<Integer> values;
471 input Integer n;
472 algorithm
473 2578 arrayUpdate(m.start, row, Vector.size(m.data) + 1);
474 2578 arrayUpdate(m.len, row, n);
475
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2578 times.
24379 for i in 1:n loop
476 21801 Vector.push(m.data, values[i]);
477 end for;
478 end setRowFromArray;
479
480 function reserveData
481 "makes room for extra more entries so that adding them does not grow the buffer"
482 input IntMatrix m;
483 input Integer extra;
484 input Boolean withAux = false;
485 algorithm
486 1634 Vector.reserve(m.data, Vector.size(m.data) + extra);
487
2/2
✓ Branch 0 taken 1622 times.
✓ Branch 1 taken 12 times.
1634 if withAux then
488 12 Vector.reserve(m.aux, Vector.size(m.aux) + extra);
489 end if;
490 end reserveData;
491
492 function clearRow
493 input IntMatrix m;
494 input Integer row;
495 algorithm
496 23098 arrayUpdate(m.len, row, 0);
497 end clearRow;
498
499 function copyRow
500 "appends row src of `from` (whose buffer must be given) as row dst of m"
501 input IntMatrix from;
502 input Integer src;
503 input array<Integer> from_data;
504 input array<Integer> from_aux;
505 input IntMatrix m;
506 input Integer dst;
507 protected
508 Integer first = from.start[src], n = from.len[src];
509 Boolean aux = arrayLength(from_aux) > 0;
510 algorithm
511 1304 arrayUpdate(m.start, dst, Vector.size(m.data) + 1);
512 1304 arrayUpdate(m.len, dst, n);
513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1304 times.
4843 for k in first:first + n - 1 loop
514 3539 Vector.push(m.data, from_data[k]);
515
1/2
✓ Branch 0 taken 3539 times.
✗ Branch 1 not taken.
3539 if aux then
516 3539 Vector.push(m.aux, from_aux[k]);
517 end if;
518 end for;
519 end copyRow;
520
521 function expandRows
522 input output IntMatrix m;
523 input Integer shift;
524 algorithm
525
2/2
✓ Branch 0 taken 1244 times.
✓ Branch 1 taken 378 times.
1622 if shift > 0 then
526
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 378 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 378 times.
1134 m := INT_MATRIX(Array.expandToSize(arrayLength(m.start) + shift, m.start, 1),
527 Array.expandToSize(arrayLength(m.len) + shift, m.len, 0), m.data, m.aux);
528 end if;
529 end expandRows;
530
531 function transpose
532 "transposes the matrix, dropping any payload. a negative entry -v means
533 that row occurs negated in column v. each result row comes out descending,
534 matching what List.sort(.., intLt) produced before.
535 slack reserves buffer space for rows that are merged in afterwards."
536 input IntMatrix m;
537 input Integer size "number of rows of the result (does not have to be square!)";
538 input Integer slack = 0;
539 output IntMatrix mT;
540 protected
541 array<Integer> data = Vector.rawArray(m.data);
542 array<Integer> start, len, out;
543 Integer n = arrayLength(m.start), nnz = 0, idx, pos, first;
544 Boolean negated = false;
545 algorithm
546 5467 start := arrayCreate(size, 1);
547 5467 len := arrayCreate(size, 0);
548
549
1/2
✓ Branch 0 taken 5467 times.
✗ Branch 1 not taken.
85271 for r in 1:n loop
550 79804 first := m.start[r];
551
2/2
✓ Branch 1 taken 59880 times.
✓ Branch 2 taken 19924 times.
228315 for k in first:first + m.len[r] - 1 loop
552 148511 idx := intAbs(data[k]);
553
1/2
✓ Branch 0 taken 148511 times.
✗ Branch 1 not taken.
148511 if idx > 0 and idx <= size then
554 148511 arrayUpdate(len, idx, len[idx] + 1);
555 148511 nnz := nnz + 1;
556
2/4
✓ Branch 0 taken 148511 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 148511 times.
148511 negated := negated or data[k] < 0;
557 else
558 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for variable index " + intString(data[k]) + ".
559 The variables have to be dense (without empty spaces) for this to work!"});
560 end if;
561 end for;
562 end for;
563
564 pos := 1;
565
1/2
✓ Branch 0 taken 5467 times.
✗ Branch 1 not taken.
5467 for c in 1:size loop
566 80154 arrayUpdate(start, c, pos);
567 80154 pos := pos + len[c];
568 end for;
569
570 5467 out := arrayCreate(nnz + slack, 0);
571
572 // scatter, using start as the cursor and winding it back afterwards.
573 // positive entries first, rows descending
574
1/2
✓ Branch 0 taken 5467 times.
✗ Branch 1 not taken.
85271 for r in n:-1:1 loop
575 79804 first := m.start[r];
576
2/2
✓ Branch 1 taken 59880 times.
✓ Branch 2 taken 19924 times.
228315 for k in first:first + m.len[r] - 1 loop
577 148511 idx := data[k];
578
1/2
✓ Branch 0 taken 148511 times.
✗ Branch 1 not taken.
148511 if idx > 0 and idx <= size then
579 148511 arrayUpdate(out, start[idx], r);
580 148511 arrayUpdate(start, idx, start[idx] + 1);
581 end if;
582 end for;
583 end for;
584
585 // then the negated ones, rows ascending so that -row descends
586
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5467 times.
5467 if negated then
587 ✗ for r in 1:n loop
588 ✗ first := m.start[r];
589 ✗ for k in first:first + m.len[r] - 1 loop
590 ✗ idx := data[k];
591 ✗ if idx < 0 and -idx <= size then
592 ✗ arrayUpdate(out, start[-idx], -r);
593 ✗ arrayUpdate(start, -idx, start[-idx] + 1);
594 end if;
595 end for;
596 end for;
597 end if;
598
599
1/2
✓ Branch 0 taken 5467 times.
✗ Branch 1 not taken.
85621 for c in 1:size loop
600 80154 arrayUpdate(start, c, start[c] - len[c]);
601 end for;
602
603 5467 mT := INT_MATRIX(start, len, Vector.fromArrayNoCopy(out, nnz), Vector.new<Integer>(0));
604 end transpose;
605
606 function newBuilder
607 input Integer capacity = 0;
608 input Boolean withAux = false;
609 output Builder b = Builder.BUILDER(Vector.new<Integer>(2 * capacity),
610 Vector.new<Integer>(if withAux then capacity else 0), withAux);
611 end newBuilder;
612
613 function builderAdd
614 input Builder b;
615 input Integer row;
616 input Integer value;
617 algorithm
618 9628 Vector.push(b.pairs, row);
619 9628 Vector.push(b.pairs, value);
620 end builderAdd;
621
622 function builderAddAux
623 input Builder b;
624 input Integer row;
625 input Integer value;
626 input Integer aux;
627 algorithm
628 51950 Vector.push(b.pairs, row);
629 51950 Vector.push(b.pairs, value);
630 51950 Vector.push(b.aux, aux);
631 end builderAddAux;
632
633 function builderAddList
634 "adds a whole row front, keeping the order of the list"
635 input Builder b;
636 input Integer row;
637 input list<Integer> values;
638 input Integer aux = 0;
639 algorithm
640
2/2
✓ Branch 2 taken 639 times.
✓ Branch 3 taken 318 times.
957 for v in listReverse(values) loop
641 639 Vector.push(b.pairs, row);
642 639 Vector.push(b.pairs, v);
643
1/2
✓ Branch 0 taken 639 times.
✗ Branch 1 not taken.
639 if b.hasAux then
644 639 Vector.push(b.aux, aux);
645 end if;
646 end for;
647 end builderAddList;
648
649 function toBuilder
650 "seeds a builder with the entries of an existing matrix, oldest first, so that
651 fromBuilder puts them back in the same order"
652 input IntMatrix m;
653 input Integer capacity = 0;
654 input Boolean withAux = false;
655 output Builder b;
656 protected
657 array<Integer> data = Vector.rawArray(m.data);
658 array<Integer> aux = Vector.rawArray(m.aux);
659 Integer nnz = nonZeroCount(m), first;
660 algorithm
661 3833 b := newBuilder(intMax(nnz, capacity), withAux);
662
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3833 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3833 times.
66461 for r in 1:arrayLength(m.start) loop
663 58795 first := m.start[r];
664
2/2
✓ Branch 1 taken 26969 times.
✓ Branch 2 taken 31826 times.
118388 for k in first + m.len[r] - 1:-1:first loop
665 59593 Vector.push(b.pairs, r);
666 59593 Vector.push(b.pairs, data[k]);
667
1/2
✓ Branch 0 taken 59593 times.
✗ Branch 1 not taken.
59593 if withAux then
668 59593 Vector.push(b.aux, aux[k]);
669 end if;
670 end for;
671 end for;
672 end toBuilder;
673
674 function fromBuilder
675 "groups the collected pairs by row. entries were prepended to their row
676 before, so the pairs are distributed back to front."
677 input Builder b;
678 input Integer rows;
679 output IntMatrix m;
680 protected
681 array<Integer> raw = Vector.rawArray(b.pairs);
682 array<Integer> raux = Vector.rawArray(b.aux);
683 array<Integer> start, len, out, aout;
684 Integer n = intDiv(Vector.size(b.pairs), 2), r, pos = 1, p;
685 algorithm
686 4908 start := arrayCreate(rows, 1);
687 4908 len := arrayCreate(rows, 0);
688
689
2/2
✓ Branch 0 taken 4811 times.
✓ Branch 1 taken 97 times.
126718 for i in 1:n loop
690 121810 r := raw[2*i - 1];
691 121810 arrayUpdate(len, r, len[r] + 1);
692 end for;
693
694
2/2
✓ Branch 0 taken 4907 times.
✓ Branch 1 taken 1 time.
4908 for i in 1:rows loop
695 68854 arrayUpdate(start, i, pos);
696 68854 pos := pos + len[i];
697 end for;
698
699 4908 out := arrayCreate(n, 0);
700
2/2
✓ Branch 0 taken 1063 times.
✓ Branch 1 taken 3845 times.
5971 aout := arrayCreate(if b.hasAux then n else 0, 0);
701
702 // scatter, using start as the cursor and winding it back afterwards
703
2/2
✓ Branch 0 taken 4811 times.
✓ Branch 1 taken 97 times.
126718 for i in n:-1:1 loop
704 121810 r := raw[2*i - 1];
705 121810 p := start[r];
706 121810 arrayUpdate(out, p, raw[2*i]);
707
2/2
✓ Branch 0 taken 112182 times.
✓ Branch 1 taken 9628 times.
121810 if b.hasAux then
708 112182 arrayUpdate(aout, p, raux[i]);
709 end if;
710 121810 arrayUpdate(start, r, p + 1);
711 end for;
712
713
2/2
✓ Branch 0 taken 4907 times.
✓ Branch 1 taken 1 time.
73762 for i in 1:rows loop
714 68854 arrayUpdate(start, i, start[i] - len[i]);
715 end for;
716
717 4908 m := INT_MATRIX(start, len, Vector.fromArrayNoCopy(out, n), Vector.fromArrayNoCopy(aout, arrayLength(aout)));
718 end fromBuilder;
719
720 function toString
721 input IntMatrix m;
722 output String str = "";
723 protected
724 Integer skip = stringLength(intString(arrayLength(m.start))) + 1;
725 String tmp;
726 algorithm
727 ✗ for row in 1:arrayLength(m.start) loop
728 ✗ tmp := intString(row);
729 ✗ str := str + "\t(" + tmp + ")" + StringUtil.repeat(" ", skip - stringLength(tmp)) + List.toString(toList(m, row), intString) + "\n";
730 end for;
731 end toString;
732 end IntMatrix;
733
734 uniontype Matrix
735 "used to store adjacency information for the bipartite graph representing the system of equations and variables
736 you have to create it in this specific order: EMPTY->FULL->FINAL(LINEAR)->FINAL->(MATCHING)->FINAL(SORTING)
737 and store the FULL for further use."
738
739 record EMPTY "placeholder for empty matrices, just stores intended strictness"
740 MatrixStrictness st;
741 end EMPTY;
742
743 record FULL "contains all information needed. create specific final matrices from this"
744 array<ComponentRef> equation_names;
745 array<UnorderedSet<ComponentRef>> occurrences;
746 array<UnorderedMap<ComponentRef, Dependency>> dependencies;
747 array<UnorderedMap<ComponentRef, Solvability>> solvabilities;
748 array<UnorderedSet<ComponentRef>> repetitions;
749 Mapping mapping;
750 end FULL;
751
752 record FINAL "specific final matrix, defined by its strictness"
753 IntMatrix m "eqn -> vars";
754 IntMatrix mT "var -> eqns";
755 Mapping mapping "index mapping scalar <-> array";
756 ModeTable modes "array reconstruction information";
757 MatrixStrictness st "strictness with which it was created";
758 end FINAL;
759
760 record SPARSITY "contains sparsity information to create sparsity patterns for jacobians"
761 array<ComponentRef> equation_names;
762 array<Iterator> equation_iterators;
763 array<UnorderedMap<ComponentRef, Dependency>> dependencies;
764 array<UnorderedSet<ComponentRef>> repetitions;
765 array<list<ComponentRef>> solved_crefs;
766 end SPARSITY;
767
768 function createFull
769 input VariablePointers vars;
770 input EquationPointers eqns;
771 input Partition.Kind kind = NBPartition.Kind.ODE;
772 output Matrix adj;
773 protected
774 Integer index, size = EquationPointers.size(eqns);
775 array<ComponentRef> equation_names;
776 array<UnorderedSet<ComponentRef>> occurrences;
777 array<UnorderedMap<ComponentRef, Dependency>> dependencies;
778 array<UnorderedMap<ComponentRef, Solvability>> solvabilities;
779 array<UnorderedSet<ComponentRef>> repetitions;
780 UnorderedSet<ComponentRef> occ_set, rep_set;
781 UnorderedMap<ComponentRef, Dependency> dep_map;
782 UnorderedMap<ComponentRef, Solvability> sol_map;
783 Mapping mapping;
784 algorithm
785 // only create matrix if there are any variables or equations
786
3/4
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1904 times.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
1905 if ExpandableArray.getNumberOfElements(vars.varArr) > 0 or ExpandableArray.getNumberOfElements(eqns.eqArr) > 0 then
787 // create empty arrays for the structures
788 1905 equation_names := arrayCreate(size, ComponentRef.EMPTY());
789 1905 occurrences := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual));
790 1905 dependencies := arrayCreate(size, UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual));
791 1905 solvabilities := arrayCreate(size, UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual));
792 1905 repetitions := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual));
793 // loop over each equation and create the corresponding maps and sets
794
2/2
✓ Branch 1 taken 14432 times.
✓ Branch 2 taken 1905 times.
16337 for eqn_ptr in EquationPointers.toList(eqns) loop
795 14432 index := UnorderedMap.getSafe(Equation.getEqnName(eqn_ptr), eqns.map, sourceInfo());
796 14432 dep_map := UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual);
797 14432 sol_map := UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual);
798 14432 rep_set := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
799 14432 occ_set := collectDependenciesEquation(Pointer.access(eqn_ptr), kind, vars.map, dep_map, sol_map, rep_set);
800 14432 addInitialStartOccurrences(occ_set, dep_map, sol_map, rep_set, kind);
801 14432 equation_names[index] := Equation.getEqnName(eqn_ptr);
802 14432 occurrences[index] := occ_set;
803 14432 dependencies[index] := dep_map;
804 14432 solvabilities[index] := sol_map;
805 14432 repetitions[index] := rep_set;
806 end for;
807 // create the index mapping and the matrix
808 1905 mapping := Mapping.create(eqns, vars);
809 1905 adj := FULL(equation_names, occurrences, dependencies, solvabilities, repetitions, mapping);
810 else
811 adj := EMPTY(MatrixStrictness.FULL);
812 end if;
813
1/2
✓ Branch 1 taken 1905 times.
✗ Branch 2 not taken.
1905 if Flags.isSet(Flags.BLT_MATRIX_DUMP) then
814 ✗ print(StringUtil.headline_1("Creating Adjacency Matrices") + "\n");
815 ✗ print(EquationPointers.toString(eqns) + "\n");
816 ✗ print(VariablePointers.toString(vars) + "\n");
817 ✗ print(toString(adj, "Full") + "\n");
818 ✗ print(solvabilityString(adj, "Full") + "\n");
819 ✗ print(dependencyString(adj, "Full") + "\n");
820 end if;
821 end createFull;
822
823 function subFull
824 "creates the full matrix of a subset of equations and variables from an
825 existing one, sharing its per-equation maps. eqn_indices are the indices
826 of eqns in full, in the order of eqns."
827 input Matrix full;
828 input list<Integer> eqn_indices;
829 input EquationPointers eqns;
830 input VariablePointers vars;
831 output Matrix sub;
832 protected
833 Integer size = listLength(eqn_indices), j = 1;
834 array<ComponentRef> equation_names;
835 array<UnorderedSet<ComponentRef>> occurrences, repetitions;
836 array<UnorderedMap<ComponentRef, Dependency>> dependencies;
837 array<UnorderedMap<ComponentRef, Solvability>> solvabilities;
838 algorithm
839 sub := match full
840 case FULL() guard(size > 0) algorithm
841 95 equation_names := arrayCreate(size, ComponentRef.EMPTY());
842 95 occurrences := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual));
843 95 dependencies := arrayCreate(size, UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual));
844 95 solvabilities := arrayCreate(size, UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual));
845 95 repetitions := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual));
846
2/2
✓ Branch 0 taken 606 times.
✓ Branch 1 taken 95 times.
701 for i in eqn_indices loop
847 606 equation_names[j] := full.equation_names[i];
848 606 occurrences[j] := full.occurrences[i];
849 606 dependencies[j] := full.dependencies[i];
850 606 solvabilities[j] := full.solvabilities[i];
851 606 repetitions[j] := full.repetitions[i];
852 606 j := j + 1;
853 end for;
854 95 then FULL(equation_names, occurrences, dependencies, solvabilities, repetitions, Mapping.create(eqns, vars));
855 else EMPTY(MatrixStrictness.FULL);
856 end match;
857 end subFull;
858
859 function fullToFinal
860 input Matrix full;
861 input UnorderedMap<ComponentRef, Integer> vars_map;
862 input UnorderedMap<ComponentRef, Integer> eqns_map;
863 input EquationPointers eqns;
864 input MatrixStrictness st;
865 input Iterator iter = Iterator.EMPTY() "optional iterator the whole system might be surrounded by";
866 output Matrix adj = upgrade(EMPTY(MatrixStrictness.FULL), full, vars_map, eqns_map, eqns, st, iter);
867 end fullToFinal;
868
869 function fullToSparsity
870 input Matrix full;
871 input list<StrongComponent> comps;
872 input UnorderedSet<ComponentRef> seed_set;
873 input UnorderedSet<ComponentRef> pder_set;
874 input UnorderedMap<ComponentRef, ComponentRef> diff_map;
875 input Boolean isAdjoint = false;
876 output Matrix sparsity;
877
878 type Dependencies = list<ComponentRef>;
879 function filterSet
880 input ComponentRef cref;
881 input UnorderedSet<ComponentRef> set;
882 output Boolean b = UnorderedSet.contains(cref, set) or
883 UnorderedSet.contains(ComponentRef.stripSubscriptsAll(cref), set);
884 end filterSet;
885
886 function expandSlice
887 "a slice (e.g. i[1:2]) whose elements are seeds depends on each of the elements"
888 input ComponentRef cref;
889 input UnorderedMap<ComponentRef, ComponentRef> diff_map;
890 output list<ComponentRef> crefs;
891 protected
892 Type ty;
893 algorithm
894 crefs := {cref};
895
4/4
✓ Branch 1 taken 4522 times.
✓ Branch 2 taken 1885 times.
✓ Branch 5 taken 1260 times.
✓ Branch 6 taken 625 times.
6407 if not (UnorderedMap.contains(cref, diff_map) or UnorderedMap.contains(ComponentRef.stripSubscriptsAll(cref), diff_map)) then
896 625 ty := ComponentRef.getSubscriptedType(cref);
897
3/4
✓ Branch 1 taken 537 times.
✓ Branch 2 taken 88 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 88 times.
625 if Type.isArray(ty) and Type.sizeOf(ty) <= 256 then
898
6/6
✓ Branch 2 taken 224 times.
✓ Branch 3 taken 144 times.
✓ Branch 4 taken 368 times.
✓ Branch 5 taken 88 times.
✓ Branch 6 taken 144 times.
✓ Branch 7 taken 88 times.
456 crefs := list(c for c guard(UnorderedMap.contains(c, diff_map)) in ComponentRef.scalarizeAll(cref, false));
899
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 64 times.
88 if listEmpty(crefs) then
900 crefs := {cref};
901 end if;
902 end if;
903 end if;
904 end expandSlice;
905 algorithm
906 sparsity := match full
907 local
908 UnorderedMap<ComponentRef, Integer> index_map = UnorderedMap.new<Integer>(ComponentRef.hash, ComponentRef.isEqual);
909 UnorderedMap<ComponentRef, Dependencies> inner_map = UnorderedMap.new<Dependencies>(ComponentRef.hash, ComponentRef.isEqual);
910 list<Pointer<Equation>> eqns;
911 list<ComponentRef> var_crefs, pder_crefs, tmp_crefs, own_vars;
912 ComponentRef eqn_name, dep_cref, seed_cref, pder_cref;
913 Option<ComponentRef> oseed_cref;
914 Integer eqn_index;
915 Iterator iter;
916 Dependency dep;
917 list<tuple<list<ComponentRef>, Dependency, Boolean>> local_deps;
918 Boolean repeated;
919 list<ComponentRef> inner_deps;
920 Boolean changed;
921 Option<list<ComponentRef>> inner_opt;
922 UnorderedMap<ComponentRef, Dependency> dep_map;
923 UnorderedSet<ComponentRef> rep_set;
924
925 list<ComponentRef> eqn_names = {};
926 list<Iterator> eqn_iters = {};
927 list<UnorderedMap<ComponentRef, Dependency>> deps = {};
928 list<UnorderedSet<ComponentRef>> reps = {};
929 list<list<ComponentRef>> solved_crefs = {};
930 list<ComponentRef> iter_names;
931 UnorderedSet<ComponentRef> own_iters;
932 UnorderedMap<ComponentRef, Dependencies> seed_elements = UnorderedMap.new<Dependencies>(ComponentRef.hash, ComponentRef.isEqual);
933 UnorderedSet<ComponentRef> no_iters = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
934 UnorderedMap<ComponentRef, SliceAliases> slice_map = UnorderedMap.new<SliceAliases>(ComponentRef.hash, ComponentRef.isEqual);
935 UnorderedMap<ComponentRef, InnerTemplates> template_map = UnorderedMap.new<InnerTemplates>(ComponentRef.hash, ComponentRef.isEqual);
936 Boolean handled;
937 list<ComponentRef> alias_deps, template_deps;
938
939 case FULL() algorithm
940 // create the equation name -> index map
941
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
✓ Branch 2 taken 169 times.
✗ Branch 3 not taken.
2034 for i in 1:arrayLength(full.equation_names) loop
942 1696 UnorderedMap.add(full.equation_names[i], i, index_map);
943 end for;
944
945 // element seeds by variable name, for dependencies with iterators that can not be resolved
946
2/2
✓ Branch 1 taken 1726 times.
✓ Branch 2 taken 169 times.
1895 for key in UnorderedMap.keyList(diff_map) loop
947
4/6
✓ Branch 1 taken 122 times.
✓ Branch 2 taken 1604 times.
✓ Branch 5 taken 122 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 122 times.
✗ Branch 10 not taken.
1726 if ComponentRef.hasSubscripts(key) and List.all(ComponentRef.subscriptsAllFlat(key), Subscript.isLiteral)
948 and not UnorderedMap.contains(ComponentRef.stripSubscriptsAll(key), diff_map) then
949 244 UnorderedMap.add(ComponentRef.stripSubscriptsAll(key), key :: UnorderedMap.getOrDefault(ComponentRef.stripSubscriptsAll(key), seed_elements, {}), seed_elements);
950 end if;
951 end for;
952
953 // get only relevant equations
954 // check equation name. (STRONG COMPONENTS, NO NEED FOR EQUATIONS?)
955 // if it is EITHER inner or result, map all deps with tmp
956 // if it is an inner equation save the mapping to tmp name -> deps
957 // if it is a result equation save the mapping to final name -> deps
958
2/2
✓ Branch 0 taken 1701 times.
✓ Branch 1 taken 169 times.
1870 for comp in comps loop
959 1701 eqns := StrongComponent.getEquations(comp);
960 1701 var_crefs := StrongComponent.getVariableCrefs(comp);
961
962
2/2
✓ Branch 0 taken 1704 times.
✓ Branch 1 taken 1701 times.
3405 for eqn in eqns loop
963 1704 eqn_name := Equation.getEqnName(eqn);
964 1704 eqn_index := UnorderedMap.getSafe(eqn_name, index_map, sourceInfo());
965
966 // map the dependencies with the inner maps
967 1704 local_deps := {};
968 1704 changed := false;
969 // the variable a single equation solves is no input of it
970
2/2
✓ Branch 1 taken 1699 times.
✓ Branch 2 taken 5 times.
1704 own_vars := if listLength(eqns) == 1 then var_crefs else {};
971
8/8
✓ Branch 6 taken 911 times.
✓ Branch 7 taken 2979 times.
✓ Branch 8 taken 3890 times.
✓ Branch 9 taken 1704 times.
✓ Branch 10 taken 2979 times.
✓ Branch 11 taken 1704 times.
✓ Branch 13 taken 2979 times.
✓ Branch 14 taken 1704 times.
8573 for tpl in list(t for t guard(not List.any(own_vars, function ComponentRef.isEqual(cref2 = Util.tuple21(t))))
972 in UnorderedMap.toList(full.dependencies[eqn_index])) loop
973 2979 (dep_cref, dep) := tpl;
974 2979 repeated := UnorderedSet.contains(dep_cref, full.repetitions[eqn_index]);
975 (inner_deps, changed) := match UnorderedMap.get(dep_cref, inner_map)
976 // with resizable arrays other slices of the variable (e.g. solved by an algebraic
977 // loop) can have the same iterator but another range, also use their dependencies
978 case SOME(inner_deps) guard Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) and not filterSet(dep_cref, seed_set) and ComponentRef.hasSubscripts(dep_cref) algorithm
979 70 inner_opt := UnorderedMap.get(ComponentRef.stripSubscriptsAll(dep_cref), inner_map);
980
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
70 if isSome(inner_opt) then
981
6/6
✓ Branch 2 taken 97 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 70 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 70 times.
180 inner_deps := UnorderedSet.unique_list(listAppend(inner_deps, List.flatten(list(sparsityExpandForeignIterators(c, no_iters, seed_elements)
982 for c guard not List.contains(inner_deps, c, ComponentRef.isEqual) in Util.getOption(inner_opt)))), ComponentRef.hash, ComponentRef.isEqual);
983 end if;
984 then (inner_deps, true);
985 case SOME(inner_deps) then (inner_deps, true);
986 else algorithm
987 // Base-key fallback for subscripted inner LS vars (partial-slice NLS).
988 // Guard prevents outer seed elements (which strip to the same base key
989 // that may be in inner_map) from being misclassified as inner deps.
990 inner_deps := {dep_cref};
991
2/2
✓ Branch 1 taken 235 times.
✓ Branch 2 taken 1967 times.
2202 alias_deps := if filterSet(dep_cref, seed_set) then {} else sparsitySliceAliasDeps(dep_cref, slice_map);
992 handled := false;
993 2202 template_deps := {};
994
2/2
✓ Branch 1 taken 235 times.
✓ Branch 2 taken 1967 times.
2202 if not filterSet(dep_cref, seed_set) then
995 235 (handled, template_deps) := sparsityTemplateDeps(dep_cref, template_map);
996 end if;
997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2202 times.
2202 if not listEmpty(alias_deps) then
998 inner_deps := dep_cref :: alias_deps;
999 changed := true;
1000 elseif handled then
1001 116 inner_deps := dep_cref :: template_deps;
1002 changed := true;
1003 elseif not filterSet(dep_cref, seed_set) then
1004 119 inner_opt := UnorderedMap.get(ComponentRef.stripSubscriptsAll(dep_cref), inner_map);
1005
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 33 times.
119 if isSome(inner_opt) then
1006 // keep the cref itself, other elements of the same array might be seeds.
1007 // iterators of the found dependencies belong to another equation and can not be
1008 // matched with the ones of this equation (e.g. x[i+1] = y[i]), use all elements
1009
4/4
✓ Branch 1 taken 412 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 412 times.
✓ Branch 4 taken 86 times.
498 inner_deps := dep_cref :: List.flatten(list(sparsityExpandForeignIterators(c, no_iters, seed_elements) for c in Util.getOption(inner_opt)));
1010 changed := true;
1011 end if;
1012 end if;
1013 then (inner_deps, changed);
1014 end match;
1015
2/2
✓ Branch 0 taken 2702 times.
✓ Branch 1 taken 277 times.
5681 local_deps := (inner_deps, dep, repeated) :: local_deps;
1016 end for;
1017
1018 1704 (pder_crefs, tmp_crefs) := List.splitOnTrue(var_crefs, function filterSet(set = pder_set));
1019
1020 // handle result rows
1021
2/2
✓ Branch 0 taken 871 times.
✓ Branch 1 taken 833 times.
1704 if not listEmpty(pder_crefs) then
1022 // create a new dependency map for this row and get all relevant seeds
1023 871 dep_map := UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual);
1024 871 rep_set := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
1025 871 (iter_names, _, _) := Iterator.getFrames(Equation.getForIterator(Pointer.access(eqn)));
1026 871 own_iters := UnorderedSet.fromList(iter_names, ComponentRef.hash, ComponentRef.isEqual);
1027
2/2
✓ Branch 0 taken 2002 times.
✓ Branch 1 taken 871 times.
2873 for tpl in local_deps loop
1028 // this might lead to duplicate occurrences. can and should not be optimized here
1029 // as dependency information might not be combinable. optimize afterwards!
1030 // ToDo: combine dependencies
1031 2002 (inner_deps, dep, repeated) := tpl;
1032
4/4
✓ Branch 0 taken 2484 times.
✓ Branch 1 taken 2002 times.
✓ Branch 2 taken 2484 times.
✓ Branch 3 taken 2002 times.
4486 inner_deps := List.flatten(list(sparsityExpandForeignIterators(c, own_iters, seed_elements) for c in inner_deps));
1033
6/6
✓ Branch 0 taken 2493 times.
✓ Branch 1 taken 2002 times.
✓ Branch 2 taken 2493 times.
✓ Branch 3 taken 2002 times.
✓ Branch 6 taken 2523 times.
✓ Branch 7 taken 2002 times.
7018 for dep_cref in List.flatten(list(expandSlice(c, diff_map) for c in inner_deps)) loop
1034
2/2
✓ Branch 1 taken 2468 times.
✓ Branch 2 taken 55 times.
2523 if filterSet(dep_cref, seed_set) then
1035 // Try subscripted key first (NLS with per-element scalar seeds), then
1036 // base key with subscript copy (ODE/DAE with full-array base seeds).
1037 // Not found in either: not one of this Jacobian's own unknowns, so its
1038 // partial derivative here is zero -- skip instead of erroring.
1039 oseed_cref := match UnorderedMap.get(dep_cref, diff_map)
1040 case SOME(seed_cref) then SOME(seed_cref);
1041 else match UnorderedMap.get(ComponentRef.stripSubscriptsAll(dep_cref), diff_map)
1042 // Strip subscripts from the base seed before copying so that
1043 // origin subscripts (iterator or literal) merge onto an empty
1044 // template rather than clashing with existing literal subscripts.
1045 394 case SOME(seed_cref) then SOME(ComponentRef.copySubscripts(dep_cref, ComponentRef.stripSubscriptsAll(seed_cref)));
1046 else NONE();
1047 end match;
1048 end match;
1049
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2468 times.
✓ Branch 2 taken 2451 times.
✓ Branch 3 taken 17 times.
2468 if isSome(oseed_cref) then
1050 2451 seed_cref := Util.getOption(oseed_cref);
1051 2451 UnorderedMap.add(seed_cref, dep, dep_map);
1052
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 2384 times.
2451 if repeated then
1053 67 UnorderedSet.add(seed_cref, rep_set);
1054 end if;
1055 end if;
1056 end if;
1057 end for;
1058 end for;
1059
1060 // Store result variables (state derivatives) in inner_map so later
1061 // result equations can trace transitive dependencies through them.
1062 // e.g. der(x_i) = f(der(x_j), x_k) with der(x_j) = g(x_s) -> x_s dep.
1063
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 662 times.
871 if changed then
1064
4/4
✓ Branch 0 taken 479 times.
✓ Branch 1 taken 209 times.
✓ Branch 2 taken 479 times.
✓ Branch 3 taken 209 times.
688 inner_deps := List.flatten(list(Util.tuple31(tpl) for tpl in local_deps));
1065 209 inner_deps := UnorderedSet.unique_list(inner_deps, ComponentRef.hash, ComponentRef.isEqual);
1066 else
1067 662 inner_deps := UnorderedMap.keyList(full.dependencies[eqn_index]);
1068 end if;
1069
4/4
✓ Branch 0 taken 2214 times.
✓ Branch 1 taken 871 times.
✓ Branch 2 taken 2214 times.
✓ Branch 3 taken 871 times.
3085 inner_deps := List.filterOnTrue(List.flatten(list(expandSlice(c, diff_map) for c in inner_deps)), function filterSet(set = seed_set));
1070
2/2
✓ Branch 0 taken 873 times.
✓ Branch 1 taken 871 times.
1744 for cref in pder_crefs loop
1071 873 sparsityAddInner(cref, inner_deps, inner_map);
1072 873 sparsityAddTemplate(cref, inner_deps, template_map);
1073 end for;
1074
1075
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 860 times.
871 if isAdjoint then
1076 // The adjoint evaluates rows of the primal Jacobian. Map each
1077 // primal result row to its adjoint seed variable. The runtime
1078 // later transposes the generated primal CSC pattern to CSR.
1079
4/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 11 times.
22 pder_crefs := list(
1080 match UnorderedMap.get(ComponentRef.stripSubscriptsAll(cref), diff_map)
1081 11 case SOME(pder_cref) then ComponentRef.copySubscripts(cref, pder_cref);
1082 else algorithm
1083 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed because no adjoint seed was found for "
1084 + ComponentRef.toString(cref) + " in diff_map."});
1085 ✗ then fail();
1086 end match
1087 for cref in pder_crefs);
1088 else
1089 try
1090
4/4
✓ Branch 0 taken 862 times.
✓ Branch 1 taken 860 times.
✓ Branch 2 taken 862 times.
✓ Branch 3 taken 860 times.
1722 pder_crefs := list(BVariable.getPartnerCref(cref, function BVariable.getVarPDer(isTmp = false)) for cref in pder_crefs);
1091 else
1092 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for " + List.toString(pder_crefs, ComponentRef.toString)
1093 + " because they were supposed to be a row vars but at least one does not have a corresponding partial derivative."});
1094 ✗ fail();
1095 end try;
1096 end if;
1097
1098 // save the row/result dependencies
1099 // get the iterators (potentially need local iterators?)
1100 871 eqn_names := eqn_name :: eqn_names;
1101 1742 eqn_iters := Equation.getForIterator(Pointer.access(eqn)) :: eqn_iters;
1102 871 deps := dep_map :: deps;
1103 871 reps := rep_set :: reps;
1104 solved_crefs := pder_crefs :: solved_crefs;
1105 end if;
1106
1107 // handle inner temporary dependencies
1108
2/2
✓ Branch 0 taken 838 times.
✓ Branch 1 taken 866 times.
1704 if not listEmpty(tmp_crefs) then
1109
2/2
✓ Branch 0 taken 517 times.
✓ Branch 1 taken 321 times.
838 if changed then
1110 // some dependencies were mapped. additional dependency information is irrelevant
1111
4/4
✓ Branch 0 taken 740 times.
✓ Branch 1 taken 517 times.
✓ Branch 2 taken 740 times.
✓ Branch 3 taken 517 times.
1257 inner_deps := List.flatten(list(Util.tuple31(tpl) for tpl in local_deps));
1112 517 inner_deps := UnorderedSet.unique_list(inner_deps, ComponentRef.hash, ComponentRef.isEqual);
1113 else
1114 // nothing changed, just use the original dependencies
1115 321 inner_deps := UnorderedMap.keyList(full.dependencies[eqn_index]);
1116 end if;
1117
1118 // filter inner dependencies for relevant seeds and add
1119
4/4
✓ Branch 0 taken 1700 times.
✓ Branch 1 taken 838 times.
✓ Branch 2 taken 1700 times.
✓ Branch 3 taken 838 times.
2538 inner_deps := List.filterOnTrue(List.flatten(list(expandSlice(c, diff_map) for c in inner_deps)), function filterSet(set = seed_set));
1120 // with resizable arrays the variables of an algebraic loop depend on whole arrays,
1121 // the iterators of its equations do not correspond to the ones of other equations
1122
4/4
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 710 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 126 times.
838 if Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) and StrongComponent.isAlgebraicLoop(comp) then
1123
4/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 2 times.
7 inner_deps := UnorderedSet.unique_list(list(ComponentRef.stripSubscriptsAll(c) for c in inner_deps), ComponentRef.hash, ComponentRef.isEqual);
1124 end if;
1125
2/2
✓ Branch 0 taken 885 times.
✓ Branch 1 taken 838 times.
1723 for cref in tmp_crefs loop
1126 885 sparsityAddInner(cref, inner_deps, inner_map);
1127 885 sparsityAddTemplate(cref, inner_deps, template_map);
1128 end for;
1129 838 sparsityAddSliceAlias(Pointer.access(eqn), tmp_crefs, seed_set, slice_map);
1130 end if;
1131 end for;
1132 end for;
1133 169 then SPARSITY(
1134 equation_names = listArray(listReverse(eqn_names)),
1135 equation_iterators = listArray(listReverse(eqn_iters)),
1136 dependencies = listArray(listReverse(deps)),
1137 repetitions = listArray(listReverse(reps)),
1138 solved_crefs = listArray(listReverse(solved_crefs)));
1139
1140 ✗ case EMPTY() then SPARSITY(
1141 equation_names = listArray({}),
1142 equation_iterators = listArray({}),
1143 dependencies = listArray({}),
1144 repetitions = listArray({}),
1145 solved_crefs = listArray({}));
1146
1147 else algorithm
1148 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong matrix type.
1149 Expected: full, Got :" + strictnessString(getStrictness(full)) + "."});
1150 ✗ then fail();
1151 end match;
1152
1153
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
169 if Flags.isSet(Flags.BLT_MATRIX_DUMP) then
1154 ✗ print(toString(sparsity) + "\n");
1155 end if;
1156 end fullToSparsity;
1157
1158 type InnerTemplate = tuple<ComponentRef, list<ComponentRef>> "solved cref with the subscripts of its equation, its dependencies";
1159 type InnerTemplates = list<InnerTemplate>;
1160
1161 function sparsityAddTemplate
1162 input ComponentRef cref;
1163 input list<ComponentRef> deps;
1164 input UnorderedMap<ComponentRef, InnerTemplates> template_map;
1165 protected
1166 ComponentRef stripped = ComponentRef.stripSubscriptsAll(cref);
1167 algorithm
1168 3516 UnorderedMap.add(stripped, (cref, deps) :: UnorderedMap.getOrDefault(stripped, template_map, {}), template_map);
1169 end sparsityAddTemplate;
1170
1171 function sparsityTemplateDeps
1172 "x[e] from the inner equations solving x[f(i)] with dependencies y[g(i)]: y[g(f^-1(e))].
1173 Not handled if a subscript can not be matched this way."
1174 input ComponentRef cref;
1175 input UnorderedMap<ComponentRef, InnerTemplates> template_map;
1176 output Boolean handled = false;
1177 output list<ComponentRef> deps = {};
1178 protected
1179 InnerTemplates templates = UnorderedMap.getOrDefault(ComponentRef.stripSubscriptsAll(cref), template_map, {});
1180 list<Subscript> subs = ComponentRef.subscriptsAllWithWholeFlat(cref);
1181 Integer status;
1182 UnorderedMap<ComponentRef, Expression> bindings;
1183 ComponentRef key, dep;
1184 list<ComponentRef> key_deps;
1185 Boolean matched = false;
1186 algorithm
1187
2/2
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 165 times.
429 for template in templates loop
1188 264 (key, key_deps) := template;
1189 264 (status, bindings) := sparsityUnify(ComponentRef.subscriptsAllWithWholeFlat(key), subs);
1190
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 194 times.
264 if status == 2 then
1191 70 return;
1192 elseif status == 1 then
1193 matched := true;
1194
2/2
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 176 times.
422 for d in key_deps loop
1195
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 246 times.
246 if sparsityHasUnbound(d, bindings) then
1196 // an iterator of the inner equation that does not occur in the solved cref
1197 ✗ deps := ComponentRef.stripSubscriptsAll(d) :: deps;
1198 else
1199 246 dep := ComponentRef.mapExp(ComponentRef.mapExp(d, function sparsityBind(bindings = bindings)), sparsitySimplify);
1200
1/2
✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
246 if sparsityInBounds(dep) then
1201 deps := dep :: deps;
1202 end if;
1203 end if;
1204 end for;
1205 end if;
1206 end for;
1207 handled := matched;
1208 end sparsityTemplateDeps;
1209
1210 function sparsityUnify
1211 "0: the subscripts address different elements, 1: they match with the bindings, 2: unknown"
1212 input list<Subscript> key_subs;
1213 input list<Subscript> subs;
1214 output Integer status = 1;
1215 output UnorderedMap<ComponentRef, Expression> bindings = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual);
1216 protected
1217 Expression key_exp, exp, value, offset;
1218 Boolean ok, negated;
1219 ComponentRef iter;
1220 algorithm
1221
2/2
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 260 times.
264 if listLength(key_subs) <> listLength(subs) then
1222 status := 2;
1223 4 return;
1224 end if;
1225
2/2
✓ Branch 1 taken 355 times.
✓ Branch 2 taken 176 times.
531 for tpl in List.zip(key_subs, subs) loop
1226 () := match tpl
1227 case (Subscript.WHOLE(), _) then ();
1228 // a literal or a parameter (x[N]) binds nothing, it can only be told apart from another literal
1229 case (Subscript.INDEX(index = key_exp), _) guard(not sparsityHasIterator(key_exp)) algorithm
1230 () := match Util.tuple22(tpl)
1231 case Subscript.INDEX(index = exp) guard(Expression.isInteger(exp) and Expression.isInteger(key_exp)) algorithm
1232
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 if Expression.integerValue(exp) <> Expression.integerValue(key_exp) then
1233 status := 0;
1234 end if;
1235 then ();
1236 else ();
1237 end match;
1238 then ();
1239 // a symbolic index without iterators (e.g. x[N] of a resizable array) may match, like a literal
1240 case (Subscript.INDEX(index = key_exp), _) guard(not Expression.contains(key_exp, Expression.isIterator)) then ();
1241 case (Subscript.INDEX(index = key_exp), Subscript.INDEX(index = exp)) algorithm
1242 166 (ok, iter, offset, negated) := sparsityIteratorOffset(key_exp);
1243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 166 times.
166 if ok then
1244
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 165 times.
166 value := if negated
1245 then SimplifyExp.simplify(Expression.BINARY(offset, Operator.makeSub(Type.INTEGER()), exp))
1246 else SimplifyExp.simplify(Expression.BINARY(exp, Operator.makeSub(Type.INTEGER()), offset));
1247
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 166 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
166 if UnorderedMap.contains(iter, bindings) and not Expression.isEqual(value, UnorderedMap.getSafe(iter, bindings, sourceInfo())) then
1248 status := 2;
1249 else
1250 166 UnorderedMap.add(iter, value, bindings);
1251 end if;
1252 else
1253 status := 2;
1254 end if;
1255 then ();
1256 else algorithm
1257 status := 2;
1258 then ();
1259 end match;
1260 if status <> 1 then
1261 84 return;
1262 end if;
1263 end for;
1264 end sparsityUnify;
1265
1266 function sparsityIteratorOffset
1267 "i + c, c + i, i - c and i as (i, c, false), c - i as (i, c, true); c without iterators"
1268 input Expression exp;
1269 output Boolean ok = true;
1270 output ComponentRef iter = ComponentRef.EMPTY();
1271 output Expression offset = Expression.INTEGER(0);
1272 output Boolean negated = false;
1273 algorithm
1274 () := match exp
1275 case Expression.CREF() guard(ComponentRef.isIterator(exp.cref)) algorithm
1276 155 iter := exp.cref;
1277 then ();
1278 case Expression.BINARY(exp1 = Expression.CREF(cref = iter), operator = Operator.OPERATOR(op = Op.ADD), exp2 = offset)
1279 guard(ComponentRef.isIterator(iter) and not sparsityHasIterator(offset)) then ();
1280 case Expression.BINARY(exp1 = offset, operator = Operator.OPERATOR(op = Op.ADD), exp2 = Expression.CREF(cref = iter))
1281 guard(ComponentRef.isIterator(iter) and not sparsityHasIterator(offset)) then ();
1282 case Expression.BINARY(exp1 = Expression.CREF(cref = iter), operator = Operator.OPERATOR(op = Op.SUB), exp2 = offset)
1283 guard(ComponentRef.isIterator(iter) and not sparsityHasIterator(offset)) algorithm
1284 ✗ offset := Expression.negate(offset);
1285 then ();
1286 case Expression.BINARY(exp1 = offset, operator = Operator.OPERATOR(op = Op.SUB), exp2 = Expression.CREF(cref = iter))
1287 guard(ComponentRef.isIterator(iter) and not sparsityHasIterator(offset)) algorithm
1288 ✗ negated := true;
1289 then ();
1290 case Expression.MULTARY(operator = Operator.OPERATOR(op = Op.ADD)) algorithm
1291 2 (ok, iter, offset, negated) := sparsityMultaryOffset(exp);
1292 then ();
1293 else algorithm
1294 ok := false;
1295 then ();
1296 end match;
1297 end sparsityIteratorOffset;
1298
1299 function sparsityHasIterator
1300 input Expression exp;
1301 output Boolean b = UnorderedSet.any(Expression.extractCrefs(exp), ComponentRef.isIterator);
1302 end sparsityHasIterator;
1303
1304 function sparsitySimplify
1305 input output Expression exp;
1306 algorithm
1307 753 exp := SimplifyExp.simplify(exp);
1308 end sparsitySimplify;
1309
1310 function sparsityHasUnbound
1311 input ComponentRef cref;
1312 input UnorderedMap<ComponentRef, Expression> bindings;
1313 output Boolean b = false;
1314 algorithm
1315 // whole dimension subscripts (:) have no expression to check
1316
7/8
✗ Branch 2 not taken.
✓ Branch 3 taken 267 times.
✓ Branch 4 taken 267 times.
✓ Branch 5 taken 246 times.
✓ Branch 6 taken 267 times.
✓ Branch 7 taken 246 times.
✓ Branch 8 taken 267 times.
✓ Branch 9 taken 246 times.
780 for sub in list(s for s guard(not Subscript.isWhole(s)) in ComponentRef.subscriptsAllFlat(cref)) loop
1317
2/2
✓ Branch 3 taken 165 times.
✓ Branch 4 taken 267 times.
432 for c in UnorderedSet.toList(Expression.extractCrefs(Subscript.toExp(sub))) loop
1318
3/4
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 39 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 126 times.
165 if ComponentRef.isIterator(c) and not UnorderedMap.contains(c, bindings) then
1319 b := true;
1320 ✗ return;
1321 end if;
1322 end for;
1323 end for;
1324 end sparsityHasUnbound;
1325
1326 function sparsityMultaryOffset
1327 "a sum with one iterator, which may be subtracted, and terms without iterators"
1328 input Expression exp;
1329 output Boolean ok = false;
1330 output ComponentRef iter = ComponentRef.EMPTY();
1331 output Expression offset = Expression.INTEGER(0);
1332 output Boolean negated = false;
1333 protected
1334 list<Expression> its, inv_its, rest, inv_rest;
1335 algorithm
1336 () := match exp
1337 case Expression.MULTARY() algorithm
1338 2 (its, rest) := List.splitOnTrue(exp.arguments, sparsityIsIteratorExp);
1339 2 (inv_its, inv_rest) := List.splitOnTrue(exp.inv_arguments, sparsityIsIteratorExp);
1340
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 if listLength(its) + listLength(inv_its) == 1 then
1341 2 negated := listEmpty(its);
1342
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
3 iter := Expression.toCref(listHead(if negated then inv_its else its));
1343 2 offset := Expression.MULTARY(rest, inv_rest, exp.operator);
1344 2 ok := not sparsityHasIterator(offset);
1345 end if;
1346 then ();
1347 else ();
1348 end match;
1349 end sparsityMultaryOffset;
1350
1351 function sparsityIsIteratorExp
1352 input Expression exp;
1353 output Boolean b = Expression.isCref(exp) and ComponentRef.isIterator(Expression.toCref(exp));
1354 end sparsityIsIteratorExp;
1355
1356 function sparsityBind
1357 input output Expression exp;
1358 input UnorderedMap<ComponentRef, Expression> bindings;
1359 algorithm
1360 exp := match exp
1361 case Expression.CREF() guard(UnorderedMap.contains(exp.cref, bindings))
1362 126 then UnorderedMap.getSafe(exp.cref, bindings, sourceInfo());
1363 else exp;
1364 end match;
1365 end sparsityBind;
1366
1367 function sparsityInBounds
1368 "false if a literal subscript is outside of its dimension"
1369 input ComponentRef cref;
1370 output Boolean b = true;
1371 algorithm
1372 b := match cref
1373 local
1374 list<Dimension> dims;
1375 case ComponentRef.CREF() algorithm
1376 497 dims := Type.arrayDims(cref.ty);
1377
2/2
✓ Branch 2 taken 495 times.
✓ Branch 3 taken 2 times.
497 if listLength(dims) == listLength(cref.subscripts) then
1378
2/2
✓ Branch 1 taken 267 times.
✓ Branch 2 taken 495 times.
762 for tpl in List.zip(cref.subscripts, dims) loop
1379 () := match tpl
1380 local
1381 Expression e;
1382 Dimension d;
1383 case (Subscript.INDEX(index = e), d) guard(Expression.isInteger(e) and Dimension.isKnown(d)) algorithm
1384
2/4
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 140 times.
140 if Expression.integerValue(e) < 1 or Expression.integerValue(e) > Dimension.size(d) then
1385 b := false;
1386 end if;
1387 then ();
1388 else ();
1389 end match;
1390 end for;
1391 end if;
1392
2/4
✓ Branch 0 taken 495 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 497 times.
497 then b and sparsityInBounds(cref.restCref);
1393 else true;
1394 end match;
1395 end sparsityInBounds;
1396
1397 type SliceAlias = tuple<Expression, Expression, ComponentRef, Expression> "solved start, solved stop, seed, seed start";
1398 type SliceAliases = list<SliceAlias>;
1399
1400 function sparsityAddSliceAlias
1401 "remembers x[a:b] = y[c:d] (or whole arrays) of an inner equation solved for x,
1402 so that x[e] can be resolved to y[e - a + c] instead of all of y"
1403 input Equation eqn;
1404 input list<ComponentRef> tmp_crefs;
1405 input UnorderedSet<ComponentRef> seed_set;
1406 input UnorderedMap<ComponentRef, SliceAliases> slice_map;
1407 protected
1408 ComponentRef lhs, rhs;
1409 algorithm
1410 () := match eqn
1411 case Equation.ARRAY_EQUATION(lhs = Expression.CREF(cref = lhs), rhs = Expression.CREF(cref = rhs)) algorithm
1412 7 sparsityAddSliceAlias2(lhs, rhs, tmp_crefs, seed_set, slice_map);
1413 7 sparsityAddSliceAlias2(rhs, lhs, tmp_crefs, seed_set, slice_map);
1414 then ();
1415 else ();
1416 end match;
1417 end sparsityAddSliceAlias;
1418
1419 function sparsityAddSliceAlias2
1420 input ComponentRef solved;
1421 input ComponentRef seed;
1422 input list<ComponentRef> tmp_crefs;
1423 input UnorderedSet<ComponentRef> seed_set;
1424 input UnorderedMap<ComponentRef, SliceAliases> slice_map;
1425 protected
1426 ComponentRef solved_base = ComponentRef.stripSubscriptsAll(solved);
1427 ComponentRef seed_base = ComponentRef.stripSubscriptsAll(seed);
1428 Boolean ok1, ok2;
1429 Expression start1, stop1, start2, stop2;
1430 algorithm
1431
3/4
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 7 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
14 if not List.any(tmp_crefs, function sparsitySameBase(base = solved_base)) or not UnorderedSet.contains(seed_base, seed_set) then
1432 14 return;
1433 end if;
1434 ✗ (ok1, start1, stop1) := sparsitySliceBounds(solved);
1435 ✗ (ok2, start2, stop2) := sparsitySliceBounds(seed);
1436 // the sides of an array equation have the same size, only literal bounds can be checked
1437 ✗ if ok1 and ok2 and not (List.all({start1, stop1, start2, stop2}, Expression.isInteger)
1438 and Expression.integerValue(stop1) - Expression.integerValue(start1) <> Expression.integerValue(stop2) - Expression.integerValue(start2)) then
1439 ✗ UnorderedMap.add(solved_base, (start1, stop1, seed_base, start2) :: UnorderedMap.getOrDefault(solved_base, slice_map, {}), slice_map);
1440 end if;
1441 end sparsityAddSliceAlias2;
1442
1443 function sparsitySameBase
1444 input ComponentRef cref;
1445 input ComponentRef base;
1446 output Boolean b = ComponentRef.isEqual(ComponentRef.stripSubscriptsAll(cref), base);
1447 end sparsitySameBase;
1448
1449 function sparsitySliceBounds
1450 "bounds of a one-dimensional variable or a unit step slice of it"
1451 input ComponentRef cref;
1452 output Boolean ok = false;
1453 output Expression start = Expression.INTEGER(1);
1454 output Expression stop = Expression.INTEGER(0);
1455 protected
1456 Type ty = ComponentRef.getSubscriptedType(ComponentRef.stripSubscriptsAll(cref));
1457 list<Subscript> subs = ComponentRef.subscriptsAllFlat(cref);
1458 Integer istart, istep, istop;
1459 Expression size;
1460 algorithm
1461 ✗ if Type.dimensionCount(ty) <> 1 or listLength(subs) <> listLength(ComponentRef.getSubscripts(cref)) then
1462 ✗ return;
1463 end if;
1464 ✗ if Type.hasKnownSize(ty) then
1465 ✗ size := Expression.INTEGER(Type.sizeOf(ty));
1466 else
1467 size := match Type.arrayDims(ty)
1468 local
1469 Dimension dim;
1470 ✗ case {dim as Dimension.RESIZABLE()} then Dimension.sizeExp(dim);
1471 ✗ case {dim as Dimension.EXP()} then Dimension.sizeExp(dim);
1472 else Expression.EMPTY(Type.INTEGER());
1473 end match;
1474 end if;
1475 (ok, start, stop) := match subs
1476 local
1477 Expression range;
1478 list<Subscript> indices;
1479 ✗ case {} then (not Expression.isEmpty(size), Expression.INTEGER(1), size);
1480 ✗ case {Subscript.WHOLE()} then (not Expression.isEmpty(size), Expression.INTEGER(1), size);
1481 case {Subscript.SLICE(slice = range as Expression.RANGE())} guard(Expression.isLiteral(range)) algorithm
1482 ✗ (istart, istep, istop) := Expression.getIntegerRange(range, false);
1483 ✗ then (istep == 1, Expression.INTEGER(istart), Expression.INTEGER(istop));
1484 case {Subscript.SLICE(slice = range as Expression.RANGE())}
1485 guard(Util.applyOptionOrDefault(range.step, function Expression.isEqual(exp2 = Expression.INTEGER(1)), true))
1486 ✗ then (true, range.start, range.stop);
1487 case {Subscript.SLICE(slice = range as Expression.ARRAY())}
1488 ✗ then sparsityConsecutive(Expression.arrayElementList(range));
1489 case {Subscript.EXPANDED_SLICE(indices = indices)}
1490 ✗ then sparsityConsecutive(list(Subscript.toExp(sub) for sub in indices));
1491 ✗ else (false, start, stop);
1492 end match;
1493 end sparsitySliceBounds;
1494
1495 function sparsityConsecutive
1496 input list<Expression> indices;
1497 output Boolean ok;
1498 output Expression start_exp;
1499 output Expression stop_exp;
1500 protected
1501 Integer start = 0, stop = 0;
1502 algorithm
1503 ✗ (ok, start, stop) := sparsityConsecutive2(indices);
1504 ✗ start_exp := Expression.INTEGER(start);
1505 ✗ stop_exp := Expression.INTEGER(stop);
1506 end sparsityConsecutive;
1507
1508 function sparsityConsecutive2
1509 input list<Expression> indices;
1510 output Boolean ok = true;
1511 output Integer start = 0;
1512 output Integer stop = 0;
1513 algorithm
1514 ✗ for index in indices loop
1515 ✗ if not Expression.isInteger(index) then
1516 ok := false;
1517 ✗ return;
1518 end if;
1519 ✗ if stop == 0 then
1520 ✗ start := Expression.integerValue(index);
1521 elseif Expression.integerValue(index) <> stop + 1 then
1522 ok := false;
1523 ✗ return;
1524 end if;
1525 ✗ stop := Expression.integerValue(index);
1526 end for;
1527 ✗ ok := stop > 0;
1528 end sparsityConsecutive2;
1529
1530 function sparsitySliceAliasDeps
1531 "x[e] with a slice alias x[a:b] = y[c:d] -> y[e - a + c]"
1532 input ComponentRef cref;
1533 input UnorderedMap<ComponentRef, SliceAliases> slice_map;
1534 output list<ComponentRef> deps = {};
1535 protected
1536 list<SliceAlias> aliases;
1537 Expression start1, stop1, start2, index;
1538 ComponentRef seed;
1539 algorithm
1540 235 aliases := UnorderedMap.getOrDefault(ComponentRef.stripSubscriptsAll(cref), slice_map, {});
1541
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
235 if listEmpty(aliases) or listLength(ComponentRef.subscriptsAllFlat(cref)) <> listLength(ComponentRef.getSubscripts(cref)) then
1542 235 return;
1543 end if;
1544 _ := match ComponentRef.getSubscripts(cref)
1545 case {Subscript.INDEX(index = index)} algorithm
1546 ✗ for alias in aliases loop
1547 ✗ (start1, stop1, seed, start2) := alias;
1548 ✗ if not (Expression.isInteger(index) and (
1549 Expression.isInteger(start1) and Expression.integerValue(index) < Expression.integerValue(start1) or
1550 Expression.isInteger(stop1) and Expression.integerValue(index) > Expression.integerValue(stop1))) then
1551 ✗ deps := ComponentRef.setSubscripts({Subscript.INDEX(SimplifyExp.simplify(Expression.BINARY(
1552 Expression.BINARY(index, Operator.makeAdd(Type.INTEGER()), start2),
1553 Operator.makeSub(Type.INTEGER()), start1)))}, seed) :: deps;
1554 end if;
1555 end for;
1556 then ();
1557 else ();
1558 end match;
1559 end sparsitySliceAliasDeps;
1560
1561 function sparsityExpandForeignIterators
1562 "a dependency with iterators of another (inner) equation depends on all its seed elements"
1563 input ComponentRef cref;
1564 input UnorderedSet<ComponentRef> own_iters;
1565 input UnorderedMap<ComponentRef, list<ComponentRef>> seed_elements "base name -> element seeds";
1566 output list<ComponentRef> crefs = {cref};
1567 protected
1568 ComponentRef base;
1569 Type ty;
1570 algorithm
1571
2/2
✓ Branch 4 taken 2893 times.
✓ Branch 5 taken 16 times.
2909 if not List.all(ComponentRef.subscriptsAllFlat(cref), function sparsityIsOwnSubscript(own_iters = own_iters)) then
1572 16 base := ComponentRef.stripSubscriptsAll(cref);
1573
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if UnorderedMap.contains(base, seed_elements) then
1574 ✗ crefs := UnorderedMap.getSafe(base, seed_elements, sourceInfo());
1575 else
1576 16 ty := ComponentRef.getSubscriptedType(base);
1577
3/4
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 5 times.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
16 crefs := if Type.isArray(ty) and Type.sizeOf(ty) <= 1024 then ComponentRef.scalarizeAll(base, false) else {base};
1578 end if;
1579 end if;
1580 end sparsityExpandForeignIterators;
1581
1582 function sparsityIsOwnSubscript
1583 input Subscript sub;
1584 input UnorderedSet<ComponentRef> own_iters;
1585 output Boolean b = Subscript.isLiteral(sub) or Subscript.isWhole(sub) or Subscript.isSliced(sub)
1586 or UnorderedSet.all(Expression.extractCrefs(Subscript.toExp(sub)), function sparsityIsOwnCref(own_iters = own_iters));
1587 end sparsityIsOwnSubscript;
1588
1589 function sparsityIsOwnCref
1590 "an iterator of this equation or a parameter (x[N])"
1591 input ComponentRef cref;
1592 input UnorderedSet<ComponentRef> own_iters;
1593 output Boolean b = UnorderedSet.contains(cref, own_iters) or not ComponentRef.isIterator(cref);
1594 end sparsityIsOwnCref;
1595
1596 function sparsityAddInner
1597 "sliced inner variables are also added by their name, later equations might use other slices of them.
1598 entries are merged, several components can solve parts of the same variable"
1599 input ComponentRef cref;
1600 input list<ComponentRef> deps;
1601 input UnorderedMap<ComponentRef, list<ComponentRef>> inner_map;
1602 protected
1603 ComponentRef stripped = ComponentRef.stripSubscriptsAll(cref);
1604 algorithm
1605 // several components can solve slices of the same variable with the same cref (e.g. x[$i1])
1606 1758 UnorderedMap.add(cref, UnorderedSet.unique_list(listAppend(deps, UnorderedMap.getOrDefault(cref, inner_map, {})), ComponentRef.hash, ComponentRef.isEqual), inner_map);
1607
2/2
✓ Branch 1 taken 1272 times.
✓ Branch 2 taken 486 times.
1758 if not ComponentRef.isEqual(stripped, cref) then
1608 486 UnorderedMap.add(stripped, UnorderedSet.unique_list(listAppend(deps, UnorderedMap.getOrDefault(stripped, inner_map, {})), ComponentRef.hash, ComponentRef.isEqual), inner_map);
1609 end if;
1610 end sparsityAddInner;
1611
1612 function upgrade
1613 "upgrades a matrix using the information provided by the full matrix"
1614 input output Matrix adj;
1615 input Matrix full;
1616 input UnorderedMap<ComponentRef, Integer> vars_map;
1617 input UnorderedMap<ComponentRef, Integer> eqns_map;
1618 input EquationPointers eqns;
1619 input MatrixStrictness st;
1620 input Iterator iter = Iterator.EMPTY();
1621 algorithm
1622
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3399 times.
3399 if Flags.isSet(Flags.BLT_MATRIX_DUMP) then
1623 ✗ print(StringUtil.headline_1("Upgrading from [" + strictnessString(getStrictness(adj)) + "] to [" + strictnessString(st) +"]") + "\n");
1624 end if;
1625
1626 adj := match full
1627 local
1628 Integer min, max;
1629 IntMatrix.Builder builder;
1630 list<Integer> indices;
1631
1632 ✗ case EMPTY() then EMPTY(st);
1633
1634 case FULL() algorithm
1635 // empty matrices can have a strictness if we want to expand them, in this case ignore and overwrite
1636 // min is the rank the matrix already contains, -1 for an empty one
1637
2/2
✓ Branch 1 taken 1783 times.
✓ Branch 2 taken 1616 times.
3399 if isEmpty(adj) then
1638 min := -1;
1639 1783 adj := initialize(full.mapping, st);
1640 else
1641 1616 min := Solvability.rank(Solvability.fromStrictness(getStrictness(adj)));
1642 end if;
1643 3399 max := Solvability.rank(Solvability.fromStrictness(st));
1644
1645 adj := match adj
1646 local
1647 Matrix result;
1648 list<ComponentRef> filtered;
1649 array<UnorderedSet<ComponentRef>> occ;
1650 array<UnorderedMap<ComponentRef, Dependency>> dep;
1651 array<UnorderedMap<ComponentRef, Solvability>> sol;
1652 array<UnorderedSet<ComponentRef>> rep;
1653
1654 // default case
1655 case FINAL() algorithm
1656 // only do if valid upgrade otherwise create from scratch and issue warning if failtrace is activated
1657
1/2
✓ Branch 0 taken 3397 times.
✗ Branch 1 not taken.
3397 if max == min then
1658 result := adj;
1659 elseif max > min then
1660 3397 (occ, dep, sol, rep) := (full.occurrences, full.dependencies, full.solvabilities, full.repetitions);
1661 3397 indices := UnorderedMap.valueList(eqns_map);
1662 3397 builder := IntMatrix.toBuilder(adj.m, estimateEntries(occ, adj.mapping, indices), true);
1663
2/2
✓ Branch 0 taken 18480 times.
✓ Branch 1 taken 3397 times.
21877 for index in indices loop
1664 18480 filtered := Solvability.filter(UnorderedSet.toList(occ[index]), sol[index], vars_map, min + 1, max);
1665 // upgrade the row and all meta data
1666 18480 upgradeRow(EquationPointers.getEqnAt(eqns, index), index, filtered, dep[index], rep[index], vars_map, vars_map, builder, adj.mapping, adj.modes, iter);
1667 end for;
1668 3397 adj.m := IntMatrix.fromBuilder(builder, IntMatrix.rows(adj.m));
1669
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3397 times.
6794 adj.mT := IntMatrix.transpose(adj.m, arrayLength(adj.mapping.var_StA));
1670 result := adj;
1671 else
1672 ✗ if Flags.isSet(Flags.FAILTRACE) then
1673 ✗ Error.addCompilerWarning("Invalid matrix upgrade request. Cannot upgrade matrix of type "
1674 + Solvability.toString(Solvability.fromStrictness(getStrictness(adj))) + " to type "
1675 + Solvability.toString(Solvability.fromStrictness(st)) + ". The new matrix will be
1676 created from using only the full adjacency matrix.");
1677 end if;
1678 ✗ result := fullToFinal(full, vars_map, eqns_map, eqns, st, iter);
1679 end if;
1680 then result;
1681
1682 // if its still empty even after initializing it, there are no variables or equations
1683 case EMPTY() then adj;
1684
1685 // cannot upgrade a full matrix
1686 case FULL() algorithm
1687 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong matrix type for the 1st input.
1688 Expected: final or empty, Got :" + strictnessString(getStrictness(adj)) + "."});
1689 ✗ then fail();
1690 end match;
1691 then adj;
1692
1693 else algorithm
1694 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong matrix type for the 2nd input.
1695 Expected: full, Got :" + strictnessString(getStrictness(full)) + "."});
1696 ✗ then fail();
1697 end match;
1698
1699
1/2
✓ Branch 1 taken 3399 times.
✗ Branch 2 not taken.
3399 if Flags.isSet(Flags.BLT_MATRIX_DUMP) then
1700 ✗ print(toString(adj, "Final") + "\n");
1701 end if;
1702 end upgrade;
1703
1704 function equalRows
1705 "equation index -> index of the equal equation in seed_eqns, 0 if none.
1706 Its rows in a final matrix over (seed_eqns, seed_vars) are its rows in one
1707 over (eqns, vars), so nothing is shared unless the variables are the same
1708 in the same order."
1709 input EquationPointers seed_eqns;
1710 input VariablePointers seed_vars;
1711 input EquationPointers eqns;
1712 input VariablePointers vars;
1713 output array<Integer> seed_index = arrayCreate(EquationPointers.lastUsedIndex(eqns), 0);
1714 protected
1715 Integer n = VariablePointers.size(vars), i;
1716 Pointer<Equation> seed_eqn;
1717 algorithm
1718
3/6
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
6 if n <> VariablePointers.size(seed_vars) or n <> VariablePointers.lastUsedIndex(vars) or n <> VariablePointers.lastUsedIndex(seed_vars) then return; end if;
1719
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
428 for j in 1:n loop
1720
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 422 times.
422 if not referenceEq(VariablePointers.getVarAt(vars, j), VariablePointers.getVarAt(seed_vars, j)) then return; end if;
1721 end for;
1722
2/2
✓ Branch 1 taken 541 times.
✓ Branch 2 taken 6 times.
547 for eqn in EquationPointers.toList(eqns) loop
1723 541 i := EquationPointers.getEqnIndex(seed_eqns, Equation.getEqnName(eqn));
1724
2/2
✓ Branch 0 taken 539 times.
✓ Branch 1 taken 2 times.
541 if i > 0 then
1725 539 seed_eqn := EquationPointers.getEqnAt(seed_eqns, i);
1726
2/2
✓ Branch 3 taken 526 times.
✓ Branch 4 taken 13 times.
539 if Equation.isEqual(Pointer.access(eqn), Pointer.access(seed_eqn)) then
1727 526 seed_index[EquationPointers.getEqnIndex(eqns, Equation.getEqnName(eqn))] := i;
1728 end if;
1729 end if;
1730 end for;
1731 end equalRows;
1732
1733 function upgradeFrom
1734 "upgrade, taking the rows of equations with a seed_index (see equalRows)
1735 from seed, a final matrix of strictness st that shares its variables"
1736 input output Matrix adj;
1737 input Matrix full;
1738 input UnorderedMap<ComponentRef, Integer> vars_map;
1739 input UnorderedMap<ComponentRef, Integer> eqns_map;
1740 input EquationPointers eqns;
1741 input MatrixStrictness st;
1742 input Matrix seed;
1743 input array<Integer> seed_index;
1744 protected
1745 Integer min, max, rows, eqn_start, eqn_size, seed_start, own_entries = 0, shared_entries = 0;
1746 Boolean fresh = isEmpty(adj);
1747 IntMatrix m, own_m;
1748 IntMatrix.Builder builder;
1749 list<Integer> own = {};
1750 list<ComponentRef> filtered;
1751 array<Integer> data, aux, seed_data, seed_aux;
1752 algorithm
1753 12 max := Solvability.rank(Solvability.fromStrictness(st));
1754
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 min := if fresh then -1 else Solvability.rank(Solvability.fromStrictness(getStrictness(adj)));
1755 adj := match (adj, full, seed)
1756 case (_, FULL(), FINAL()) guard(min < max) algorithm
1757
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if fresh then
1758 6 adj := initialize(full.mapping, st);
1759 end if;
1760 adj := match adj
1761 case FINAL() algorithm
1762
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if fresh then
1763 6 adj.modes := Vector.copy(seed.modes);
1764 end if;
1765 12 rows := IntMatrix.rows(adj.m);
1766
2/2
✓ Branch 1 taken 1082 times.
✓ Branch 2 taken 12 times.
1094 for index in UnorderedMap.valueList(eqns_map) loop
1767 1082 (eqn_start, eqn_size) := adj.mapping.eqn_AtS[index];
1768
2/2
✓ Branch 1 taken 1052 times.
✓ Branch 2 taken 30 times.
1082 if seed_index[index] > 0 then
1769 1052 (seed_start, _) := seed.mapping.eqn_AtS[seed_index[index]];
1770
2/2
✓ Branch 0 taken 970 times.
✓ Branch 1 taken 82 times.
1052 for k in 0:eqn_size - 1 loop
1771 1274 shared_entries := shared_entries + seed.m.len[seed_start + k];
1772 end for;
1773 else
1774 own := index :: own;
1775
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 for k in 0:eqn_size - 1 loop
1776 30 own_entries := own_entries + adj.m.len[eqn_start + k];
1777 end for;
1778 30 own_entries := own_entries + UnorderedSet.size(full.occurrences[index]) * eqn_size;
1779 end if;
1780 end for;
1781 12 own := listReverse(own);
1782
1783 // the own rows are built the way upgrade builds all rows
1784 12 builder := IntMatrix.newBuilder(own_entries, true);
1785 12 data := IntMatrix.entries(adj.m);
1786 12 aux := IntMatrix.payload(adj.m);
1787
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
42 for index in own loop
1788 30 (eqn_start, eqn_size) := adj.mapping.eqn_AtS[index];
1789
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
60 for k in eqn_size - 1:-1:0 loop
1790
2/2
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
63 for p in adj.m.start[eqn_start + k] + adj.m.len[eqn_start + k] - 1:-1:adj.m.start[eqn_start + k] loop
1791
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 IntMatrix.builderAddAux(builder, eqn_start + k, data[p], if arrayLength(aux) > 0 then aux[p] else 0);
1792 end for;
1793 end for;
1794 end for;
1795
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
42 for index in own loop
1796 30 filtered := Solvability.filter(UnorderedSet.toList(full.occurrences[index]), full.solvabilities[index], vars_map, min + 1, max);
1797 30 upgradeRow(EquationPointers.getEqnAt(eqns, index), index, filtered, full.dependencies[index], full.repetitions[index], vars_map, vars_map, builder, adj.mapping, adj.modes);
1798 end for;
1799 12 own_m := IntMatrix.fromBuilder(builder, rows);
1800
1801 12 m := IntMatrix.new(rows);
1802 12 IntMatrix.reserveData(m, shared_entries + IntMatrix.nonZeroCount(own_m), true);
1803 12 data := IntMatrix.entries(own_m);
1804 12 aux := IntMatrix.payload(own_m);
1805 12 seed_data := IntMatrix.entries(seed.m);
1806 12 seed_aux := IntMatrix.payload(seed.m);
1807
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if arrayLength(seed_aux) == 0 then
1808 ✗ seed_aux := arrayCreate(arrayLength(seed_data), 0);
1809 end if;
1810
2/2
✓ Branch 1 taken 1082 times.
✓ Branch 2 taken 12 times.
1094 for index in UnorderedMap.valueList(eqns_map) loop
1811 1082 (eqn_start, eqn_size) := adj.mapping.eqn_AtS[index];
1812
2/2
✓ Branch 1 taken 1052 times.
✓ Branch 2 taken 30 times.
1082 if seed_index[index] > 0 then
1813 1052 (seed_start, _) := seed.mapping.eqn_AtS[seed_index[index]];
1814
2/2
✓ Branch 0 taken 970 times.
✓ Branch 1 taken 82 times.
2326 for k in 0:eqn_size - 1 loop
1815 1274 IntMatrix.copyRow(seed.m, seed_start + k, seed_data, seed_aux, m, eqn_start + k);
1816 end for;
1817 else
1818
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
60 for k in 0:eqn_size - 1 loop
1819 30 IntMatrix.copyRow(own_m, eqn_start + k, data, aux, m, eqn_start + k);
1820 end for;
1821 end if;
1822 end for;
1823 12 adj.m := m;
1824
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
24 adj.mT := IntMatrix.transpose(m, arrayLength(adj.mapping.var_StA));
1825 then adj;
1826 else adj;
1827 end match;
1828 then adj;
1829 ✗ else upgrade(adj, full, vars_map, eqns_map, eqns, st);
1830 end match;
1831 end upgradeFrom;
1832
1833 function expand
1834 "expands the adjacency matrix adj with new information provided by vn and en.
1835 If necessary it also expands the full matrix."
1836 input output Matrix adj "adjancency matrix to be expanded";
1837 input output Matrix full "full matrix having all information";
1838 input UnorderedMap<ComponentRef, Integer> vo, vn "old and new variable index map";
1839 input UnorderedMap<ComponentRef, Integer> eo, en "old and new equation index map";
1840 input VariablePointers vars "all variables, containing new and old";
1841 input EquationPointers eqns "all equations, containing new and old";
1842 input Partition.Kind kind;
1843 protected
1844 Integer size_vo, size_vn, size_eo, size_en; //only for debugging
1845 algorithm
1846
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 479 times.
479 if Flags.isSet(Flags.BLT_MATRIX_DUMP) then
1847 ✗ size_vo := sum(ComponentRef.size(var, true) for var in UnorderedMap.keyList(vo));
1848 ✗ size_vn := sum(ComponentRef.size(var, true) for var in UnorderedMap.keyList(vn)) + size_vo;
1849 ✗ size_eo := sum(ComponentRef.size(eqn, true) for eqn in UnorderedMap.keyList(eo));
1850 ✗ size_en := sum(ComponentRef.size(eqn, true) for eqn in UnorderedMap.keyList(en)) + size_eo;
1851 ✗ print(StringUtil.headline_1("Expanding from size [vars: " + intString(size_vo) + "| eqns: " + intString(size_eo) + "] to [vars: " + intString(size_vn) + "| eqns: " + intString(size_en) + "]") + "\n");
1852 end if;
1853
1854 // check if full has to be expanded
1855 full := match full
1856 case FULL() guard(EquationPointers.size(eqns) > arrayLength(full.equation_names))
1857 28 then expandFull(full, vo, vn, eo, en, vars, eqns, kind);
1858 else full;
1859 end match;
1860
1861 adj := match (adj, full)
1862 local
1863 Matrix new;
1864 Integer rank, max_index_eq, max_index_var, eqn_scalar_size;
1865 list<ComponentRef> filtered;
1866 list<Integer> eo_lst, en_lst;
1867 IntMatrix.Builder builder;
1868 UnorderedMap<ComponentRef, Integer> v = vo;
1869
1870 // if the matrix is empty, initialize it first
1871 case (EMPTY(), FULL()) algorithm
1872 43 new := initialize(full.mapping, adj.st);
1873
2/2
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 2 times.
43 if not isEmpty(new) then
1874 41 new := expand(new, full, vo, vn, eo, en, vars, eqns, kind);
1875 end if;
1876 then new;
1877
1878 // default case
1879 case (FINAL(), FULL()) algorithm
1880 // 0. expand the integer matrix
1881 436 eqn_scalar_size := EquationPointers.scalarSize(eqns, true);
1882 436 adj.mapping := full.mapping;
1883 436 eo_lst := UnorderedMap.valueList(eo);
1884 436 en_lst := UnorderedMap.valueList(en);
1885 436 builder := IntMatrix.toBuilder(adj.m,
1886 estimateEntries(full.occurrences, adj.mapping, eo_lst) + estimateEntries(full.occurrences, adj.mapping, en_lst), true);
1887
1888
1889 // get the strictness ranking
1890 436 rank := Solvability.rank(Solvability.fromStrictness(getStrictness(adj)));
1891 // only merge if there is a second phase
1892
3/4
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 324 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 112 times.
436 if not UnorderedMap.isEmpty(vn) and not UnorderedMap.isEmpty(en) then
1893 ✗ v := UnorderedMap.merge(v, vn, sourceInfo());
1894 end if;
1895
1896 // I. update all old equations with the new variables
1897
2/2
✓ Branch 1 taken 112 times.
✓ Branch 2 taken 324 times.
436 if not UnorderedMap.isEmpty(vn) then
1898
2/2
✓ Branch 0 taken 2291 times.
✓ Branch 1 taken 112 times.
2403 for e in eo_lst loop
1899 2291 filtered := Solvability.filter(UnorderedSet.toList(full.occurrences[e]), full.solvabilities[e], vn, 0, rank);
1900 2291 upgradeRow(EquationPointers.getEqnAt(eqns, e), e, filtered, full.dependencies[e], full.repetitions[e], vn, vars.map, builder, adj.mapping, adj.modes);
1901 end for;
1902 end if;
1903
1904 // II. update new equations with all variables
1905
2/2
✓ Branch 1 taken 202 times.
✓ Branch 2 taken 234 times.
436 if not UnorderedMap.isEmpty(en) then
1906
2/2
✓ Branch 0 taken 3387 times.
✓ Branch 1 taken 202 times.
3589 for e in en_lst loop
1907 3387 filtered := Solvability.filter(UnorderedSet.toList(full.occurrences[e]), full.solvabilities[e], v, 0, rank);
1908 3387 upgradeRow(EquationPointers.getEqnAt(eqns, e), e, filtered, full.dependencies[e], full.repetitions[e], v, vars.map, builder, adj.mapping, adj.modes);
1909 end for;
1910 end if;
1911
1912 // transpose the matrix
1913
3/4
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 395 times.
✓ Branch 4 taken 41 times.
✗ Branch 5 not taken.
436 if UnorderedMap.isEmpty(vo) and UnorderedMap.isEmpty(vn) then
1914 max_index_var := 0;
1915 else
1916
8/8
✓ Branch 1 taken 6072 times.
✓ Branch 2 taken 436 times.
✓ Branch 3 taken 6072 times.
✓ Branch 4 taken 436 times.
✓ Branch 6 taken 490 times.
✓ Branch 7 taken 436 times.
✓ Branch 8 taken 490 times.
✓ Branch 9 taken 436 times.
6998 max_index_var := intMax(max(i for i in UnorderedMap.valueList(vo)), max(i for i in UnorderedMap.valueList(vn)));
1917 end if;
1918 436 adj.m := IntMatrix.fromBuilder(builder, eqn_scalar_size);
1919 436 adj.mT := IntMatrix.transpose(adj.m, VariablePointers.scalarSize(vars, true));
1920 then adj;
1921
1922 // fail cases
1923 case (FINAL(), _) algorithm
1924 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the full matrix expected to contain all information is instead of type "
1925 + strictnessString(getStrictness(full)) + "."});
1926 ✗ then fail();
1927
1928 case (_, FULL()) algorithm
1929 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the matrix to be expanded of type "
1930 + strictnessString(getStrictness(adj)) + " should be of type final."});
1931 ✗ then fail();
1932
1933 else algorithm
1934 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected types final and full, got types " + strictnessString(getStrictness(adj))
1935 + " and " + strictnessString(getStrictness(full)) + "."});
1936 ✗ then fail();
1937 end match;
1938
1939
1/2
✓ Branch 1 taken 479 times.
✗ Branch 2 not taken.
479 if Flags.isSet(Flags.BLT_MATRIX_DUMP) then
1940 ✗ print(toString(adj, "Expanded Final") + "\n");
1941 end if;
1942 end expand;
1943
1944 function expandFull
1945 "usually only called from expand()"
1946 input output Matrix full "full matrix having all information";
1947 input UnorderedMap<ComponentRef, Integer> vo, vn "old and new variable index map";
1948 input UnorderedMap<ComponentRef, Integer> eo, en "old and new equation index map";
1949 input VariablePointers vars "all variables, containing new and old";
1950 input EquationPointers eqns "all equations, containing new and old";
1951 input Partition.Kind kind;
1952 algorithm
1953 full := match full
1954 local
1955 list<Pointer<Variable>> new_vars = list(VariablePointers.getVarAt(vars, idx) for idx in UnorderedMap.valueList(vn));
1956 list<Pointer<Equation>> new_eqns = list(EquationPointers.getEqnAt(eqns, idx) for idx in UnorderedMap.valueList(en));
1957 Integer index, size = EquationPointers.size(eqns);
1958 Pointer<Equation> eqn_ptr;
1959 UnorderedSet<ComponentRef> occ_set;
1960 case FULL() algorithm
1961 // 0. enlargen the arrays
1962 28 full := FULL(Array.expandToSize(size, full.equation_names, ComponentRef.EMPTY()),
1963 Array.expandToSize(size, full.occurrences, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)),
1964 Array.expandToSize(size, full.dependencies, UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual)),
1965 Array.expandToSize(size, full.solvabilities, UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual)),
1966 Array.expandToSize(size, full.repetitions, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)),
1967 Mapping.expand(full.mapping, new_eqns, new_vars));
1968
1969 // I. update all old equations with the new variables
1970
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 if not UnorderedMap.isEmpty(vn) then
1971 ✗ for e in UnorderedMap.valueList(eo) loop
1972 ✗ eqn_ptr := EquationPointers.getEqnAt(eqns, e);
1973 ✗ index := UnorderedMap.getSafe(Equation.getEqnName(eqn_ptr), eqns.map, sourceInfo());
1974 ✗ occ_set := collectDependenciesEquation(Pointer.access(eqn_ptr), kind, vn, full.dependencies[index], full.solvabilities[index], full.repetitions[index]);
1975 ✗ full.occurrences[index] := UnorderedSet.union(full.occurrences[index], occ_set);
1976 end for;
1977 end if;
1978
1979 // II. update new equations with all variables
1980
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 if not UnorderedMap.isEmpty(en) then
1981
2/2
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 28 times.
82 for e in UnorderedMap.valueList(en) loop
1982 54 eqn_ptr := EquationPointers.getEqnAt(eqns, e);
1983 54 index := UnorderedMap.getSafe(Equation.getEqnName(eqn_ptr), eqns.map, sourceInfo());
1984 54 occ_set := collectDependenciesEquation(Pointer.access(eqn_ptr), kind, vars.map, full.dependencies[index], full.solvabilities[index], full.repetitions[index]);
1985 54 full.equation_names[index] := Equation.getEqnName(eqn_ptr);
1986 54 full.occurrences[index] := occ_set;
1987 end for;
1988 end if;
1989 then full;
1990
1991 else algorithm
1992 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected type full, got type " + strictnessString(getStrictness(full)) + "."});
1993 ✗ then fail();
1994 end match;
1995
1996
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 if Flags.isSet(Flags.BLT_MATRIX_DUMP) then
1997 ✗ print(toString(full, "Expanded Full") + "\n");
1998 end if;
1999 end expandFull;
2000
2001 function containsLoopCref
2002 "true if the expression contains a cref of the set, also as an element of an array in the set"
2003 input Expression exp;
2004 input UnorderedSet<ComponentRef> set;
2005 output Boolean b = Expression.fold(exp, function isLoopCref(set = set), false);
2006 end containsLoopCref;
2007
2008 function isLoopCref
2009 input Expression exp;
2010 input output Boolean b;
2011 input UnorderedSet<ComponentRef> set;
2012 algorithm
2013 b := match (b, exp)
2014 case (false, Expression.CREF())
2015
4/4
✓ Branch 1 taken 726 times.
✓ Branch 2 taken 83 times.
✓ Branch 5 taken 34 times.
✓ Branch 6 taken 692 times.
809 then UnorderedSet.contains(exp.cref, set) or UnorderedSet.contains(ComponentRef.stripSubscriptsAll(exp.cref), set);
2016 else b;
2017 end match;
2018 end isLoopCref;
2019
2020 function refine
2021 "refines the solvability kind using differentiation
2022 Note: only updates the solvabilites of the variables and equations from the maps v and e"
2023 input output Matrix full;
2024 input UnorderedMap<Path, Function> funcMap;
2025 input UnorderedMap<ComponentRef, Integer> v "variables to refine";
2026 input UnorderedMap<ComponentRef, Integer> e "equations to refine";
2027 input VariablePointers vars "all variables";
2028 input EquationPointers eqns "all equations";
2029 input UnorderedSet<ComponentRef> vars_set "context variables to determine solvability";
2030 input Boolean init "true if initial";
2031 algorithm
2032 full := match full
2033 local
2034 DifferentiationArguments diffArgs = DifferentiationArguments.default(NBDifferentiate.DifferentiationType.SIMPLE, funcMap);
2035 Pointer<Equation> eqn_ptr;
2036 Expression residual = Expression.EMPTY(Type.REAL()), exp;
2037 Solve.Status status;
2038 Solvability sol;
2039 UnorderedSet<ComponentRef> linear_set, param_set, var_set;
2040 Boolean eqnIsDiscrete, eqnIsIf, eqnHasNoResidual, diffOk;
2041 Option<Expression> residual_opt;
2042
2043 case FULL() algorithm
2044
3/4
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 4 taken 1657 times.
✓ Branch 5 taken 96 times.
1849 for eqn_idx in UnorderedMap.valueArray(e) loop
2045 1657 eqn_ptr := EquationPointers.getEqnAt(eqns, eqn_idx);
2046 // ALGORITHM equations have no simple scalar residual for getResidualExp --
2047 // treat them like discrete equations (solveSimple fallback below) instead of
2048 // crashing, now that NBTearing.mo's initialize can pass them in here.
2049
5/6
✓ Branch 1 taken 1653 times.
✓ Branch 2 taken 4 times.
✓ Branch 4 taken 1653 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 1650 times.
1657 eqnIsDiscrete := Equation.isDiscrete(eqn_ptr) or Equation.isWhenEquation(eqn_ptr) or Equation.isAlgorithm(eqn_ptr);
2050 1657 eqnIsIf := Equation.isIfEquation(eqn_ptr);
2051 1657 eqnHasNoResidual := false;
2052
2/2
✓ Branch 0 taken 1650 times.
✓ Branch 1 taken 7 times.
1657 if not (eqnIsDiscrete or eqnIsIf) then
2053 // e.g. a RECORD_EQUATION whose type has no '+'/'-'/'0' operators (a plain
2054 // Medium ThermodynamicState, for example) can't have a residual built at
2055 // all -- fall back to IMPLICIT below instead of crashing.
2056 1650 residual_opt := Equation.tryGetResidualExp(eqn_ptr);
2057
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1650 times.
✓ Branch 2 taken 1641 times.
✓ Branch 3 taken 9 times.
1650 if isSome(residual_opt) then
2058 1641 SOME(residual) := residual_opt;
2059 else
2060 eqnHasNoResidual := true;
2061 end if;
2062 end if;
2063
3/4
✗ Branch 2 not taken.
✓ Branch 3 taken 1657 times.
✓ Branch 5 taken 4794 times.
✓ Branch 6 taken 1657 times.
8108 for var in UnorderedSet.toArray(full.occurrences[eqn_idx]) loop
2064 // only do something if var is to be refined
2065
2/2
✓ Branch 1 taken 3925 times.
✓ Branch 2 taken 869 times.
4794 if UnorderedMap.contains(var, v) then
2066 // only do something if it is not implicit or unsolvable)
2067 3925 sol := UnorderedMap.getSafe(var, full.solvabilities[eqn_idx], sourceInfo());
2068
2/2
✓ Branch 2 taken 3713 times.
✓ Branch 3 taken 212 times.
3925 if Solvability.rank(sol) < Solvability.rank(Solvability.IMPLICIT()) then
2069 // booleans or (todo: enumerations)
2070
6/6
✓ Branch 0 taken 1805 times.
✓ Branch 1 taken 1908 times.
✓ Branch 3 taken 3703 times.
✓ Branch 4 taken 10 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 3701 times.
5518 if eqnIsDiscrete or not BVariable.checkCref(var, function BVariable.isContinuous(staticAsContinuous = init), sourceInfo()) then
2071 // if the equation or cref type is boolean, it can only be solved if its isolated in the LHS or RHS
2072 // Use solveSimple for this and check if status is EXPLICIT
2073 12 (_, status, _) := Solve.solveSimple(Pointer.access(eqn_ptr), var);
2074
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 sol := if status == NBSolve.Status.EXPLICIT then Solvability.EXPLICIT_LINEAR(NONE(), NONE()) else Solvability.UNSOLVABLE();
2075 elseif eqnIsIf or eqnHasNoResidual then
2076 // TODO more thorough analysis
2077 sol := Solvability.IMPLICIT();
2078 else
2079 // get the residual expression, differentiate and simplify it
2080 3671 diffArgs.diffCref := var;
2081 try
2082 3671 (exp, diffArgs) := Differentiate.differentiateExpressionDump(residual, diffArgs, getInstanceName());
2083 3671 exp := SimplifyExp.simplifyDump(exp, true, getInstanceName());
2084 diffOk := true;
2085 else
2086 // not everything can be differentiated, e.g. functions with function inputs
2087 ✗ exp := residual;
2088 diffOk := false;
2089 end try;
2090
1/2
✓ Branch 0 taken 3671 times.
✗ Branch 1 not taken.
3671 if not diffOk then
2091 sol := Solvability.IMPLICIT();
2092 elseif Expression.isZero(exp) then
2093 sol := Solvability.UNSOLVABLE();
2094 elseif containsLoopCref(exp, vars_set) then
2095 // nonlinear -> unique solution if does not contain the variable itself
2096 // TODO: might still be unique in some cases, even if contains the variable, e.g. `exp(x)`
2097
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 75 times.
159 sol := Solvability.EXPLICIT_NONLINEAR(not Expression.containsCref(exp, var));
2098 else
2099 // linear -> find all contained crefs and split them by kind. remove constants and save params / variables
2100 3554 linear_set := Expression.extractCrefs(exp);
2101 3554 linear_set := UnorderedSet.filterOnFalse(linear_set, function BVariable.checkCref(func = BVariable.isConst, info = sourceInfo()));
2102 3554 (param_set, var_set) := UnorderedSet.splitOnTrue(linear_set, function BVariable.checkCref(func = BVariable.isParamOrConst, info = sourceInfo()));
2103
4/4
✓ Branch 1 taken 473 times.
✓ Branch 2 taken 3081 times.
✓ Branch 5 taken 71 times.
✓ Branch 6 taken 3483 times.
3625 sol := Solvability.EXPLICIT_LINEAR(
2104 pars = if UnorderedSet.isEmpty(param_set) then NONE() else SOME(param_set),
2105 vars = if UnorderedSet.isEmpty(var_set) then NONE() else SOME(var_set));
2106 end if;
2107 end if;
2108 3713 UnorderedMap.add(var, sol, full.solvabilities[eqn_idx]);
2109 end if;
2110 end if;
2111 end for;
2112 end for;
2113 96 then full;
2114 else algorithm
2115 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected type full, got type " + strictnessString(getStrictness(full)) + "."});
2116 ✗ then fail();
2117 end match;
2118
2119
1/2
✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
96 if Flags.isSet(Flags.BLT_MATRIX_DUMP) then
2120 ✗ print(toString(full, "Refined Full") + "\n");
2121 end if;
2122 end refine;
2123
2124 function compress
2125 "use after equations have been removed"
2126 input output Matrix adj;
2127 input output Matrix full;
2128 input EquationPointers eqns;
2129 input VariablePointers vars;
2130 input UnorderedMap<ComponentRef, Integer> old_map;
2131 protected
2132 Integer index_old, index_new, size = EquationPointers.size(eqns);
2133 ComponentRef name;
2134 array<ComponentRef> equation_names;
2135 array<UnorderedSet<ComponentRef>> occurrences;
2136 array<UnorderedMap<ComponentRef, Dependency>> dependencies;
2137 array<UnorderedMap<ComponentRef, Solvability>> solvabilities;
2138 array<UnorderedSet<ComponentRef>> repetitions;
2139 Mapping mapping;
2140 IntMatrix m;
2141 array<Integer> m_data, m_aux;
2142 Integer old_start, old_size, new_start, new_size;
2143 algorithm
2144 (adj, full) := match (adj, full)
2145 local
2146 Matrix new_adj, new_full;
2147 case (FINAL(), FULL()) algorithm
2148 // create the index mapping from scratch
2149 ✗ mapping := Mapping.create(eqns, vars);
2150
2151 // create empty arrays for the structures
2152 ✗ m := IntMatrix.new(arrayLength(mapping.eqn_StA));
2153 ✗ m_data := IntMatrix.entries(adj.m);
2154 ✗ m_aux := IntMatrix.payload(adj.m);
2155 ✗ equation_names := arrayCreate(size, ComponentRef.EMPTY());
2156 ✗ occurrences := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual));
2157 ✗ dependencies := arrayCreate(size, UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual));
2158 ✗ solvabilities := arrayCreate(size, UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual));
2159 ✗ repetitions := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual));
2160 // loop over each equation and copy the corresponding maps and sets
2161 ✗ for eqn_ptr in EquationPointers.toList(eqns) loop
2162 ✗ name := Equation.getEqnName(eqn_ptr);
2163 ✗ index_new := UnorderedMap.getSafe(name, eqns.map, sourceInfo());
2164 ✗ index_old := UnorderedMap.getSafe(name, old_map, sourceInfo());
2165 // create structures for final matrix
2166 ✗ (old_start, old_size) := adj.mapping.eqn_AtS[index_old];
2167 ✗ (new_start, new_size) := mapping.eqn_AtS[index_new];
2168 ✗ if old_size == new_size then
2169 ✗ for i in 0:old_size-1 loop
2170 ✗ IntMatrix.copyRow(adj.m, old_start+i, m_data, m_aux, m, new_start+i);
2171 end for;
2172 else
2173 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " sizes (old: " + intString(old_size) + ", new: "
2174 + intString(new_size) + " do not mach for equation:\n" + Equation.pointerToString(eqn_ptr)});
2175 ✗ fail();
2176 end if;
2177 // create the structures for full matrix
2178 ✗ equation_names[index_new] := name;
2179 ✗ occurrences[index_new] := full.occurrences[index_old];
2180 ✗ dependencies[index_new] := full.dependencies[index_old];
2181 ✗ solvabilities[index_new] := full.solvabilities[index_old];
2182 ✗ repetitions[index_new] := full.repetitions[index_old];
2183 end for;
2184
2185 ✗ new_adj := FINAL(m, IntMatrix.transpose(m, VariablePointers.scalarSize(vars, true)), mapping, adj.modes, adj.st);
2186 ✗ new_full := FULL(equation_names, occurrences, dependencies, solvabilities, repetitions, mapping);
2187 then (new_adj, new_full);
2188
2189 else algorithm
2190 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected types final and full, got types " + strictnessString(getStrictness(adj))
2191 + " and " + strictnessString(getStrictness(full)) + "."});
2192 ✗ then fail();
2193 end match;
2194
2195 ✗ if Flags.isSet(Flags.BLT_MATRIX_DUMP) then
2196 ✗ print(toString(adj, "Compressed Final") + "\n");
2197 ✗ print(toString(full, "Compressed Full") + "\n");
2198 end if;
2199 end compress;
2200
2201 function combine
2202 "for now only combines sparsity matrices as its the only one needed"
2203 input list<Matrix> matrices;
2204 output Matrix result;
2205 protected
2206 list<list<ComponentRef>> equation_names = {};
2207 list<list<Iterator>> equation_iterators = {};
2208 list<list<UnorderedMap<ComponentRef, Dependency>>> dependencies = {};
2209 list<list<UnorderedSet<ComponentRef>>> repetitions = {};
2210 list<list<list<ComponentRef>>> solved_crefs = {};
2211 algorithm
2212
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
6 for matrix in listReverse(matrices) loop
2213 _ := match matrix
2214 case SPARSITY() algorithm
2215 4 equation_names := arrayList(matrix.equation_names) :: equation_names;
2216 4 equation_iterators := arrayList(matrix.equation_iterators) :: equation_iterators;
2217 4 dependencies := arrayList(matrix.dependencies) :: dependencies;
2218 4 repetitions := arrayList(matrix.repetitions) :: repetitions;
2219 4 solved_crefs := arrayList(matrix.solved_crefs) :: solved_crefs;
2220 then ();
2221
2222 else algorithm
2223 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected type sparsity, got type " + strictnessString(getStrictness(matrix)) + "."});
2224 ✗ then fail();
2225 end match;
2226 end for;
2227
2228 // compile the final result
2229 2 result := SPARSITY(
2230 equation_names = listArray(List.flatten(equation_names)),
2231 equation_iterators = listArray(List.flatten(equation_iterators)),
2232 dependencies = listArray(List.flatten(dependencies)),
2233 repetitions = listArray(List.flatten(repetitions)),
2234 solved_crefs = listArray(List.flatten(solved_crefs))
2235 );
2236 end combine;
2237
2238 function toString
2239 input Matrix adj;
2240 input output String str = "";
2241 algorithm
2242 str := match adj
2243 local
2244 list<Type> types;
2245 array<String> solved, names, types_str, complex_sizes;
2246 Integer length0, length1, length2, length3;
2247
2248 case FULL() algorithm
2249 ✗ str := StringUtil.headline_2(str + "FULL Adjacency Matrix") + "\n";
2250 ✗ types := list(ComponentRef.getSubscriptedType(name) for name in adj.equation_names);
2251 ✗ complex_sizes := listArray(list(Util.applyOptionOrDefault(Type.complexSize(ty, true), intString, "0") for ty in types));
2252 ✗ types_str := listArray(list(dimsString(Type.arrayDims(ty)) for ty in types));
2253 ✗ names := listArray(list(ComponentRef.toString(name) for name in adj.equation_names));
2254 ✗ length0 := max(stringLength(sz) for sz in complex_sizes);
2255 ✗ length1 := max(stringLength(ty) for ty in types_str) + 1;
2256 ✗ length2 := max(stringLength(name) for name in names) + 3;
2257 ✗ for i in 1:arrayLength(names) loop
2258 ✗ str := str
2259 + arrayGet(complex_sizes, i) + " " + StringUtil.repeat(" ", length0 - stringLength(arrayGet(complex_sizes, i))) + " | "
2260 + arrayGet(types_str, i) + " " + StringUtil.repeat(".", length1 - stringLength(arrayGet(types_str, i)))
2261 + arrayGet(names, i) + " " + StringUtil.repeat(".", length2 - stringLength(arrayGet(names, i)))
2262 + " " + List.toString(UnorderedSet.toList(adj.occurrences[i]), function fullString(dep_map = adj.dependencies[i],
2263 sol_map = adj.solvabilities[i], rep_set = adj.repetitions[i])) + "\n";
2264 end for;
2265 then str;
2266
2267 case FINAL() algorithm
2268 ✗ str := StringUtil.headline_2(str + "FINAL Adjacency Matrix") + "\n";
2269 ✗ if IntMatrix.rows(adj.m) > 0 then
2270 ✗ str := str + StringUtil.headline_4("Normal Adjacency Matrix (row = equation)");
2271 ✗ str := str + IntMatrix.toString(adj.m);
2272 end if;
2273 ✗ str := str + "\n";
2274 ✗ if IntMatrix.rows(adj.mT) > 0 then
2275 ✗ str := str + StringUtil.headline_4("Transposed Adjacency Matrix (row = variable)");
2276 ✗ str := str + IntMatrix.toString(adj.mT);
2277 end if;
2278 ✗ str := str + "\n" + Mapping.toString(adj.mapping);
2279 then str;
2280
2281 case SPARSITY() algorithm
2282 4 str := StringUtil.headline_2(str + "SPARSITY Adjacency Matrix") + "\n";
2283
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
20 types := list(ComponentRef.getSubscriptedType(name) for name in adj.equation_names);
2284
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4 times.
10 complex_sizes := listArray(list(Util.applyOptionOrDefault(Type.complexSize(ty, true), intString, "0") for ty in types));
2285
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4 times.
10 types_str := listArray(list(dimsString(Type.arrayDims(ty)) for ty in types));
2286
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
20 names := listArray(list(ComponentRef.toString(name) for name in adj.equation_names));
2287
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
20 solved := listArray(list(List.toString(var_list, ComponentRef.toString) for var_list in adj.solved_crefs));
2288
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
10 length0 := max(stringLength(sz) for sz in complex_sizes);
2289
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
10 length1 := max(stringLength(ty) for ty in types_str) + 1;
2290
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
10 length2 := max(stringLength(name) for name in names) + 3;
2291
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
10 length3 := max(stringLength(var) for var in solved) + 3;
2292
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
10 for i in 1:arrayLength(names) loop
2293 6 str := str
2294 + arrayGet(complex_sizes, i) + " " + StringUtil.repeat(" ", length0 - stringLength(arrayGet(complex_sizes, i))) + " | "
2295 + arrayGet(types_str, i) + " " + StringUtil.repeat(".", length1 - stringLength(arrayGet(types_str, i)))
2296 + arrayGet(names, i) + " " + StringUtil.repeat(".", length2 - stringLength(arrayGet(names, i)))
2297 + arrayGet(solved, i) + " " + StringUtil.repeat(".", length3 - stringLength(arrayGet(solved, i)))
2298 + " " + List.toString(UnorderedMap.keyList(adj.dependencies[i]), function sparsityString(dep_map = adj.dependencies[i],
2299 rep_set = adj.repetitions[i])) + "\n";
2300 end for;
2301 then str;
2302
2303 ✗ case EMPTY() then str + StringUtil.headline_4("EMPTY Adjacency Matrix") + "\n";
2304 else algorithm
2305 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unknown adjacency matrix type."});
2306 ✗ then fail();
2307 end match;
2308 end toString;
2309
2310 function solvabilityString
2311 input Matrix adj;
2312 input output String str = "";
2313 algorithm
2314 str := match adj
2315 local
2316 list<ComponentRef> XX, II, NM, NP, LV, LP, LC, QQ;
2317 list<String> xx = {}, ii = {}, nm = {}, np = {}, lv = {}, lp = {}, lc = {}, qq = {};
2318 array<String> names, types, XX_, II_, NM_, NP_, LV_, LP_, LC_, QQ_;
2319 Integer length1, length2, length_xx, length_ii, length_nm, length_np, length_lv, length_lp, length_lc, length_qq;
2320
2321 case FULL() algorithm
2322 ✗ str := StringUtil.headline_2(str + " Solvability Adjacency Matrix") + "\n";
2323 ✗ types := listArray(list(intString(Type.sizeOf(ComponentRef.getSubscriptedType(name), true)) for name in adj.equation_names));
2324 ✗ names := listArray(list(ComponentRef.toString(name) for name in adj.equation_names));
2325 ✗ for i in arrayLength(names):-1:1 loop
2326 ✗ (XX, II, NM, NP, LV, LP, LC, QQ) := Solvability.categorize(UnorderedSet.toList(adj.occurrences[i]), adj.solvabilities[i]);
2327 ✗ xx := List.toStringCustom(XX, ComponentRef.toString, "XX ", "{", ",", "}", false) :: xx;
2328 ✗ ii := List.toStringCustom(II, ComponentRef.toString, "II ", "{", ",", "}", false) :: ii;
2329 ✗ nm := List.toStringCustom(NM, ComponentRef.toString, "N- ", "{", ",", "}", false) :: nm;
2330 ✗ np := List.toStringCustom(NP, ComponentRef.toString, "N+ ", "{", ",", "}", false) :: np;
2331 ✗ lv := List.toStringCustom(LV, ComponentRef.toString, "LV ", "{", ",", "}", false) :: lv;
2332 ✗ lp := List.toStringCustom(LP, ComponentRef.toString, "LP ", "{", ",", "}", false) :: lp;
2333 ✗ lc := List.toStringCustom(LC, ComponentRef.toString, "LC ", "{", ",", "}", false) :: lc;
2334 ✗ qq := List.toStringCustom(QQ, ComponentRef.toString, "|| ", "{", ",", "}", false) :: qq;
2335 end for;
2336 ✗ XX_ := listArray(xx);
2337 ✗ II_ := listArray(ii);
2338 ✗ NM_ := listArray(nm);
2339 ✗ NP_ := listArray(np);
2340 ✗ LV_ := listArray(lv);
2341 ✗ LP_ := listArray(lp);
2342 ✗ LC_ := listArray(lc);
2343 ✗ QQ_ := listArray(qq);
2344 ✗ length1 := max(stringLength(ty) for ty in types) + 1;
2345 ✗ length2 := max(stringLength(name) for name in names) + 3;
2346 ✗ length_xx := max(stringLength(s) for s in XX_);
2347 ✗ length_ii := max(stringLength(s) for s in II_);
2348 ✗ length_nm := max(stringLength(s) for s in NM_);
2349 ✗ length_np := max(stringLength(s) for s in NP_);
2350 ✗ length_lv := max(stringLength(s) for s in LV_);
2351 ✗ length_lp := max(stringLength(s) for s in LP_);
2352 ✗ length_lc := max(stringLength(s) for s in LC_);
2353 ✗ length_qq := max(stringLength(s) for s in QQ_);
2354 ✗ for i in 1:arrayLength(names) loop
2355 ✗ str := str + arrayGet(types, i) + " " + StringUtil.repeat(".", length1 - stringLength(arrayGet(types, i))) + " "
2356 + arrayGet(names, i) + " " + StringUtil.repeat(".", length2 - stringLength(arrayGet(names, i)))
2357 + arrayGet(LC_, i) + " " + StringUtil.repeat(".", length_lc - stringLength(arrayGet(LC_, i)))
2358 + arrayGet(LP_, i) + " " + StringUtil.repeat(".", length_lp - stringLength(arrayGet(LP_, i)))
2359 + arrayGet(LV_, i) + " " + StringUtil.repeat(".", length_lv - stringLength(arrayGet(LV_, i)))
2360 + arrayGet(NP_, i) + " " + StringUtil.repeat(".", length_np - stringLength(arrayGet(NP_, i)))
2361 + arrayGet(NM_, i) + " " + StringUtil.repeat(".", length_nm - stringLength(arrayGet(NM_, i)))
2362 + arrayGet(II_, i) + " " + StringUtil.repeat(".", length_ii - stringLength(arrayGet(II_, i)))
2363 + arrayGet(XX_, i) + " " + StringUtil.repeat(".", length_xx - stringLength(arrayGet(XX_, i)))
2364 + arrayGet(QQ_, i) + " " + StringUtil.repeat(".", length_qq - stringLength(arrayGet(QQ_, i))) + "\n";
2365 end for;
2366 then str;
2367 ✗ else toString(adj, str);
2368 end match;
2369 end solvabilityString;
2370
2371 function dependencyString
2372 input Matrix adj;
2373 input output String str = "";
2374 algorithm
2375 str := match adj
2376 local
2377 list<ComponentRef> F, R, E, A, S, K;
2378 list<String> f = {}, r = {}, e = {}, a = {}, s = {}, k = {};
2379 array<String> names, types, F_, R_, E_, A_, S_, K_;
2380 Integer length1, length2, lengthf, lengthr, lengthe, lengtha, lengths, lengthk;
2381
2382 case FULL() algorithm
2383 ✗ str := StringUtil.headline_2(str + " Dependency Adjacency Matrix") + "\n";
2384 ✗ types := listArray(list(intString(Type.sizeOf(ComponentRef.getSubscriptedType(name), true)) for name in adj.equation_names));
2385 ✗ names := listArray(list(ComponentRef.toString(name) for name in adj.equation_names));
2386 ✗ for i in arrayLength(names):-1:1 loop
2387 ✗ (F, R, E, A, S, K) := Dependency.categorize(UnorderedSet.toList(adj.occurrences[i]), adj.dependencies[i], adj.repetitions[i]);
2388 ✗ f := List.toStringCustom(F, ComponentRef.toString, "[!]", "{", ",", "}", false) :: f;
2389 ✗ r := List.toStringCustom(R, ComponentRef.toString, "[-]", "{", ",", "}", false) :: r;
2390 ✗ e := List.toStringCustom(E, ComponentRef.toString, "[+]", "{", ",", "}", false) :: e;
2391 ✗ a := List.toStringCustom(A, ComponentRef.toString, "[:]", "{", ",", "}", false) :: a;
2392 ✗ s := List.toStringCustom(S, ComponentRef.toString, "[.]", "{", ",", "}", false) :: s;
2393 ✗ k := List.toStringCustom(K, ComponentRef.toString, "[o]", "{", ",", "}", false) :: k;
2394 end for;
2395 ✗ F_ := listArray(f);
2396 ✗ R_ := listArray(r);
2397 ✗ E_ := listArray(e);
2398 ✗ A_ := listArray(a);
2399 ✗ S_ := listArray(s);
2400 ✗ K_ := listArray(k);
2401 ✗ length1 := max(stringLength(ty) for ty in types) + 1;
2402 ✗ length2 := max(stringLength(name) for name in names) + 3;
2403 ✗ lengthf := max(stringLength(st) for st in F_);
2404 ✗ lengthr := max(stringLength(st) for st in R_);
2405 ✗ lengthe := max(stringLength(st) for st in E_);
2406 ✗ lengtha := max(stringLength(st) for st in A_);
2407 ✗ lengths := max(stringLength(st) for st in S_);
2408 ✗ lengthk := max(stringLength(st) for st in K_);
2409 ✗ for i in 1:arrayLength(names) loop
2410 ✗ str := str + arrayGet(types, i) + " " + StringUtil.repeat(".", length1 - stringLength(arrayGet(types, i))) + " "
2411 + arrayGet(names, i) + " " + StringUtil.repeat(".", length2 - stringLength(arrayGet(names, i)))
2412 + arrayGet(K_, i) + " " + StringUtil.repeat(".", lengthk - stringLength(arrayGet(K_, i)))
2413 + arrayGet(S_, i) + " " + StringUtil.repeat(".", lengths - stringLength(arrayGet(S_, i)))
2414 + arrayGet(A_, i) + " " + StringUtil.repeat(".", lengtha - stringLength(arrayGet(A_, i)))
2415 + arrayGet(E_, i) + " " + StringUtil.repeat(".", lengthe - stringLength(arrayGet(E_, i)))
2416 + arrayGet(R_, i) + " " + StringUtil.repeat(".", lengthr - stringLength(arrayGet(R_, i)))
2417 + arrayGet(F_, i) + " " + StringUtil.repeat(".", lengthf - stringLength(arrayGet(F_, i))) + "\n";
2418 end for;
2419 then str;
2420 ✗ else toString(adj, str);
2421 end match;
2422 end dependencyString;
2423
2424 function getStrictness
2425 input Matrix adj;
2426 output MatrixStrictness st;
2427 algorithm
2428 st := match adj
2429 case FULL() then MatrixStrictness.FULL;
2430 2058 case FINAL() then adj.st;
2431 ✗ case EMPTY() then adj.st;
2432 else fail();
2433 end match;
2434 end getStrictness;
2435
2436 function isEmpty
2437 input Matrix adj;
2438 output Boolean b;
2439 algorithm
2440 b := match adj
2441 case EMPTY() then true;
2442 else false;
2443 end match;
2444 end isEmpty;
2445
2446 function getMappingOpt
2447 input Matrix adj;
2448 output Option<Mapping> mapping;
2449 algorithm
2450 mapping := match adj
2451 6 case FULL() then SOME(adj.mapping);
2452 136 case FINAL() then SOME(adj.mapping);
2453 else NONE();
2454 end match;
2455 end getMappingOpt;
2456
2457 function nonZeroCount
2458 input Matrix adj;
2459 output Integer count;
2460 algorithm
2461 count := match adj
2462 ✗ case FINAL() then IntMatrix.nonZeroCount(adj.m);
2463 case EMPTY() then 0;
2464 else algorithm
2465 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unknown matrix type."});
2466 ✗ then fail();
2467 end match;
2468 end nonZeroCount;
2469
2470 protected
2471 function fullString
2472 input ComponentRef cref;
2473 input UnorderedMap<ComponentRef, Dependency> dep_map;
2474 input UnorderedMap<ComponentRef, Solvability> sol_map;
2475 input UnorderedSet<ComponentRef> rep_set;
2476 output String str = ComponentRef.toString(cref) + "[";
2477 algorithm
2478 ✗ str := str + Solvability.toString(UnorderedMap.getSafe(cref, sol_map, sourceInfo()))
2479 + "|" + Dependency.toString(UnorderedMap.getSafe(cref, dep_map, sourceInfo()));
2480 ✗ if UnorderedSet.contains(cref, rep_set) then str := str + "+"; end if;
2481 ✗ str := str + "]";
2482 end fullString;
2483
2484 function sparsityString
2485 input ComponentRef cref;
2486 input UnorderedMap<ComponentRef, Dependency> dep_map;
2487 input UnorderedSet<ComponentRef> rep_set;
2488 output String str = ComponentRef.toString(cref) + "[";
2489 algorithm
2490 5 str := str + Dependency.toString(UnorderedMap.getSafe(cref, dep_map, sourceInfo()));
2491
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if UnorderedSet.contains(cref, rep_set) then str := str + "+"; end if;
2492 5 str := str + "]";
2493 end sparsityString;
2494
2495 function dimsString
2496 input list<Dimension> dims;
2497 output String str;
2498 algorithm
2499 str := match dims
2500 case {} then "{1}";
2501
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
2 else List.toString(list(Dimension.size(d, true) for d in dims), intString);
2502 end match;
2503 end dimsString;
2504
2505 function initialize
2506 input Mapping mapping;
2507 input MatrixStrictness st;
2508 output Matrix adj;
2509 protected
2510 Integer eqn_scalar_size, var_scalar_size;
2511 algorithm
2512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1832 times.
1832 eqn_scalar_size := arrayLength(mapping.eqn_StA);
2513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1832 times.
1832 var_scalar_size := arrayLength(mapping.var_StA);
2514
2/2
✓ Branch 0 taken 1828 times.
✓ Branch 1 taken 4 times.
1832 if eqn_scalar_size > 0 or var_scalar_size > 0 then
2515 1828 adj := FINAL(IntMatrix.new(eqn_scalar_size), IntMatrix.new(var_scalar_size), mapping, Modes.new(), st);
2516 else
2517 4 adj := EMPTY(st);
2518 end if;
2519 end initialize;
2520
2521 function estimateEntries
2522 "estimates how many entries the given equations contribute, to size the builder"
2523 input array<UnorderedSet<ComponentRef>> occ;
2524 input Mapping mapping;
2525 input list<Integer> indices;
2526 output Integer n = 0;
2527 protected
2528 Integer sz;
2529 algorithm
2530
2/2
✓ Branch 0 taken 27325 times.
✓ Branch 1 taken 4269 times.
31594 for i in indices loop
2531 27325 (_, sz) := mapping.eqn_AtS[i];
2532 27325 n := n + UnorderedSet.size(occ[i]) * sz;
2533 end for;
2534 end estimateEntries;
2535
2536 function upgradeRow
2537 input Pointer<Equation> eqn_ptr;
2538 input Integer eqn_arr_idx;
2539 input list<ComponentRef> dependencies "dependent var crefs";
2540 input UnorderedMap<ComponentRef, Dependency> dep "dependency map";
2541 input UnorderedSet<ComponentRef> rep "repetition set";
2542 input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance";
2543 input UnorderedMap<ComponentRef, Integer> fullmap "unordered map to check for general relevance";
2544 input IntMatrix.Builder m;
2545 input Mapping mapping;
2546 input ModeTable modes;
2547 input Iterator iter_ = Iterator.EMPTY();
2548 protected
2549 Integer eqn_scal_idx, eqn_size;
2550 list<Integer> row;
2551 Equation eqn = Pointer.access(eqn_ptr);
2552 Iterator iter = Equation.getForIterator(eqn);
2553 Type ty = Equation.getType(eqn, true);
2554 list<ComponentRef> names;
2555 list<Expression> ranges;
2556 list<Option<Iterator>> maps;
2557 algorithm
2558 try
2559 // don't do this for if equations as soon as we properly split them
2560
4/4
✓ Branch 1 taken 23445 times.
✓ Branch 2 taken 743 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 23441 times.
24188 if Equation.isAlgorithm(eqn_ptr) or Equation.isIfEquation(eqn_ptr) then
2561 // algorithm full dependency
2562 747 (eqn_scal_idx, eqn_size) := mapping.eqn_AtS[eqn_arr_idx];
2563 747 row := Slice.upgradeRowFull(dependencies, map, mapping);
2564
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 600 times.
1065 for i in 0:eqn_size-1 loop
2565 318 IntMatrix.builderAddList(m, eqn_scal_idx+i, row);
2566 end for;
2567 else
2568 // todo: if, when single equation (needs to be updated for if)
2569
2570 // add the optional surrounding iterator frames
2571
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 23435 times.
23441 if not Iterator.isEmpty(iter_) then
2572 6 (names, ranges, maps) := Iterator.getFrames(iter_);
2573 6 iter := Iterator.addFrames(iter, List.zip3(names, ranges, maps));
2574 end if;
2575
2576 23441 Slice.upgradeRow(Equation.getEqnName(eqn_ptr), eqn_arr_idx, iter, ty, dependencies, dep, rep, map, fullmap, m, mapping, modes);
2577 end if;
2578 else
2579 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for:\n" + Equation.pointerToString(eqn_ptr)});
2580 ✗ fail();
2581 end try;
2582 end upgradeRow;
2583
2584 end Matrix;
2585
2586 uniontype Dependency
2587 "the dependency kind to show how a component reference occurs in an equation.
2588 for each dimension there has to be one dependency kind."
2589 type Kind = enumeration(REGULAR, REDUCTION);
2590
2591 record DEPENDENCY
2592 array<list<Integer>> skips;
2593 list<Dependency.Kind> kinds;
2594 end DEPENDENCY;
2595
2596 function toString
2597 input Dependency dep;
2598 output String str;
2599 protected
2600 function kindString
2601 input Kind kind;
2602 output String str;
2603 algorithm
2604 str := match kind
2605 case Kind.REGULAR then ":";
2606 else "-";
2607 end match;
2608 end kindString;
2609 String str1, str2;
2610 algorithm
2611 244 str1 := Array.toString(dep.skips, function List.toString(
2612 inPrintFunc = intString, style = List.Style.FLAT_CURLY), "", "", ", ", "");
2613 244 str2 := List.toString(dep.kinds, kindString, List.Style.FLAT);
2614
2/8
✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 244 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
244 str := if str1 == "" or str2 == "" then str1 + str2 else str1 + ", " + str2;
2615 244 str := "{" + str + "}";
2616 end toString;
2617
2618 function toBoolean
2619 "converts the regular/reduction part of the dependency to a boolean list for scalarization"
2620 input Dependency dep;
2621 output list<Boolean> b = list(not isReductionKind(k) for k in dep.kinds);
2622 end toBoolean;
2623
2624 function create
2625 input Type sub_ty;
2626 input Integer depth;
2627 output Dependency dep;
2628 algorithm
2629
6/6
✓ Branch 2 taken 459 times.
✓ Branch 3 taken 1926 times.
✓ Branch 4 taken 2385 times.
✓ Branch 5 taken 28135 times.
✓ Branch 6 taken 1926 times.
✓ Branch 7 taken 28135 times.
30520 dep := DEPENDENCY(arrayCreate(depth, {}), list(Kind.REGULAR for dim guard(not Dimension.isOne(dim)) in Type.arrayDims(sub_ty)));
2630 end create;
2631
2632 function update
2633 "sets the dependency of num dimensions
2634 REGULAR -> REDUCTION"
2635 input ComponentRef cref;
2636 input Integer num "number of dependencies to turn to reductions. negative means all";
2637 input Boolean reverse "true = from right, false = from left";
2638 input UnorderedMap<ComponentRef, Dependency> map;
2639 protected
2640 Option<Dependency> opt_dep = UnorderedMap.get(cref, map);
2641 Dependency dep;
2642 list<Kind> kinds;
2643 Integer res;
2644
2645 function makeNewKinds
2646 input output list<Kind> kinds;
2647 input output Integer num;
2648 algorithm
2649 (kinds, num) := match (kinds, num)
2650 local
2651 list<Kind> rest;
2652 case (_, 0) then (kinds, num);
2653 case (_::rest, _) algorithm
2654 634 (kinds, num) := makeNewKinds(rest, num-1);
2655 634 then (Kind.REDUCTION :: kinds, num);
2656 else (kinds, num);
2657 end match;
2658 end makeNewKinds;
2659 algorithm
2660
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3156 times.
3156 if isSome(opt_dep) then
2661 3156 SOME(dep) := opt_dep;
2662
2663 // turn to reductions
2664
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 2944 times.
3156 if reverse then
2665 212 (kinds, res) := makeNewKinds(listReverse(dep.kinds), num);
2666 212 dep.kinds := listReverse(kinds);
2667 else
2668 2944 (kinds, res) := makeNewKinds(dep.kinds, num);
2669 2944 dep.kinds := kinds;
2670 end if;
2671
2672 // if any remain, remove from skips
2673
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3144 times.
3156 if res > 0 then
2674 12 removeSkips(cref, map, res, reverse);
2675 end if;
2676
2677 // add the updated dependency back to the map
2678 3156 UnorderedMap.add(cref, dep, map);
2679 else
2680 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because cref "
2681 + ComponentRef.toString(cref) + " was not found in the map."});
2682 ✗ fail();
2683 end if;
2684 end update;
2685
2686 function skip
2687 input ComponentRef cref;
2688 input Integer depth;
2689 input Integer sk;
2690 input UnorderedMap<ComponentRef, Dependency> map;
2691 protected
2692 Option<Dependency> opt_dep = UnorderedMap.get(cref, map);
2693 Dependency dep;
2694 algorithm
2695
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1106 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1106 times.
1106 if isSome(opt_dep) then
2696 1106 SOME(dep) := opt_dep;
2697
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1106 times.
✓ Branch 2 taken 1097 times.
✓ Branch 3 taken 9 times.
2212 if arrayLength(dep.skips) >= depth then
2698 // this might scale badly, try to unique the lists in the end or always use sets here
2699 2194 arrayUpdate(dep.skips, depth, UnorderedSet.unique_list(sk :: dep.skips[depth], Util.id, intEq));
2700 else
2701
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if Flags.isSet(Flags.FAILTRACE) then
2702 ✗ Error.addCompilerWarning(getInstanceName() + ": Cref " + ComponentRef.toString(cref)
2703 + " was saved with depth " + intString(arrayLength(dep.skips)) + " but depth " + intString(depth) + " was requested.");
2704 end if;
2705 end if;
2706
2707 1106 UnorderedMap.add(cref, dep, map);
2708 else
2709 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because cref "
2710 + ComponentRef.toString(cref) + " was not found in the map."});
2711 ✗ fail();
2712 end if;
2713 end skip;
2714
2715 function removeSkips
2716 input ComponentRef cref;
2717 input UnorderedMap<ComponentRef, Dependency> map;
2718 input Integer num = -1 "number of skips to remove. negative implys all";
2719 input Boolean reverse = false "if num > 0 this removes true->from right, false->from left";
2720 protected
2721 Option<Dependency> opt_dep = UnorderedMap.get(cref, map);
2722 Dependency dep;
2723 Integer rest = num;
2724 Integer i, len;
2725 algorithm
2726
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 554 times.
554 if isSome(opt_dep) then
2727 554 SOME(dep) := opt_dep;
2728
2/2
✓ Branch 0 taken 542 times.
✓ Branch 1 taken 12 times.
554 if num < 0 then
2729 // remove all skips
2730
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 542 times.
✓ Branch 2 taken 127 times.
✓ Branch 3 taken 415 times.
1211 for i in 1:arrayLength(dep.skips) loop
2731 127 arrayUpdate(dep.skips, i, {});
2732 end for;
2733 else
2734 // remove specific number
2735
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
12 i := if reverse then arrayLength(dep.skips) else 1;
2736
4/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
20 while rest > 0 and i > 0 and i < arrayLength(dep.skips)+1 loop
2737 4 len := listLength(dep.skips[i]);
2738
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if len <= rest then
2739 // can remove full list
2740 4 arrayUpdate(dep.skips, i, {});
2741 elseif len > 0 then
2742 // list needs to be reduced
2743 ✗ if reverse then
2744 ✗ arrayUpdate(dep.skips, i, List.firstN(dep.skips[i], len - rest));
2745 else
2746 ✗ arrayUpdate(dep.skips, i, List.lastN(dep.skips[i], len - rest));
2747 end if;
2748 end if;
2749 // update rest to remove and move iterator
2750 4 rest := rest - len;
2751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 i := if reverse then i - 1 else i + 1;
2752 end while;
2753 end if;
2754 554 UnorderedMap.add(cref, dep, map);
2755 else
2756 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because cref "
2757 + ComponentRef.toString(cref) + " was not found in the map."});
2758 ✗ fail();
2759 end if;
2760 end removeSkips;
2761
2762 function updateList
2763 input list<ComponentRef> lst;
2764 input Integer num;
2765 input Boolean reverse;
2766 input UnorderedMap<ComponentRef, Dependency> map;
2767 algorithm
2768
2/2
✓ Branch 0 taken 3156 times.
✓ Branch 1 taken 3749 times.
6905 for cref in lst loop
2769 3156 update(cref, num, reverse, map);
2770 end for;
2771 end updateList;
2772
2773 function skipList
2774 input list<ComponentRef> lst;
2775 input Integer depth;
2776 input Integer sk;
2777 input UnorderedMap<ComponentRef, Dependency> map;
2778 algorithm
2779
2/2
✓ Branch 0 taken 659 times.
✓ Branch 1 taken 346 times.
1005 for cref in lst loop
2780 659 skip(cref, depth, sk, map);
2781 end for;
2782 end skipList;
2783
2784 function removeSkipsList
2785 input list<ComponentRef> lst;
2786 input UnorderedMap<ComponentRef, Dependency> map;
2787 algorithm
2788
2/2
✓ Branch 0 taken 542 times.
✓ Branch 1 taken 679 times.
1221 for cref in lst loop
2789 542 removeSkips(cref, map);
2790 end for;
2791 end removeSkipsList;
2792
2793 function addListFull
2794 "adds a list and applies full dependency"
2795 input list<ComponentRef> lst;
2796 input Integer depth;
2797 input UnorderedMap<ComponentRef, Dependency> map;
2798 input UnorderedSet<ComponentRef> rep;
2799 protected
2800 Dependency dep;
2801 algorithm
2802
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 794 times.
1006 for cref in lst loop
2803 212 UnorderedMap.add(cref, create(ComponentRef.getSubscriptedType(cref), depth), map);
2804 212 UnorderedSet.add(cref, rep);
2805 end for;
2806 794 updateList(lst, -1, false, map);
2807 end addListFull;
2808
2809 function isReductionKind
2810 input Dependency.Kind kind;
2811 output Boolean b = kind == Kind.REDUCTION;
2812 end isReductionKind;
2813
2814 function categorize
2815 input list<ComponentRef> crefs;
2816 input UnorderedMap<ComponentRef, Dependency> map;
2817 input UnorderedSet<ComponentRef> rep_set;
2818 output list<ComponentRef> F = {};
2819 output list<ComponentRef> R = {};
2820 output list<ComponentRef> E = {};
2821 output list<ComponentRef> A = {};
2822 output list<ComponentRef> S = {};
2823 output list<ComponentRef> K = {};
2824 protected
2825 Boolean repeats;
2826 algorithm
2827 ✗ for cref in crefs loop
2828 ✗ repeats := UnorderedSet.contains(cref, rep_set);
2829 _ := match UnorderedMap.getSafe(cref, map, sourceInfo())
2830 local
2831 array<list<Integer>> skips;
2832 list<Kind> kinds;
2833 case DEPENDENCY(skips = skips) guard(not Array.all(skips, listEmpty))
2834 algorithm K := cref :: K; then ();
2835 case DEPENDENCY(kinds = {}) guard(repeats)
2836 algorithm E := cref :: E; then ();
2837 case DEPENDENCY(kinds = {})
2838 algorithm S := cref :: S; then ();
2839 case DEPENDENCY(kinds = kinds) algorithm
2840 ✗ if List.any(kinds, isReductionKind) then
2841 ✗ if repeats then
2842 F := cref :: F;
2843 else
2844 R := cref :: R;
2845 end if;
2846 else
2847 A := cref :: A;
2848 end if;
2849 then ();
2850 else ();
2851 end match;
2852 end for;
2853 end categorize;
2854
2855 function convert
2856 input Dependency dep;
2857 output OldSimCode.Dependency odep;
2858 protected
2859 function convertKind
2860 input Kind kind;
2861 output Boolean okind = kind == Kind.REDUCTION;
2862 end convertKind;
2863 algorithm
2864
6/6
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 6121 times.
✓ Branch 2 taken 237 times.
✓ Branch 3 taken 6121 times.
✓ Branch 5 taken 224 times.
✓ Branch 6 taken 13 times.
6595 odep := OldSimCode.DEPENDENCY(dep.skips, list(convertKind(kind) for kind in dep.kinds));
2865 end convert;
2866 end Dependency;
2867
2868 uniontype Solvability
2869 record UNKNOWN end UNKNOWN; // do not set, only used as default if unset
2870 record UNSOLVABLE end UNSOLVABLE;
2871 record IMPLICIT end IMPLICIT;
2872
2873 record EXPLICIT_NONLINEAR
2874 Boolean unique "true if it has a unique solution when solved";
2875 end EXPLICIT_NONLINEAR;
2876
2877 record EXPLICIT_LINEAR
2878 Option<UnorderedSet<ComponentRef>> pars "parameters we need to divide by to solve";
2879 Option<UnorderedSet<ComponentRef>> vars "variables we need to divide by to solve";
2880 end EXPLICIT_LINEAR;
2881
2882 function toString
2883 input Solvability sol;
2884 output String str;
2885 algorithm
2886 str := match sol
2887 case UNSOLVABLE() then "XX";
2888 case IMPLICIT() then "II";
2889 ✗ case EXPLICIT_NONLINEAR() then "N" + (if sol.unique then "+" else "-");
2890 ✗ case EXPLICIT_LINEAR() then "L" + (if isSome(sol.vars) then "V" elseif isSome(sol.pars) then "P" else "C");
2891 case UNKNOWN() then "||";
2892 else algorithm
2893 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unknown solvability kind."});
2894 ✗ then fail();
2895 end match;
2896 end toString;
2897
2898 function rank
2899 input Solvability sol;
2900 output Integer r;
2901 algorithm
2902 r := match sol
2903 case UNSOLVABLE() then 7;
2904 case IMPLICIT() then 6;
2905 case EXPLICIT_NONLINEAR(unique = false) then 5;
2906 case EXPLICIT_NONLINEAR() then 4;
2907 case EXPLICIT_LINEAR(vars = SOME(_)) then 3;
2908 case EXPLICIT_LINEAR(pars = SOME(_)) then 2;
2909 case EXPLICIT_LINEAR() then 1;
2910 case UNKNOWN() then 0;
2911 else algorithm
2912 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unknown solvability kind."});
2913 ✗ then fail();
2914 end match;
2915 end rank;
2916
2917 function update
2918 "sets the solvability of a component reference if it is of
2919 higher rank than previously determined"
2920 input ComponentRef cref;
2921 input Solvability sol;
2922 input UnorderedMap<ComponentRef, Solvability> map;
2923 algorithm
2924
2/2
✓ Branch 4 taken 3095 times.
✓ Branch 5 taken 30235 times.
33330 if rank(sol) > rank(Util.getOptionOrDefault(UnorderedMap.get(cref, map), UNKNOWN())) then
2925 30235 UnorderedMap.add(cref, sol, map);
2926 end if;
2927 end update;
2928
2929 function updateList
2930 input list<ComponentRef> lst;
2931 input Solvability sol;
2932 input UnorderedMap<ComponentRef, Solvability> map;
2933 algorithm
2934
2/2
✓ Branch 0 taken 1425 times.
✓ Branch 1 taken 3861 times.
5286 for cref in lst loop
2935 1425 Solvability.update(cref, sol, map);
2936 end for;
2937 end updateList;
2938
2939 function categorize
2940 input list<ComponentRef> crefs;
2941 input UnorderedMap<ComponentRef, Solvability> map;
2942 output list<ComponentRef> XX = {};
2943 output list<ComponentRef> II = {};
2944 output list<ComponentRef> NM = {};
2945 output list<ComponentRef> NP = {};
2946 output list<ComponentRef> LV = {};
2947 output list<ComponentRef> LP = {};
2948 output list<ComponentRef> LC = {};
2949 output list<ComponentRef> QQ = {};
2950 algorithm
2951 ✗ for cref in crefs loop
2952 _ := match UnorderedMap.getSafe(cref, map, sourceInfo())
2953 case UNSOLVABLE() algorithm XX := cref :: XX; then();
2954 case IMPLICIT() algorithm II := cref :: II; then();
2955 case EXPLICIT_NONLINEAR(unique = false) algorithm NM := cref :: NM; then();
2956 case EXPLICIT_NONLINEAR() algorithm NP := cref :: NP; then();
2957 case EXPLICIT_LINEAR(vars = SOME(_)) algorithm LV := cref :: LV; then();
2958 case EXPLICIT_LINEAR(pars = SOME(_)) algorithm LP := cref :: LP; then();
2959 case EXPLICIT_LINEAR() algorithm LC := cref :: LC; then();
2960 else algorithm QQ := cref :: QQ; then();
2961 end match;
2962 end for;
2963 end categorize;
2964
2965 function filter
2966 "filters the cref list for all relevant crefs (checked with the rel map)
2967 and with solvability ranking between (and including) min and max"
2968 input list<ComponentRef> all_occ;
2969 input UnorderedMap<ComponentRef, Solvability> map;
2970 input UnorderedMap<ComponentRef, Integer> rel "check for relevance";
2971 input Integer min;
2972 input Integer max;
2973 output list<ComponentRef> occ = {};
2974 protected
2975 Integer r;
2976 algorithm
2977
2/2
✓ Branch 0 taken 47556 times.
✓ Branch 1 taken 24188 times.
71744 for cref in all_occ loop
2978
2/2
✓ Branch 1 taken 42287 times.
✓ Branch 2 taken 5269 times.
47556 if UnorderedMap.contains(cref, rel) then
2979 42287 r := rank(UnorderedMap.getSafe(cref, map, sourceInfo()));
2980
2/2
✓ Branch 0 taken 24243 times.
✓ Branch 1 taken 18044 times.
42287 if r >= min and r <= max then
2981 occ := cref :: occ;
2982 end if;
2983 end if;
2984 end for;
2985 end filter;
2986
2987 function fromStrictness
2988 input MatrixStrictness st;
2989 output Solvability sol;
2990 algorithm
2991 sol := match st
2992 120 case MatrixStrictness.LINEAR then EXPLICIT_LINEAR(NONE(), SOME(UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)));
2993 case MatrixStrictness.MATCHING then IMPLICIT();
2994 case MatrixStrictness.SORTING then UNSOLVABLE();
2995 else UNKNOWN();
2996 end match;
2997 end fromStrictness;
2998
2999 function isNonlinearOrImplicit
3000 input Solvability sol;
3001 output Boolean b;
3002 algorithm
3003 b := match sol
3004 case EXPLICIT_NONLINEAR() then true;
3005 case IMPLICIT() then true;
3006 else false;
3007 end match;
3008 end isNonlinearOrImplicit;
3009 end Solvability;
3010
3011 function collectDependenciesEquation
3012 "collects all relevant component references from an equation
3013 furthermore it collects additional data about dependency and solvability."
3014 input Equation eqn;
3015 input Partition.Kind kind;
3016 input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance";
3017 input UnorderedMap<ComponentRef, Dependency> dep_map;
3018 input UnorderedMap<ComponentRef, Solvability> sol_map;
3019 input UnorderedSet<ComponentRef> rep_set;
3020 output UnorderedSet<ComponentRef> occurrences;
3021 protected
3022 list<ComponentRef> inputs, outputs;
3023 algorithm
3024 occurrences := match eqn
3025 local
3026 UnorderedSet<ComponentRef> occ1, occ2;
3027 Equation body;
3028 Slice.filterCref filter;
3029
3030 case Equation.SCALAR_EQUATION() algorithm
3031 12874 occ1 := collectDependencies(eqn.lhs, 0, map, dep_map, sol_map, rep_set);
3032 12874 occ2 := collectDependencies(eqn.rhs, 0, map, dep_map, sol_map, rep_set);
3033 12874 then UnorderedSet.union(occ1, occ2);
3034
3035 case Equation.ARRAY_EQUATION() algorithm
3036 1035 occ1 := collectDependencies(eqn.lhs, 0, map, dep_map, sol_map, rep_set);
3037 1035 occ2 := collectDependencies(eqn.rhs, 0, map, dep_map, sol_map, rep_set);
3038 1035 then UnorderedSet.union(occ1, occ2);
3039
3040 case Equation.RECORD_EQUATION() algorithm
3041 115 occ1 := collectDependencies(eqn.lhs, 0, map, dep_map, sol_map, rep_set);
3042 115 occ2 := collectDependencies(eqn.rhs, 0, map, dep_map, sol_map, rep_set);
3043 115 then UnorderedSet.union(occ1, occ2);
3044
3045 case Equation.ALGORITHM() algorithm
3046 // filter inputs for solvable (not occuring only in conditions)
3047 397 inputs := collectDependenciesAlgorithmInputs(eqn.alg.statements, eqn.alg.inputs);
3048 // collect all crefs expanding potential records
3049
4/4
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 397 times.
✓ Branch 2 taken 111 times.
✓ Branch 3 taken 397 times.
508 inputs := List.flatten(list(collectDependenciesCref(c, 0, map, dep_map, sol_map) for c in inputs));
3050
4/4
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 397 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 397 times.
559 outputs := List.flatten(list(collectDependenciesCref(c, 0, map, dep_map, sol_map) for c in eqn.alg.outputs));
3051 // create dependencies for inputs and outputs
3052 397 Dependency.addListFull(inputs, 0, dep_map, rep_set);
3053 397 Dependency.addListFull(outputs, 0, dep_map, rep_set);
3054 // make inputs unsolvable and outputs solvable (maybe check if algorithm can be reversed)
3055 397 Solvability.updateList(inputs, Solvability.IMPLICIT(), sol_map);
3056 397 Solvability.updateList(outputs, Solvability.EXPLICIT_LINEAR(NONE(), NONE()), sol_map);
3057 397 then UnorderedSet.fromList(listAppend(inputs, outputs), ComponentRef.hash, ComponentRef.isEqual);
3058
3059 case Equation.FOR_EQUATION(body = {body}) algorithm
3060 // gather solvables from body
3061 1442 occ1 := collectDependenciesEquation(body, kind, map, dep_map, sol_map, rep_set);
3062 // gather unsolvables from iterator
3063 1442 occ2 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3064 1442 filter := function Slice.getDependentCref(map = map, pseudo = true);
3065 2884 _ := Iterator.map(eqn.iter, function Slice.filterExp(filter = filter, acc = occ2),
3066 SOME(function filter(acc = occ2)), Expression.mapShallow);
3067 // update unsolvables
3068 1442 Solvability.updateList(UnorderedSet.toList(occ2), Solvability.UNSOLVABLE(), sol_map);
3069 1442 then UnorderedSet.union(occ1, occ2);
3070
3071 case Equation.IF_EQUATION()
3072 10 then collectDependenciesIf(eqn.body, kind, map, dep_map, sol_map, rep_set);
3073
3074 case Equation.WHEN_EQUATION()
3075 75 then collectDependenciesWhen(eqn.body, kind, map, dep_map, sol_map, rep_set);
3076
3077 ✗ else UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3078 end match;
3079 end collectDependenciesEquation;
3080
3081 function collectDependencies
3082 "collects all relevant component references from an expression
3083 furthermore it collects additional data about dependency and solvability."
3084 input Expression exp;
3085 input Integer depth;
3086 input UnorderedMap<ComponentRef, Integer> map "unknowns map to check for relevance";
3087 input UnorderedMap<ComponentRef, Dependency> dep_map;
3088 input UnorderedMap<ComponentRef, Solvability> sol_map;
3089 input UnorderedSet<ComponentRef> rep_set;
3090 output UnorderedSet<ComponentRef> set;
3091 algorithm
3092 set := match exp
3093 local
3094 Dependency dep;
3095 UnorderedSet<ComponentRef> set1, set2, diff;
3096 list<UnorderedSet<ComponentRef>> sets = {};
3097 Expression call_exp;
3098 Call call;
3099 Boolean repeatLeft, repeatRight, reduce;
3100 Integer ind, new_depth;
3101 Boolean isTuple;
3102
3103 // add a cref dependency
3104 38087 case Expression.CREF() then UnorderedSet.fromList(collectDependenciesCref(exp.cref, depth, map, dep_map, sol_map), ComponentRef.hash, ComponentRef.isEqual);
3105
3106 // add skips for arrays
3107 case Expression.ARRAY(literal = false) algorithm
3108
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 146 times.
✓ Branch 2 taken 146 times.
✗ Branch 3 not taken.
632 for i in 1:arrayLength(exp.elements) loop
3109 340 set1 := collectDependencies(exp.elements[i], depth + 1, map, dep_map, sol_map, rep_set);
3110 340 Dependency.skipList(UnorderedSet.toList(set1), depth + 1, i, dep_map);
3111 sets := set1 :: sets;
3112 end for;
3113 146 then UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual);
3114
3115 // add skips for tuples
3116 case Expression.TUPLE() algorithm
3117 ind := 1;
3118
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for elem in exp.elements loop
3119 4 set1 := collectDependencies(elem, depth + 1, map, dep_map, sol_map, rep_set);
3120 4 Dependency.skipList(UnorderedSet.toList(set1), depth + 1, ind, dep_map);
3121 sets := set1 :: sets;
3122 4 ind := ind + 1;
3123 end for;
3124 2 set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual);
3125 then set;
3126
3127 // reduce the dependency and remove skips for these
3128 case Expression.SUBSCRIPTED_EXP() algorithm
3129 146 set := collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set);
3130 146 Dependency.updateList(UnorderedSet.toList(set), listLength(exp.subscripts), true, dep_map);
3131 146 Dependency.removeSkipsList(UnorderedSet.toList(set), dep_map);
3132 // collect dependencies from subscript expressions (e.g. arr[i] depends on i)
3133 // subscript variables are unsolvable (cannot determine i from arr[i] = c)
3134
4/5
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 146 times.
✓ Branch 4 taken 146 times.
292 for sub in exp.subscripts loop
3135 set2 := match sub
3136 137 case Subscript.INDEX() then collectDependencies(sub.index, 0, map, dep_map, sol_map, rep_set);
3137 9 case Subscript.SLICE() then collectDependencies(sub.slice, 0, map, dep_map, sol_map, rep_set);
3138 ✗ else UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3139 end match;
3140 146 Solvability.updateList(UnorderedSet.toList(set2), Solvability.UNSOLVABLE(), sol_map);
3141 146 set := UnorderedSet.union(set, set2);
3142 end for;
3143 then set;
3144
3145 // should not change anything
3146 ✗ case Expression.TUPLE_ELEMENT() then collectDependencies(exp.tupleExp, depth, map, dep_map, sol_map, rep_set);
3147 57 case Expression.RECORD_ELEMENT() then collectDependencies(exp.recordExp, depth, map, dep_map, sol_map, rep_set);
3148
3149 case Expression.BINARY() algorithm
3150 667 set1 := collectDependencies(exp.exp1, depth, map, dep_map, sol_map, rep_set);
3151 667 set2 := collectDependencies(exp.exp2, depth, map, dep_map, sol_map, rep_set);
3152 // add repetitions if needed (.+, .*)
3153 667 (repeatLeft, repeatRight) := Operator.repetition(exp.operator);
3154
2/2
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 503 times.
667 if repeatLeft then addRepetitions(set1, rep_set); end if;
3155
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 509 times.
667 if repeatRight then addRepetitions(set2, rep_set); end if;
3156 // add reductions if needed
3157 667 reduce := Operator.reduction(exp.operator);
3158
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 460 times.
667 if reduce then
3159 207 Dependency.updateList(UnorderedSet.toList(set1), 1, true, dep_map);
3160 207 Dependency.updateList(UnorderedSet.toList(set2), 1, false, dep_map);
3161 // a scalar result has no elements to skip to, e.g. {1, 2} * {x, y}
3162
2/2
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 152 times.
207 if not Type.isArray(Expression.typeOf(exp)) then
3163 55 Dependency.removeSkipsList(UnorderedSet.toList(set1), dep_map);
3164 55 Dependency.removeSkipsList(UnorderedSet.toList(set2), dep_map);
3165 end if;
3166 end if;
3167 667 then UnorderedSet.union(set1, set2);
3168
3169 // mostly equal to binary
3170 case Expression.MULTARY() algorithm
3171 // add repetitions if needed (.+, .*)
3172 11878 (repeatLeft, repeatRight) := Operator.repetition(exp.operator);
3173 11878 repeatLeft := repeatLeft or repeatRight;
3174 // traverse arguments
3175
2/2
✓ Branch 0 taken 21061 times.
✓ Branch 1 taken 11878 times.
32939 for arg in exp.arguments loop
3176 21061 set1 := collectDependencies(arg, depth, map, dep_map, sol_map, rep_set);
3177 // add repetitions if needed
3178 21061 addRepetitionsCond(set1, arg, repeatLeft, rep_set);
3179 sets := set1 :: sets;
3180 end for;
3181 // traverse inverse arguments
3182
2/2
✓ Branch 0 taken 3754 times.
✓ Branch 1 taken 11878 times.
15632 for arg in exp.inv_arguments loop
3183 3754 set2 := collectDependencies(arg, depth, map, dep_map, sol_map, rep_set);
3184 // add repetitions if needed
3185 3754 addRepetitionsCond(set2, arg, repeatLeft, rep_set);
3186 sets := set2 :: sets;
3187 end for;
3188 11878 set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual);
3189 then set;
3190
3191 // cannot solve from lbinary
3192 case Expression.LBINARY() algorithm
3193 158 set1 := collectDependencies(exp.exp1, depth, map, dep_map, sol_map, rep_set);
3194 158 set2 := collectDependencies(exp.exp2, depth, map, dep_map, sol_map, rep_set);
3195 158 set := UnorderedSet.union(set1, set2);
3196 158 Solvability.updateList(UnorderedSet.toList(set), Solvability.UNSOLVABLE(), sol_map);
3197 then set;
3198
3199 // cannot solve from relation
3200 case Expression.RELATION() algorithm
3201 434 set1 := collectDependencies(exp.exp1, depth, map, dep_map, sol_map, rep_set);
3202 434 set2 := collectDependencies(exp.exp2, depth, map, dep_map, sol_map, rep_set);
3203 434 set := UnorderedSet.union(set1, set2);
3204 434 Solvability.updateList(UnorderedSet.toList(set), Solvability.UNSOLVABLE(), sol_map);
3205 then set;
3206
3207 // these don't really change anything, just pass on the argument
3208 151 case Expression.CAST() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set);
3209 ✗ case Expression.BOX() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set);
3210 ✗ case Expression.UNBOX() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set);
3211 622 case Expression.UNARY() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set);
3212 137 case Expression.LUNARY() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set);
3213 ✗ case Expression.MUTABLE() then collectDependencies(Mutable.access(exp.exp), depth, map, dep_map, sol_map, rep_set);
3214
3215 // in the size() operator nothing is solvable
3216 case Expression.SIZE() algorithm
3217 ✗ set := collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set);
3218 ✗ if isSome(exp.dimIndex) then
3219 ✗ set2 := collectDependencies(Util.getOption(exp.dimIndex), depth, map, dep_map, sol_map, rep_set);
3220 ✗ set := UnorderedSet.union(set, set2);
3221 end if;
3222 ✗ Solvability.updateList(UnorderedSet.toList(set), Solvability.UNSOLVABLE(), sol_map);
3223 then set;
3224
3225 // variables in conditions are unsolvable and variables not occuring in both branches are implicit
3226 case Expression.IF() algorithm
3227 277 set1 := collectDependencies(exp.trueBranch, depth, map, dep_map, sol_map, rep_set);
3228 277 set2 := collectDependencies(exp.falseBranch, depth, map, dep_map, sol_map, rep_set);
3229 // variables not occuring in both branches will be tagged implicit
3230 277 diff := UnorderedSet.sym_difference(set1, set2);
3231 277 Solvability.updateList(UnorderedSet.toList(diff), Solvability.IMPLICIT(), sol_map);
3232 // variables in conditions are unsolvable, their skips have to be removed and they can be repeated
3233 277 set := collectDependencies(exp.condition, depth, map, dep_map, sol_map, rep_set);
3234 277 addRepetitions(set, rep_set);
3235 277 updateConditionCrefs(UnorderedSet.toList(set), dep_map, sol_map);
3236 277 then UnorderedSet.union_list({set, set1, set2}, ComponentRef.hash, ComponentRef.isEqual);
3237
3238 // for array constructors replace all iterators (temporarily)
3239 case Expression.CALL(call = call as Call.TYPED_ARRAY_CONSTRUCTOR(exp = call_exp)) algorithm
3240
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 34 times.
68 for iter in call.iters loop
3241 34 call_exp := Expression.replaceIterator(call_exp, Util.tuple21(iter), Util.tuple22(iter));
3242 end for;
3243 // if these are not simplified before this step, they can only be solved implicitely
3244 34 set := collectDependencies(call_exp, depth, map, dep_map, sol_map, rep_set);
3245 34 Solvability.updateList(UnorderedSet.toList(set), Solvability.IMPLICIT(), sol_map);
3246 then set;
3247
3248 // for reductions set the dependency to full reduction
3249 case Expression.CALL(call = call as Call.TYPED_REDUCTION(exp = call_exp)) algorithm
3250
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
50 for iter in call.iters loop
3251 25 call_exp := Expression.replaceIterator(call_exp, Util.tuple21(iter), Util.tuple22(iter));
3252 end for;
3253 25 set := collectDependencies(call_exp, depth, map, dep_map, sol_map, rep_set);
3254 25 Dependency.updateList(UnorderedSet.toList(set), -1, false, dep_map);
3255 then set;
3256
3257 // for functions set the dependency to full reduction (+ repetition) and solvability to implicit
3258 case Expression.CALL(call = call as Call.TYPED_CALL()) algorithm
3259 // add depth if return type is tuple
3260 1939 isTuple := Type.isTuple(call.ty);
3261
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1937 times.
1939 new_depth := if isTuple then depth + 1 else depth;
3262
2/2
✓ Branch 0 taken 3714 times.
✓ Branch 1 taken 1939 times.
5653 for arg in call.arguments loop
3263 3714 sets := collectDependencies(arg, new_depth, map, dep_map, sol_map, rep_set) :: sets;
3264 end for;
3265 1939 set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual);
3266 1939 Dependency.updateList(UnorderedSet.toList(set), -1, false, dep_map);
3267 // discrete arguments cannot be iterated on and no argument can be solved from a
3268 // discrete result (e.g. integer(x)), so they are unsolvable
3269
2/2
✓ Branch 1 taken 2214 times.
✓ Branch 2 taken 1939 times.
4153 for cref in UnorderedSet.toList(set) loop
3270
4/4
✓ Branch 2 taken 2166 times.
✓ Branch 3 taken 48 times.
✓ Branch 6 taken 55 times.
✓ Branch 7 taken 2111 times.
2269 Solvability.update(cref, if not Type.isDiscrete(call.ty) and BVariable.checkCref(cref, function BVariable.isContinuous(staticAsContinuous = true), sourceInfo())
3271 then Solvability.IMPLICIT() else Solvability.UNSOLVABLE(), sol_map);
3272 end for;
3273 1939 addRepetitions(set, rep_set);
3274 // if the return type has to be skipped - add empty skip
3275
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1937 times.
1939 if isTuple then
3276 2 Dependency.skipList(UnorderedSet.toList(set), depth + 1, 0, dep_map);
3277 end if;
3278 then set;
3279
3280 // for not inlined record constructors set the dependency to full reduction (+ repetition) and solvability to implicit
3281 case Expression.RECORD() algorithm
3282
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
24 for arg in exp.elements loop
3283 16 sets := collectDependencies(arg, depth, map, dep_map, sol_map, rep_set) :: sets;
3284 end for;
3285 8 set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual);
3286 8 Dependency.updateList(UnorderedSet.toList(set), -1, false, dep_map);
3287 8 Solvability.updateList(UnorderedSet.toList(set), Solvability.IMPLICIT(), sol_map);
3288 8 addRepetitions(set, rep_set);
3289 then set;
3290
3291 // nothing is solvable from ranges
3292 case Expression.RANGE() algorithm
3293 9 sets := collectDependencies(exp.start, depth, map, dep_map, sol_map, rep_set) :: sets;
3294
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if isSome(exp.step) then
3295 ✗ sets := collectDependencies(Util.getOption(exp.step), depth, map, dep_map, sol_map, rep_set) :: sets;
3296 end if;
3297 9 sets := collectDependencies(exp.stop, depth, map, dep_map, sol_map, rep_set) :: sets;
3298 9 set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual);
3299 9 Solvability.updateList(UnorderedSet.toList(set), Solvability.UNSOLVABLE(), sol_map);
3300 then set;
3301
3302 7243 else UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3303 end match;
3304 end collectDependencies;
3305
3306 function collectDependenciesCref
3307 input ComponentRef cref;
3308 input Integer depth;
3309 input UnorderedMap<ComponentRef, Integer> map "unknowns map to check for relevance";
3310 input UnorderedMap<ComponentRef, Dependency> dep_map;
3311 input UnorderedMap<ComponentRef, Solvability> sol_map;
3312 output list<ComponentRef> crefs;
3313 protected
3314 Pointer<Variable> var;
3315 Integer sk = 1;
3316 list<Subscript> subs;
3317 list<ComponentRef> scalar_matches;
3318 Boolean hasSetSub = false;
3319 algorithm
3320
2/2
✓ Branch 1 taken 15916 times.
✓ Branch 2 taken 38807 times.
54723 for s in ComponentRef.subscriptsAllFlat(cref) loop
3321 // WHOLE (":") and SLICE (e.g. "1:3") are ordinary, common range subscripts
3322 // that the exact-match check below already handles correctly -- only a
3323 // literal/array-valued INDEX subscript (e.g. the "{1, 2}" in i_s[{1, 2}])
3324 // is the set-subscript case this function needs to special-case.
3325
3/4
✓ Branch 1 taken 405 times.
✓ Branch 2 taken 15511 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 405 times.
15916 if not Subscript.isScalar(s) and not Subscript.isSliced(s) then
3326 hasSetSub := true;
3327 end if;
3328 end for;
3329
3330 // a cref with a set/array-valued subscript (e.g. i_s[{1, 2}], produced when a torn
3331 // slice's residual equation keeps its original vector-valued RHS subexpression --
3332 // see NBTearing.scalarSlices) must not go through the ordinary exact-match check
3333 // below: "map" here can use stripped (subscript-ignoring) cref equality
3334 // (VariablePointers' non-scalarized mode), under which i_s[{1, 2}] can spuriously
3335 // "contain"-match some unrelated whole-array entry for the same base variable,
3336 // recording that wrong, un-scalarized cref as the dependency and silently breaking
3337 // the seed/column mapping in fullToSparsity downstream (whose seed set is matched by
3338 // strict, non-stripped equality). Resolve those via their individual scalar elements
3339 // instead, matched strictly against map.
3340
3/4
✓ Branch 0 taken 38807 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 29691 times.
✓ Branch 4 taken 9116 times.
38807 if not hasSetSub and UnorderedMap.contains(cref, map) then
3341
2/2
✓ Branch 1 taken 27923 times.
✓ Branch 2 taken 1768 times.
29691 if not UnorderedMap.contains(cref, dep_map) then
3342 27923 UnorderedMap.add(cref, Dependency.create(ComponentRef.getSubscriptedType(cref), depth), dep_map);
3343 end if;
3344 29691 Solvability.update(cref, Solvability.EXPLICIT_LINEAR(NONE(), NONE()), sol_map);
3345 crefs := {cref};
3346 29691 return;
3347 end if;
3348
3349 // a slice (e.g. i[1:2]) of variables whose elements are the unknowns is resolved via its elements as well
3350
4/6
✓ Branch 0 taken 9116 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 514 times.
✓ Branch 5 taken 8602 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 514 times.
9116 if not hasSetSub and Type.isArray(ComponentRef.getSubscriptedType(cref)) and Type.sizeOf(ComponentRef.getSubscriptedType(cref)) <= 256 then
3351 hasSetSub := true;
3352 end if;
3353
3354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8602 times.
8602 if hasSetSub then
3355
4/6
✓ Branch 2 taken 2686 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2686 times.
✓ Branch 5 taken 514 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 514 times.
3200 scalar_matches := list(c for c guard(UnorderedMap.contains(c, map)) in ComponentRef.scalarize(cref, false));
3356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 514 times.
514 if not listEmpty(scalar_matches) then
3357 ✗ for c in scalar_matches loop
3358 ✗ if not UnorderedMap.contains(c, dep_map) then
3359 ✗ UnorderedMap.add(c, Dependency.create(ComponentRef.getSubscriptedType(c), depth), dep_map);
3360 end if;
3361 ✗ Solvability.update(c, Solvability.EXPLICIT_LINEAR(NONE(), NONE()), sol_map);
3362 end for;
3363 crefs := scalar_matches;
3364 ✗ return;
3365 end if;
3366 end if;
3367
3368 9116 var := BVariable.getVarPointer(cref, sourceInfo());
3369
2/2
✓ Branch 1 taken 239 times.
✓ Branch 2 taken 8877 times.
9116 if BVariable.isRecord(var) then
3370 239 subs := ComponentRef.subscriptsAllFlat(cref);
3371 // get all Record children that are relevant for current context
3372
4/4
✓ Branch 1 taken 572 times.
✓ Branch 2 taken 239 times.
✓ Branch 3 taken 572 times.
✓ Branch 4 taken 239 times.
811 crefs := list(BVariable.getVarName(child) for child in BVariable.getRecordChildren(var));
3373
6/6
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 447 times.
✓ Branch 3 taken 572 times.
✓ Branch 4 taken 239 times.
✓ Branch 5 taken 447 times.
✓ Branch 6 taken 239 times.
811 crefs := list(child for child guard(UnorderedMap.contains(child, map)) in crefs);
3374 // add original subscripts
3375
4/4
✓ Branch 0 taken 447 times.
✓ Branch 1 taken 239 times.
✓ Branch 2 taken 447 times.
✓ Branch 3 taken 239 times.
686 crefs := list(ComponentRef.mergeSubscripts(subs, child) for child in crefs);
3376 // collect dependencies
3377
4/4
✓ Branch 0 taken 447 times.
✓ Branch 1 taken 239 times.
✓ Branch 2 taken 447 times.
✓ Branch 3 taken 239 times.
686 crefs := List.flatten(list(collectDependenciesCref(child, depth + 1, map, dep_map, sol_map) for child in crefs));
3378
2/2
✓ Branch 0 taken 447 times.
✓ Branch 1 taken 239 times.
686 for cref in crefs loop
3379 447 Dependency.skip(cref, depth + 1, sk, dep_map);
3380 447 sk := sk + 1;
3381 end for;
3382 else
3383 crefs := {};
3384 end if;
3385 end collectDependenciesCref;
3386
3387 function addRepetitionsCond
3388 "adds component references from a set to the repetition set,
3389 only if the expression they appear in is of size 1"
3390 input UnorderedSet<ComponentRef> occ;
3391 input Expression exp;
3392 input Boolean isRep;
3393 input UnorderedSet<ComponentRef> rep_set;
3394 algorithm
3395
4/4
✓ Branch 0 taken 24563 times.
✓ Branch 1 taken 252 times.
✓ Branch 4 taken 106 times.
✓ Branch 5 taken 146 times.
24815 if isRep and Type.sizeOf(Expression.typeOf(exp)) == 1 then
3396 146 addRepetitions(occ, rep_set);
3397 end if;
3398 end addRepetitionsCond;
3399
3400 function addRepetitions
3401 "adds component references to the repetition set"
3402 input UnorderedSet<ComponentRef> occ;
3403 input UnorderedSet<ComponentRef> rep_set;
3404 algorithm
3405
2/2
✓ Branch 1 taken 2692 times.
✓ Branch 2 taken 2723 times.
5415 for cref in UnorderedSet.toList(occ) loop
3406 2692 UnorderedSet.add(cref, rep_set);
3407 end for;
3408 end addRepetitions;
3409
3410 function collectDependenciesIf
3411 "collects all relevant component references from an if equation body
3412 furthermore it collects additional data about dependency and solvability.
3413 variables in conditions and variables not contained in all branches are unsolvable"
3414 input IfEquationBody body;
3415 input Partition.Kind kind;
3416 input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance";
3417 input UnorderedMap<ComponentRef, Dependency> dep_map;
3418 input UnorderedMap<ComponentRef, Solvability> sol_map;
3419 input UnorderedSet<ComponentRef> rep_set;
3420 output UnorderedSet<ComponentRef> set;
3421 protected
3422 list<UnorderedSet<ComponentRef>> sets1 = {};
3423 UnorderedSet<ComponentRef> set1, set2, diff;
3424 algorithm
3425 // variables in conditions are unsolvable, repeated and get their skips removed
3426 20 set := collectDependencies(body.condition, 0, map, dep_map, sol_map, rep_set);
3427 20 addRepetitions(set, rep_set);
3428 20 updateConditionCrefs(UnorderedSet.toList(set), dep_map, sol_map);
3429
3430 // get variables from 'then' branch
3431
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 for eqn in body.then_eqns loop
3432 20 sets1 := collectDependenciesEquation(Pointer.access(eqn), kind, map, dep_map, sol_map, rep_set) :: sets1;
3433 end for;
3434
3435 // if there is an 'else' branch, mark those not occuring in both as implicit (maybe it should be unsolvable?)
3436
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 10 times.
20 if isSome(body.else_if) then
3437 10 set1 := UnorderedSet.union_list(sets1, ComponentRef.hash, ComponentRef.isEqual);
3438 10 set2 := collectDependenciesIf(Util.getOption(body.else_if), kind, map, dep_map, sol_map, rep_set);
3439 10 diff := UnorderedSet.sym_difference(set1, set2);
3440 10 Solvability.updateList(UnorderedSet.toList(diff), Solvability.IMPLICIT(), sol_map);
3441 10 set := UnorderedSet.union_list({set, set1, set2}, ComponentRef.hash, ComponentRef.isEqual);
3442 else
3443 10 set := UnorderedSet.union_list(set :: sets1, ComponentRef.hash, ComponentRef.isEqual);
3444 end if;
3445 end collectDependenciesIf;
3446
3447 function collectDependenciesWhen
3448 "collects all relevant component references from a when equation body
3449 furthermore it collects additional data about dependency and solvability.
3450 variables assigned on the left hand side are solvable,
3451 variables from the right hand side (-lhs variables) are unsolvable"
3452 input WhenEquationBody body;
3453 input Partition.Kind kind;
3454 input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance";
3455 input UnorderedMap<ComponentRef, Dependency> dep_map;
3456 input UnorderedMap<ComponentRef, Solvability> sol_map;
3457 input UnorderedSet<ComponentRef> rep_set;
3458 output UnorderedSet<ComponentRef> set;
3459 protected
3460 UnorderedSet<ComponentRef> set1 "solvables";
3461 UnorderedSet<ComponentRef> set2 "potentially unsolvables";
3462 UnorderedSet<ComponentRef> diff "set2 / set1 unsolvables";
3463 list<UnorderedSet<ComponentRef>> lst = {}, lst1, lst2;
3464 list<tuple<UnorderedSet<ComponentRef>, UnorderedSet<ComponentRef>>> tpl_lst = {};
3465 algorithm
3466 // variables in conditions are unsolvable, reduced and get their skips removed
3467 126 set := collectDependencies(body.condition, 0, map, dep_map, sol_map, rep_set);
3468 126 updateConditionCrefs(UnorderedSet.toList(set), dep_map, sol_map);
3469
3470 // make condition repeat if the body is larger than 1
3471
6/6
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 126 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 115 times.
252 if sum(WhenStatement.size(stmt, true) for stmt in body.when_stmts) > 1 then
3472 11 addRepetitions(set, rep_set);
3473 end if;
3474
3475 // collect all dependencies from the statments
3476
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 126 times.
252 for stmt in body.when_stmts loop
3477 126 tpl_lst := collectDependenciesStmt(stmt, map, dep_map, sol_map, rep_set) :: tpl_lst;
3478 end for;
3479
3480 // create the two sets for solvables and potentially unsovables
3481 126 (lst1, lst2) := List.unzip(tpl_lst);
3482 126 set1 := UnorderedSet.union_list(lst1, ComponentRef.hash, ComponentRef.isEqual);
3483 126 set2 := UnorderedSet.union_list(lst2, ComponentRef.hash, ComponentRef.isEqual);
3484
3485 // get the set difference to determine the unsolvables and tag them as such
3486 126 diff := UnorderedSet.difference(set2, set1);
3487 126 Solvability.updateList(UnorderedSet.toList(diff), Solvability.UNSOLVABLE(), sol_map);
3488
3489 // traverse else when if it exists
3490
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 75 times.
126 if isSome(body.else_when) then
3491 51 lst := collectDependenciesWhen(Util.getOption(body.else_when), kind, map, dep_map, sol_map, rep_set) :: lst;
3492 end if;
3493 126 set := UnorderedSet.union_list(set :: set1 :: set2 :: lst, ComponentRef.hash, ComponentRef.isEqual);
3494 end collectDependenciesWhen;
3495
3496 function collectDependenciesStmt
3497 "collects all relevant component references from a when statement
3498 furthermore it collects additional data about dependency and solvability.
3499 Returns a tuple of two sets, one containing the solvables and the other
3500 containing potentially unsolvables"
3501 input WhenStatement stmt;
3502 input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance";
3503 input UnorderedMap<ComponentRef, Dependency> dep_map;
3504 input UnorderedMap<ComponentRef, Solvability> sol_map;
3505 input UnorderedSet<ComponentRef> rep_set;
3506 output tuple<UnorderedSet<ComponentRef>, UnorderedSet<ComponentRef>> set_tpl;
3507 protected
3508 UnorderedSet<ComponentRef> set1 "solvable";
3509 UnorderedSet<ComponentRef> set2 "potentially unsolvable";
3510 algorithm
3511 set_tpl := match stmt
3512 case WhenStatement.ASSIGN() algorithm
3513 126 set1 := collectDependencies(stmt.lhs, 0, map, dep_map, sol_map, rep_set);
3514 126 set2 := collectDependencies(stmt.rhs, 0, map, dep_map, sol_map, rep_set);
3515 126 then (set1, set2);
3516
3517 case WhenStatement.REINIT() algorithm
3518 ✗ set1 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3519 ✗ set2 := collectDependencies(stmt.value, 0, map, dep_map, sol_map, rep_set);
3520 ✗ then (set1, set2);
3521
3522 case WhenStatement.ASSERT() algorithm
3523 ✗ set1 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3524 ✗ set2 := collectDependencies(stmt.condition, 0, map, dep_map, sol_map, rep_set);
3525 ✗ updateConditionCrefs(UnorderedSet.toList(set2), dep_map, sol_map);
3526 ✗ then (set1, set2);
3527
3528 else algorithm
3529 ✗ set1 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3530 ✗ set2 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
3531 ✗ then (set1, set2);
3532 end match;
3533 end collectDependenciesStmt;
3534
3535 function collectDependenciesAlgorithmInputs
3536 "collects dependencies from algorithm inputs.
3537 Only consider inputs that appear outside of when/if conditions"
3538 input list<Statement> stmts;
3539 input output list<ComponentRef> inputs;
3540 protected
3541 UnorderedSet<ComponentRef> candidates = UnorderedSet.fromList(inputs, ComponentRef.hash, ComponentRef.isEqual);
3542 UnorderedSet<ComponentRef> result = UnorderedSet.fromList(inputs, ComponentRef.hash, ComponentRef.isEqual);
3543 algorithm
3544
2/2
✓ Branch 0 taken 493 times.
✓ Branch 1 taken 397 times.
890 for stmt in stmts loop
3545 493 collectDependenciesAlgorithmStatement(stmt, candidates, result);
3546 end for;
3547 397 inputs := UnorderedSet.toList(result);
3548 end collectDependenciesAlgorithmInputs;
3549
3550 function collectDependenciesAlgorithmStatement
3551 input Statement stmt;
3552 input UnorderedSet<ComponentRef> candidates;
3553 input UnorderedSet<ComponentRef> result;
3554 algorithm
3555 _ := match stmt
3556
3557 // actual occurence can only happen here
3558 case Statement.ASSIGNMENT() algorithm
3559 183 Slice.filterExp(stmt.lhs, function Equation.collectFromSet(check_set = candidates), result);
3560 183 Slice.filterExp(stmt.rhs, function Equation.collectFromSet(check_set = candidates), result);
3561 then ();
3562
3563 // map body
3564 case Statement.FOR() algorithm
3565
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 26 times.
54 for s in stmt.body loop
3566 28 collectDependenciesAlgorithmStatement(s, candidates, result);
3567 end for;
3568 then ();
3569
3570 // map body
3571 case Statement.WHILE() algorithm
3572 ✗ for s in stmt.body loop
3573 ✗ collectDependenciesAlgorithmStatement(s, candidates, result);
3574 end for;
3575 then ();
3576
3577 // skip conditions but map body
3578 case Statement.IF() algorithm
3579
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 35 times.
86 for branch in stmt.branches loop
3580
2/2
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 51 times.
126 for s in Util.tuple22(branch) loop
3581 75 collectDependenciesAlgorithmStatement(s, candidates, result);
3582 end for;
3583 end for;
3584 then ();
3585
3586 // skip conditions but map body
3587 case Statement.WHEN() algorithm
3588
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for branch in stmt.branches loop
3589
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 12 times.
28 for s in Util.tuple22(branch) loop
3590 16 collectDependenciesAlgorithmStatement(s, candidates, result);
3591 end for;
3592 end for;
3593 then ();
3594
3595 // all other cases do not produce an occurence
3596 else ();
3597 end match;
3598 end collectDependenciesAlgorithmStatement;
3599
3600 function updateConditionCrefs
3601 "variables in conditions are unsolvable, reduced and get their skips removed"
3602 input list<ComponentRef> crefs;
3603 input UnorderedMap<ComponentRef, Dependency> dep_map;
3604 input UnorderedMap<ComponentRef, Solvability> sol_map;
3605 algorithm
3606 423 Dependency.removeSkipsList(crefs, dep_map);
3607 423 Dependency.updateList(crefs, -1, false, dep_map);
3608 423 Solvability.updateList(crefs, Solvability.UNSOLVABLE(), sol_map);
3609 end updateConditionCrefs;
3610
3611 function addInitialStartOccurrences
3612 "in the initial system start value dependencies must be included.
3613 - x has a start value x.start which is unfixed
3614 - x is iteration variable in an algebraic loop
3615 - the equation for x.start has to be solved before x is used"
3616 input UnorderedSet<ComponentRef> occs;
3617 input UnorderedMap<ComponentRef, Dependency> dep_map;
3618 input UnorderedMap<ComponentRef, Solvability> sol_map;
3619 input UnorderedSet<ComponentRef> rep_set;
3620 input Partition.Kind kind;
3621 algorithm
3622 // only do something if its an initial partition
3623
2/2
✓ Branch 1 taken 9390 times.
✓ Branch 2 taken 5042 times.
14432 if Partition.kindIsInitial(kind) then
3624
2/2
✓ Branch 2 taken 10120 times.
✓ Branch 3 taken 5042 times.
15162 for cref in UnorderedSet.toList(occs) loop
3625 () := match BVariable.getVarStart(BVariable.getVarPointer(cref, sourceInfo()))
3626 local
3627 Pointer<Variable> start;
3628 ComponentRef start_cref;
3629
3630 // only save the x -> x.start dependency not the other way around
3631 case SOME(start) guard(BVariable.isStart(start)) algorithm
3632 571 start_cref := ComponentRef.copySubscripts(cref, BVariable.getVarName(start));
3633 // add the start cref dependency in the same way the original variable occured
3634 // but with UNSOLVABLE as it is only relevant for sorting and cannot be solved
3635 571 UnorderedSet.add(start_cref, occs);
3636 571 UnorderedMap.add(start_cref, UnorderedMap.getSafe(cref, dep_map, sourceInfo()), dep_map);
3637 571 UnorderedMap.add(start_cref, Solvability.UNSOLVABLE(), sol_map);
3638
2/2
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 511 times.
571 if UnorderedSet.contains(cref, rep_set) then
3639 60 UnorderedSet.add(start_cref, rep_set);
3640 end if;
3641 then ();
3642 else ();
3643 end match;
3644 end for;
3645 end if;
3646 end addInitialStartOccurrences;
3647
3648 annotation(__OpenModelica_Interface="nbackend");
3649 end NBAdjacency;
3650