Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 90.2% 268 / 0 / 297
Functions: -% 0 / 1 / 1
Branches: 74.5% 149 / 0 / 200

OMCompiler/Compiler/NFFrontEnd/NFArrayConnections.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package NFArrayConnections
37 import Connection = NFConnection;
38 import Connector = NFConnector;
39 import FlatModel = NFFlatModel;
40 import ComponentRef = NFComponentRef;
41 import Equation = NFEquation;
42 import Connections = NFConnections;
43 import Expression = NFExpression;
44
45 import SBSet;
46 import SBPWLinearMap;
47
48 protected
49 import SBGraph.IncidenceList;
50 import SBGraph.VertexDescriptor;
51 import Array;
52 import Call = NFCall;
53 import Ceval = NFCeval;
54 import Class = NFClass;
55 import NFClassTree.ClassTree;
56 import Component = NFComponent;
57 import DAE;
58 import Dimension = NFDimension;
59 import ElementSource;
60 import MetaModelica.Dangerous.*;
61 import NFInstNode.InstNode;
62 import NFInstNode;
63 import NFPrefixes.ConnectorType;
64 import NFPrefixes.Purity;
65 import NFPrefixes.Variability;
66 import NFBuiltin;
67 import Operator = NFOperator;
68 import Op = NFOperator.Op;
69 import SBFunctions;
70 import SBGraphUtil = NFSBGraphUtil;
71 import SimplifyExp = NFSimplifyExp;
72 import Subscript = NFSubscript;
73 import Type = NFType;
74 import Variable = NFVariable;
75 import UnorderedSet;
76 import UnorderedMap;
77
78 uniontype SetVertex
79 record SET_VERTEX
80 Connector name;
81 SBSet vs;
82 end SET_VERTEX;
83
84 function isEqual
85 input SetVertex v1;
86 input SetVertex v2;
87 output Boolean equal = Connector.isEqual(v1.name, v2.name);
88 end isEqual;
89
90 function toString
91 input SetVertex v;
92 output String str = Connector.toString(v.name) + "\n" + SBSet.toString(v.vs) + "\n";
93 end toString;
94 end SetVertex;
95
96 uniontype SetEdge
97 record SET_EDGE
98 String name;
99 SBPWLinearMap es1;
100 SBPWLinearMap es2;
101 end SET_EDGE;
102
103 function isEqual
104 input SetEdge e1;
105 input SetEdge e2;
106 output Boolean equal = e1.name == e2.name;
107 end isEqual;
108
109 function toString
110 input SetEdge e;
111 output String str = e.name + "\n" + "SetVertex 1:\t" + SBPWLinearMap.toString(e.es1) + "\nSetVertex 2:\t" + SBPWLinearMap.toString(e.es2) + "\n";
112 end toString;
113 end SetEdge;
114
115 public
116 type NameVertexTable = UnorderedMap<String, VertexDescriptor>;
117 type SBGraph = IncidenceList<SetVertex, SetEdge>;
118 type ConnVar = tuple<ComponentRef, Integer, String, Boolean> "variable, dimensions of its connector, path inside the connector, outside connector";
119 type VertexList = list<VertexDescriptor>;
120 type VertexSets = UnorderedMap<SBAtomicSet, VertexDescriptor>;
121
122 function resolve
123 input output FlatModel flatModel;
124 protected
125 Integer max_dim = 1;
126 Vector<Integer> v_count, e_count;
127 list<Equation> conns;
128 list<list<Equation>> eqll = {};
129 SBGraph graph;
130 SBPWLinearMap res;
131 NameVertexTable nmv_table;
132 array<list<VertexDescriptor>> comp_vertices;
133 array<list<Integer>> comp_edges;
134 array<list<ConnVar>> pot_vars, flow_vars;
135 array<InstNode> iterators;
136 list<Expression> iter_expl;
137 algorithm
138
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 3 times.
54 for var in flatModel.variables loop
139 51 max_dim := max(max_dim, Type.dimensionCount(var.ty));
140 end for;
141
142 3 v_count := Vector.newFill(max_dim, 1);
143 3 e_count := Vector.newFill(max_dim, 1);
144
145 3 (flatModel, conns) := collect(flatModel);
146
147 3 graph := IncidenceList.new(SetVertex.isEqual, SetEdge.isEqual, SetVertex.toString, SetEdge.toString);
148 3 nmv_table := UnorderedMap.new<VertexDescriptor>(stringHashDjb2, stringEq);
149 3 createGraph(flatModel.variables, conns, graph, v_count, e_count, nmv_table);
150
151
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if Flags.isSet(Flags.DUMP_SET_BASED_GRAPHS) then
152 ✗ print(IncidenceList.toString(graph));
153 end if;
154
155 3 iterators := arrayCreate(Vector.size(v_count), InstNode.EMPTY_NODE());
156
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
7 for i in 1:arrayLength(iterators) loop
157 4 iterators[i] := InstNode.newUniqueIterator();
158 end for;
159
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 3 times.
14 iter_expl := list(Expression.fromCref(ComponentRef.makeIterator(i, Type.INTEGER())) for i in iterators);
160
161 3 (pot_vars, flow_vars) := vertexVars(flatModel.variables, graph);
162 3 (comp_vertices, comp_edges) := components(graph);
163
164
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
13 for i in 1:arrayLength(comp_vertices) loop
165 10 res := componentMap(comp_vertices[i], comp_edges[i], graph);
166 10 eqll := generateEquations(res, vertexSets(comp_vertices[i], graph), iterators, iter_expl, pot_vars, flow_vars) :: eqll;
167 end for;
168
169
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if Flags.isSet(Flags.DUMP_SET_BASED_GRAPHS) then
170 ✗ print(IncidenceList.toString(graph));
171 end if;
172
173 3 flatModel.equations := listAppend(flatModel.equations, List.flatten(listReverseInPlace(eqll)));
174 end resolve;
175
176 protected
177 function collect
178 input output FlatModel flatModel;
179 output list<Equation> conns = {};
180 protected
181 list<Equation> eql = {};
182 algorithm
183 3 (conns, eql) := List.splitOnTrue(flatModel.equations, isConnection);
184
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 flatModel.equations := eql;
185 end collect;
186
187 function isConnection
188 input Equation eq;
189 output Boolean isConn;
190 algorithm
191 isConn := match eq
192 local
193 Equation e;
194
195 case Equation.CONNECT() then true;
196 14 case Equation.FOR(body = e :: _) then isConnection(e);
197 else false;
198 end match;
199 end isConnection;
200
201 function createGraph
202 input list<Variable> variables;
203 input list<Equation> equations;
204 input SBGraph graph;
205 input Vector<Integer> vCount;
206 input Vector<Integer> eCount;
207 input NameVertexTable nmvTable;
208 algorithm
209 3 addFlowsToGraph(variables, graph, vCount, nmvTable);
210 3 addConnectionsToGraph(equations, graph, vCount, eCount, nmvTable);
211 end createGraph;
212
213 function addFlowsToGraph
214 input list<Variable> variables;
215 input SBGraph graph;
216 input Vector<Integer> vCount;
217 input NameVertexTable nmvTable;
218 protected
219 Connector conn;
220 ComponentRef parent_cr;
221 algorithm
222
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 3 times.
54 for var in variables loop
223
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 30 times.
51 if Variable.isFlow(var) then
224 21 parent_cr := ComponentRef.rest(var.name);
225 21 conn := Connector.fromFacedCref(parent_cr, ComponentRef.nodeType(parent_cr), NFConnector.Face.INSIDE,
226 ElementSource.createElementSource(var.info));
227 21 createVertex(conn, graph, vCount, nmvTable);
228 end if;
229 end for;
230 end addFlowsToGraph;
231
232 function addConnectionsToGraph
233 input list<Equation> equations;
234 input SBGraph graph;
235 input Vector<Integer> vCount;
236 input Vector<Integer> eCount;
237 input NameVertexTable nmvTable;
238 protected
239 Expression range;
240 list<Equation> body;
241 algorithm
242
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 9 times.
30 for eq in equations loop
243 () := match eq
244 case Equation.CONNECT()
245 algorithm
246 15 createConnection(eq.lhs, eq.rhs, eq.source, graph, vCount, eCount, nmvTable);
247 then
248 ();
249
250 case Equation.FOR(range = SOME(range))
251 algorithm
252 6 range := Ceval.evalExp(range, Ceval.EvalTarget.new(Equation.info(eq), NFInstContext.ITERATION_RANGE));
253
254
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if not Type.isEmptyArray(Expression.typeOf(range)) then
255 6 body := Equation.replaceIteratorList(eq.body, eq.iterator, range);
256 6 addConnectionsToGraph(body, graph, vCount, eCount, nmvTable);
257 end if;
258 then
259 ();
260
261 else
262 algorithm
263 ✗ Error.terminate(getInstanceName() + " got unknown equation " +
264 Equation.toString(eq) + "\n", sourceInfo());
265 ✗ then
266 fail();
267 end match;
268 end for;
269 end addConnectionsToGraph;
270
271 function createConnection
272 input Expression lhs;
273 input Expression rhs;
274 input DAE.ElementSource source;
275 input SBGraph graph;
276 input Vector<Integer> vCount;
277 input Vector<Integer> eCount;
278 input NameVertexTable nmvTable;
279 protected
280 ComponentRef lhs_cr, rhs_cr;
281 list<Subscript> lhs_subs, rhs_subs;
282 SBMultiInterval mi1, mi2;
283 VertexDescriptor d1, d2;
284 Connector lhs_conn, rhs_conn;
285 algorithm
286 15 (lhs_cr, lhs_subs) := separate(Expression.toCref(lhs));
287 15 (rhs_cr, rhs_subs) := separate(Expression.toCref(rhs));
288
289 15 lhs_conn := Connector.fromCref(lhs_cr, ComponentRef.nodeType(lhs_cr), source);
290 15 rhs_conn := Connector.fromCref(rhs_cr, ComponentRef.nodeType(rhs_cr), source);
291
292 15 (mi1, d1) := getConnectIntervals(lhs_conn, lhs_subs, graph, vCount, nmvTable);
293 15 (mi2, d2) := getConnectIntervals(rhs_conn, rhs_subs, graph, vCount, nmvTable);
294
295 15 updateGraph(d1, d2, mi1, mi2, graph, eCount);
296 end createConnection;
297
298 function separate
299 input output ComponentRef cref;
300 output list<Subscript> subs;
301 algorithm
302 30 cref := ComponentRef.fillSubscripts(cref);
303 30 cref := ComponentRef.replaceWholeSubscripts(cref);
304 30 subs := ComponentRef.subscriptsAllFlat(cref);
305 30 cref := ComponentRef.stripSubscriptsAll(cref);
306 end separate;
307
308 function getConnectIntervals
309 input Connector conn;
310 input list<Subscript> subs;
311 input SBGraph graph;
312 input Vector<Integer> vCount;
313 input NameVertexTable nmvTable;
314 output SBMultiInterval outMI;
315 output VertexDescriptor d;
316 algorithm
317 30 (outMI, d) := createVertex(conn, graph, vCount, nmvTable);
318 30 outMI := SBGraphUtil.multiIntervalFromSubscripts(subs, vCount, outMI);
319 end getConnectIntervals;
320
321 function createVertex
322 input Connector conn;
323 input SBGraph graph;
324 input Vector<Integer> vCount;
325 input NameVertexTable nmvTable;
326 output SBMultiInterval mi;
327 output VertexDescriptor d;
328 protected
329 Option<VertexDescriptor> od;
330 SetVertex v;
331 list<Dimension> dims;
332 SBSet s;
333 String name;
334 algorithm
335 51 name := Connector.toString(conn) + "$" + Connector.faceString(conn);
336 51 od := UnorderedMap.get(name, nmvTable);
337
338
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 28 times.
51 if isSome(od) then
339 28 SOME(d) := od;
340 28 mi := vertexInterval(IncidenceList.getVertex(graph, d));
341 28 return;
342 end if;
343
344 23 dims := crefDims(Connector.name(conn));
345 23 mi := SBGraphUtil.multiIntervalFromDimensions(dims, vCount);
346
347 23 s := SBSet.newEmpty();
348 23 s := SBSet.addAtomicSet(SBAtomicSet.new(mi), s);
349
350 23 v := SET_VERTEX(conn, s);
351 23 d := IncidenceList.addVertex(graph, v);
352 23 UnorderedMap.addUnique(name, d, nmvTable);
353 end createVertex;
354
355 function vertexInterval
356 input SetVertex v;
357 output SBMultiInterval mi = SBAtomicSet.aset(UnorderedSet.first(SBSet.asets(v.vs)));
358 end vertexInterval;
359
360 function vertexSets
361 input list<VertexDescriptor> vertices;
362 input SBGraph graph;
363 output VertexSets sets = UnorderedMap.new<VertexDescriptor>(SBAtomicSet.hash, SBAtomicSet.isEqual);
364 protected
365 SetVertex v;
366 algorithm
367
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 10 times.
33 for d in vertices loop
368 23 v := IncidenceList.getVertex(graph, d);
369 23 UnorderedMap.add(UnorderedSet.first(SBSet.asets(v.vs)), d, sets);
370 end for;
371 end vertexSets;
372
373 function crefDims
374 input ComponentRef cr;
375 output list<Dimension> dims = {};
376 protected
377 ComponentRef c = cr;
378 algorithm
379
2/2
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 95 times.
315 while not ComponentRef.isEmpty(c) loop
380 220 dims := listAppend(Type.arrayDims(ComponentRef.nodeType(c)), dims);
381 220 c := ComponentRef.rest(c);
382 end while;
383 end crefDims;
384
385 function updateGraph
386 input VertexDescriptor d1;
387 input VertexDescriptor d2;
388 input SBMultiInterval mi1;
389 input SBMultiInterval mi2;
390 input SBGraph graph;
391 input Vector<Integer> eCount;
392 protected
393 SBPWLinearMap pw1, pw2;
394 String name;
395 SetEdge se;
396 algorithm
397 15 (name, pw1, pw2) := SBGraphUtil.linearMapFromIntervals(d1, d2, mi1, mi2, eCount);
398 15 se := SET_EDGE(name, pw1, pw2);
399 15 IncidenceList.addEdge(graph, d1, d2, se);
400 end updateGraph;
401
402 function components
403 "The vertices and edges of each connected component of the graph, ignoring
404 which elements an edge connects."
405 input SBGraph graph;
406 output array<list<VertexDescriptor>> vertices;
407 output array<list<Integer>> edges;
408 protected
409 Integer nv = IncidenceList.vertexCount(graph);
410 Integer ne = IncidenceList.edgeCount(graph);
411 Integer count = 0, r, c;
412 array<Integer> parent = listArray(List.intRange(nv));
413 array<Integer> edge_vertex = arrayCreate(ne, 0);
414 array<Integer> comp = arrayCreate(nv, 0);
415 algorithm
416
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
26 for d in 1:nv loop
417
2/2
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 23 times.
53 for e in IncidenceList.getRow(graph, d) loop
418
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
30 if edge_vertex[e] == 0 then
419 15 edge_vertex[e] := d;
420 else
421 15 joinRoots(parent, d, edge_vertex[e]);
422 end if;
423 end for;
424 end for;
425
426
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
26 for d in 1:nv loop
427 23 r := findRoot(parent, d);
428
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 13 times.
23 if comp[r] == 0 then
429 10 count := count + 1;
430 10 comp[r] := count;
431 end if;
432 end for;
433
434 3 vertices := arrayCreate(count, {});
435 3 edges := arrayCreate(count, {});
436
437
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
26 for d in nv:-1:1 loop
438 23 c := comp[findRoot(parent, d)];
439 46 vertices[c] := d :: vertices[c];
440 end for;
441
442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
18 for e in ne:-1:1 loop
443 15 c := comp[findRoot(parent, edge_vertex[e])];
444 30 edges[c] := e :: edges[c];
445 end for;
446 end components;
447
448 function findRoot
449 input array<Integer> parent;
450 input output Integer i;
451 protected
452 Integer p;
453 algorithm
454
2/2
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 91 times.
124 while parent[i] <> i loop
455 33 p := parent[parent[i]];
456 33 arrayUpdate(parent, i, p);
457 i := p;
458 end while;
459 end findRoot;
460
461 function joinRoots
462 input array<Integer> parent;
463 input Integer i1;
464 input Integer i2;
465 protected
466 Integer r1 = findRoot(parent, i1), r2 = findRoot(parent, i2);
467 algorithm
468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if r1 < r2 then
469 ✗ arrayUpdate(parent, r2, r1);
470 elseif r2 < r1 then
471 13 arrayUpdate(parent, r1, r2);
472 end if;
473 end joinRoots;
474
475 function componentMap
476 "Maps each element of the vertices of a component of the graph to the
477 smallest element it is connected to."
478 input list<VertexDescriptor> vertices;
479 input list<Integer> edges;
480 input SBGraph graph;
481 output SBPWLinearMap res;
482 protected
483 SBSet vss = SBSet.newEmpty();
484 SetVertex v;
485 Boolean scalar = true;
486 SBPWLinearMap emap1, emap2;
487 array<Real> offset;
488 algorithm
489
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 10 times.
33 for d in vertices loop
490 23 v := IncidenceList.getVertex(graph, d);
491 23 vss := SBSet.addAtomicSets(SBSet.asets(v.vs), vss);
492
5/6
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 7 times.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 10 times.
23 scalar := scalar and UnorderedSet.size(SBSet.asets(v.vs)) == 1 and
493 SBMultiInterval.size(vertexInterval(v)) == 1;
494 end for;
495
496
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 9 times.
10 if listEmpty(edges) then
497 1 res := SBPWLinearMap.newIdentity(vss);
498 elseif scalar then
499 3 offset := Array.map(SBSet.minElem(vss), intReal);
500 3 res := SBPWLinearMap.newScalar(vss, SBLinearMap.new(arrayCreate(arrayLength(offset), 0.0), offset));
501 else
502
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 6 times.
18 (emap1, emap2) := createMaps(list(IncidenceList.getEdge(graph, e) for e in edges));
503 6 res := SBFunctions.connectedComponents(vss, emap1, emap2);
504 end if;
505 end componentMap;
506
507 function createMaps
508 input list<SetEdge> edges;
509 output SBPWLinearMap emap1;
510 output SBPWLinearMap emap2;
511 protected
512 SetEdge e;
513 list<SetEdge> es;
514 algorithm
515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 e :: es := edges;
516 6 emap1 := e.es1;
517 6 emap2 := e.es2;
518
519
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for e in es loop
520 6 emap1 := SBPWLinearMap.combine(e.es1, emap1);
521 6 emap2 := SBPWLinearMap.combine(e.es2, emap2);
522 end for;
523 end createMaps;
524
525 function vertexVars
526 "The potential and flow variables of the connector of each vertex, with the
527 number of dimensions of the connector and their path inside it."
528 input list<Variable> variables;
529 input SBGraph graph;
530 output array<list<ConnVar>> potVars;
531 output array<list<ConnVar>> flowVars;
532 protected
533 Integer nv = IncidenceList.vertexCount(graph);
534 UnorderedMap<ComponentRef, VertexList> names;
535 SetVertex v;
536 ComponentRef name;
537 list<VertexDescriptor> candidates;
538 Boolean is_pot;
539 ConnVar cv;
540 algorithm
541 3 potVars := arrayCreate(nv, {});
542 3 flowVars := arrayCreate(nv, {});
543 3 names := UnorderedMap.new<VertexList>(ComponentRef.hashStrip, ComponentRef.isEqualStrip);
544
545
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
26 for d in 1:nv loop
546 23 v := IncidenceList.getVertex(graph, d);
547 23 name := Connector.name(v.name);
548 46 UnorderedMap.add(name, d :: UnorderedMap.getOrDefault(name, names, {}), names);
549 end for;
550
551
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 3 times.
54 for var in variables loop
552 51 is_pot := Variable.isPotential(var);
553
554
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 21 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 9 times.
51 if is_pot or Variable.isFlow(var) then
555 // ComponentRef.isPrefix only matches the variable itself or its parent.
556 42 candidates := UnorderedMap.getOrDefault(var.name, names, {});
557
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 if ComponentRef.isCref(var.name) then
558 42 candidates := listAppend(UnorderedMap.getOrDefault(ComponentRef.rest(var.name), names, {}), candidates);
559 end if;
560
561
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 42 times.
88 for d in candidates loop
562 46 v := IncidenceList.getVertex(graph, d);
563 46 name := Connector.name(v.name);
564
565
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 if ComponentRef.isPrefix(name, var.name) then
566
2/2
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 46 times.
118 for field in recordFields(var.name) loop
567
2/2
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 8 times.
136 cv := (field, listLength(crefDims(name)), memberName(field, name), Connector.isOutside(v.name));
568
569
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
72 if is_pot then
570 72 potVars[d] := cv :: potVars[d];
571 else
572 72 flowVars[d] := cv :: flowVars[d];
573 end if;
574 end for;
575 end if;
576 end for;
577 end if;
578 end for;
579
580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
26 for d in 1:nv loop
581 23 potVars[d] := listReverseInPlace(potVars[d]);
582 23 flowVars[d] := listReverseInPlace(flowVars[d]);
583 end for;
584 end vertexVars;
585
586 function recordFields
587 "The scalar fields of a record variable, or the variable itself if it is
588 not a record."
589 input ComponentRef cref;
590 input output list<ComponentRef> fields = {};
591 protected
592 Type ty = Type.arrayElementType(ComponentRef.nodeType(cref));
593 array<InstNode> comps;
594 Component c;
595 algorithm
596
2/2
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 72 times.
98 if Type.isRecord(ty) then
597 26 comps := ClassTree.getComponents(Class.classTree(InstNode.getClass(Type.complexNode(ty))));
598
599
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
78 for i in arrayLength(comps):-1:1 loop
600 52 c := InstNode.component(comps[i]);
601
602
1/2
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
52 if not ConnectorType.isPotentiallyPresent(Component.connectorType(c)) then
603 52 fields := recordFields(ComponentRef.append(ComponentRef.fromNode(comps[i], Component.getType(c)), cref), fields);
604 end if;
605 end for;
606 else
607 fields := cref :: fields;
608 end if;
609 end recordFields;
610
611 function generateEquations
612 input SBPWLinearMap pw;
613 input VertexSets vertexSets;
614 input array<InstNode> iterators;
615 input list<Expression> iterExps;
616 input array<list<ConnVar>> potVars;
617 input array<list<ConnVar>> flowVars;
618 output list<Equation> equations = {};
619 protected
620 SBSet vc_im, aux_s, vc_domi, vc_domi_aux;
621 list<ConnVar> vars;
622 algorithm
623 10 vc_im := SBPWLinearMap.fullImage(pw);
624
625
2/2
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 10 times.
32 for aset in UnorderedSet.toArray(SBSet.asets(vc_im)) loop
626 12 aux_s := SBSet.newEmpty();
627 12 aux_s := SBSet.addAtomicSet(aset, aux_s);
628 12 vc_domi := SBPWLinearMap.preImage(pw, aux_s);
629 12 vc_domi_aux := SBSet.complement(vc_domi, aux_s);
630 12 vars := getVars(aset, vertexSets, potVars);
631
632 12 equations := generatePotentialEquations(aset, vc_domi_aux, vars, iterators,
633 iterExps, vertexSets, potVars, equations);
634 12 equations := generateFlowEquation(aset, vc_domi, iterators, vertexSets, flowVars, equations);
635 end for;
636
637 10 equations := listReverseInPlace(equations);
638 end generateEquations;
639
640 function intervalToRange
641 input SBInterval interval;
642 output Expression range;
643 protected
644 Integer lo = SBInterval.lowerBound(interval);
645 Integer hi = SBInterval.upperBound(interval);
646 algorithm
647
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 9 times.
34 if lo == hi then
648 25 range := Expression.INTEGER(lo);
649 else
650 9 range := Expression.makeIntegerRange(lo, SBInterval.stepValue(interval), hi);
651 end if;
652 end intervalToRange;
653
654 function generatePotentialEquations
655 input SBAtomicSet aset;
656 input SBSet dom;
657 input list<ConnVar> vars;
658 input array<InstNode> iterators;
659 input list<Expression> iterExps;
660 input VertexSets vertexSets;
661 input array<list<ConnVar>> potVars;
662 input output list<Equation> equations;
663 protected
664 SBMultiInterval mi, mi_range, aux_mi;
665 array<SBInterval> inters;
666 array<Expression> ranges;
667 list<ConnVar> vars1;
668 list<Equation> eql;
669 list<Expression> inds;
670 algorithm
671
2/2
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 12 times.
42 for auxi in UnorderedSet.toArray(SBSet.asets(dom)) loop
672 18 mi := SBAtomicSet.aset(auxi);
673 18 mi_range := applyOffset(mi, getOffset(auxi, vertexSets));
674 18 inters := SBMultiInterval.intervals(mi_range);
675 18 ranges := Array.map(inters, intervalToRange);
676
677 18 vars1 := getVars(auxi, vertexSets, potVars);
678
679 18 mi := SBAtomicSet.aset(aset);
680 18 aux_mi := applyOffset(mi, getOffset(aset, vertexSets));
681 18 inds := transMulti(mi_range, aux_mi, iterators, false);
682
683 18 eql := generatePotentialEquations2(vars1, vars, iterExps, inds);
684 18 equations := generateForLoop(eql, iterators, ranges, equations);
685 end for;
686 end generatePotentialEquations;
687
688 function generatePotentialEquations2
689 input list<ConnVar> vars1;
690 input list<ConnVar> vars2;
691 input list<Expression> inds1;
692 input list<Expression> inds2;
693 output list<Equation> equations = {};
694 protected
695 ComponentRef var1, var2;
696 Integer n1, n2;
697 String m1, m2;
698 Expression l, r;
699 Type ty;
700 Equation eq;
701 algorithm
702
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 18 times.
43 for v1 in vars1 loop
703 25 (var1, n1, m1, _) := v1;
704
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 25 times.
64 for v2 in vars2 loop
705 39 (var2, n2, m2, _) := v2;
706 // the same member of both connectors: a connector can have several
707 // potential variables of the same type (e.g. v and an angle theta)
708 // (the element types: the dimensions of a node can belong to the
709 // connector, e.g. u[3] for an array of input connectors)
710
4/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 25 times.
✓ Branch 4 taken 14 times.
✓ Branch 10 taken 25 times.
✗ Branch 11 not taken.
39 if m1 == m2 and
711 Type.isEqual(Type.arrayElementType(ComponentRef.nodeType(var1)), Type.arrayElementType(ComponentRef.nodeType(var2))) then
712 25 l := generateConnector(var1, inds1, n1);
713 25 r := generateConnector(var2, inds2, n2);
714 25 ty := Expression.typeOf(l);
715
2/4
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
25 if ComponentRef.variability(var1) > Variability.PARAMETER and ComponentRef.variability(var2) > Variability.PARAMETER then
716 25 eq := Equation.makeEquality(l, r, ty, scalarizeMode = NFEquation.ScalarizeMode.DONT_SCALARIZE);
717 else
718 // connected constants and parameters are checked, like the classic connection handler does
719 ✗ eq := makeEqualityAssert(l, r, ty);
720 end if;
721 equations := eq :: equations;
722 end if;
723 end for;
724 end for;
725
726 18 equations := listReverseInPlace(equations);
727 end generatePotentialEquations2;
728
729 function makeEqualityAssert
730 "assert(abs(l - r) <= 0) for Reals, assert(l == r) else; like
731 NFConnectEquations.makeEqualityAssert, for array connections"
732 input Expression l;
733 input Expression r;
734 input Type ty;
735 output Equation eq;
736 protected
737 Type elem_ty = Type.arrayElementType(ty);
738 Expression exp;
739 algorithm
740 ✗ if Type.isArray(ty) then
741 ✗ Error.addInternalError(getInstanceName() + ": connected parameters of array type are not supported with array connections yet: "
742 + Expression.toString(l) + ", " + Expression.toString(r), sourceInfo());
743 ✗ fail();
744 end if;
745 ✗ if Type.isReal(elem_ty) then
746 ✗ exp := Expression.BINARY(l, Operator.makeSub(elem_ty), r);
747 ✗ exp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.ABS_REAL, {exp}, Expression.variability(exp), Purity.PURE));
748 ✗ exp := Expression.RELATION(exp, Operator.makeLessEq(elem_ty), Expression.REAL(0.0), -1);
749 else
750 ✗ exp := Expression.RELATION(l, Operator.makeEqual(elem_ty), r, -1);
751 end if;
752 ✗ eq := Equation.ASSERT(exp, Expression.STRING("Connected constants/parameters must be equal"),
753 NFBuiltin.ASSERTIONLEVEL_ERROR, NFInstNode.NO_SCOPE, DAE.emptyElementSource);
754 end makeEqualityAssert;
755
756 function generateFlowEquation
757 input SBAtomicSet aset;
758 input SBSet dom;
759 input array<InstNode> iterators;
760 input VertexSets vertexSets;
761 input array<list<ConnVar>> flowVars;
762 input output list<Equation> equations;
763 protected
764 SBMultiInterval mi, mi_range, mi_range2;
765 array<SBInterval> inters;
766 array<Expression> ranges;
767 list<Expression> expl, inds;
768 Boolean is_sum, outside;
769 list<ConnVar> vars;
770 ComponentRef var;
771 Integer n;
772 String m;
773 Expression e, sum_exp;
774 Type ty;
775 Equation eq;
776 UnorderedMap<String, ExpList> named_expl = UnorderedMap.new<ExpList>(stringHashDjb2, stringEq) "the terms of each sum, in reverse order";
777 UnorderedSet<String> elementwise = UnorderedSet.new(stringHashDjb2, stringEq);
778 list<tuple<ComponentRef, Integer, String, Boolean, list<Expression>, Boolean>> terms = {};
779 Integer sz;
780 algorithm
781 12 mi := SBAtomicSet.aset(aset);
782 12 mi_range := applyOffset(mi, getOffset(aset, vertexSets));
783 12 inters := SBMultiInterval.intervals(mi_range);
784 12 ranges := Array.map(inters, intervalToRange);
785 expl := {};
786
787 // collect the flow variables of all connectors of the set with their indices
788
2/2
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 12 times.
54 for auxi in UnorderedSet.toArray(SBSet.asets(dom)) loop
789 30 mi := SBAtomicSet.aset(auxi);
790 30 mi_range2 := applyOffset(mi, getOffset(auxi, vertexSets));
791 30 (inds, is_sum) := transMulti(mi_range, mi_range2, iterators, true);
792 30 vars := getVars(auxi, vertexSets, flowVars);
793
794
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 30 times.
73 for v in vars loop
795 43 (var, n, m, outside) := v;
796
4/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 4 times.
122 terms := (var, n, m, outside, inds, is_sum) :: terms;
797 // a flow variable that is an array in its connector (e.g. i[3]) summed
798 // over a range of connectors has to be summed element by element
799
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
43 if is_sum and Type.isArray(ComponentRef.nodeType(var)) then
800 ✗ UnorderedSet.add(m, elementwise);
801 end if;
802 end for;
803 end for;
804
805
2/2
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 12 times.
55 for t in listReverse(terms) loop
806 43 (var, n, m, outside, inds, is_sum) := t;
807
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
43 if UnorderedSet.contains(m, elementwise) then
808 ✗ sz := memberSize(var);
809 ✗ for k in 1:sz loop
810 ✗ e := flowTerm(ComponentRef.setSubscripts({Subscript.INDEX(Expression.INTEGER(k))}, var), inds, n, is_sum, outside);
811 ✗ addNamed(m + "[" + intString(k) + "]", e, named_expl);
812 end for;
813 else
814 43 e := flowTerm(var, inds, n, is_sum, outside);
815 43 addNamed(m, e, named_expl);
816 end if;
817 end for;
818
819 // one sum for each flow variable of the connectors (a connector can have several),
820 // in the order of their first terms
821
2/2
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 12 times.
30 for name in UnorderedMap.keyList(named_expl) loop
822 18 expl := UnorderedMap.getOrFail(name, named_expl);
823
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 sum_exp :: expl := expl;
824
825
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 18 times.
43 while not listEmpty(expl) loop
826 25 e :: expl := expl;
827 25 sum_exp := Expression.BINARY(e, Operator.makeAdd(Expression.typeOf(e)), sum_exp);
828 end while;
829
830 18 ty := Expression.typeOf(sum_exp);
831 18 eq := Equation.makeEquality(sum_exp, Expression.makeZero(ty), ty);
832 18 equations := generateForLoop({eq}, iterators, ranges, equations);
833 end for;
834 end generateFlowEquation;
835
836 function flowTerm
837 "A flow variable of a connector in the flow equation of its set, summed if a
838 range of connectors is connected to one."
839 input ComponentRef var;
840 input list<Expression> inds;
841 input Integer connectorDims;
842 input Boolean isSum;
843 input Boolean outside;
844 output Expression e;
845 algorithm
846 43 e := generateConnector(var, inds, connectorDims);
847
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
43 if isSum then
848
2/4
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
3 if Type.isArray(Expression.typeOf(e)) and Type.dimensionCount(Expression.typeOf(e)) > 1 then
849 ✗ Error.addInternalError(getInstanceName() + ": the flow variable " + ComponentRef.toString(var) +
850 " has several dimensions inside its connector, connecting a range of such connectors to one is not supported yet.", sourceInfo());
851 ✗ fail();
852 end if;
853 6 e := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.SUM,
854 {e}, Expression.variability(e), Purity.PURE, Type.arrayElementType(Expression.typeOf(e))));
855 end if;
856
857
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 4 times.
43 if outside then
858 4 e := Expression.negate(e);
859 end if;
860 end flowTerm;
861
862 function memberSize
863 "The size of a flow variable that is a vector in its connector."
864 input ComponentRef var;
865 output Integer sz;
866 protected
867 list<Dimension> dims = Type.arrayDims(ComponentRef.nodeType(var));
868 algorithm
869 ✗ if listLength(dims) <> 1 or not Dimension.isKnown(listHead(dims)) then
870 ✗ Error.addInternalError(getInstanceName() + ": the flow variable " + ComponentRef.toString(var) +
871 " has to be a vector of known size inside its connector to connect a range of connectors to one.", sourceInfo());
872 ✗ fail();
873 end if;
874 ✗ sz := Dimension.size(listHead(dims));
875 end memberSize;
876
877 type ExpList = list<Expression>;
878
879 function addNamed
880 "adds a term to the sum of the flow variable name"
881 input String name;
882 input Expression e;
883 input UnorderedMap<String, ExpList> namedExpl;
884 algorithm
885 43 UnorderedMap.addUpdate(name, function prependTerm(e = e), namedExpl);
886 end addNamed;
887
888 function prependTerm
889 input Option<list<Expression>> old;
890 input Expression e;
891 output list<Expression> res = e :: Util.getOptionOrDefault(old, {});
892 end prependTerm;
893
894 function generateConnector
895 "The variable of a connector, subscripted with the indices of the connector.
896 Dimensions of the variable inside the connector (e.g. v[3] in the connector)
897 stay whole."
898 input ComponentRef cr;
899 input list<Expression> indices;
900 input Integer connectorDims "the number of dimensions of the connector";
901 output Expression outExp;
902 protected
903 list<Subscript> subs;
904 algorithm
905 93 outExp := Expression.fromCref(cr);
906
907
3/4
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 47 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 47 times.
93 if Type.isArray(Expression.typeOf(outExp)) and connectorDims > 0 then
908
4/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 47 times.
✓ Branch 2 taken 55 times.
✓ Branch 3 taken 47 times.
102 subs := list(Subscript.fromTypedExp(i) for i in indices);
909 47 subs := List.firstN(subs, intMin(connectorDims, Type.dimensionCount(Expression.typeOf(outExp))));
910 47 outExp := Expression.applySubscripts(subs, outExp);
911 end if;
912 end generateConnector;
913
914 function generateForLoop
915 input list<Equation> connects;
916 input array<InstNode> iterators;
917 input array<Expression> ranges;
918 input output list<Equation> equations;
919 protected
920 list<Equation> body = connects;
921 algorithm
922
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
76 for i in arrayLength(iterators):-1:1 loop
923
2/2
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 11 times.
40 if Expression.isInteger(ranges[i]) then
924 // Scalar range means the interval had the same lower and upper bound,
925 // in which case the iterator can be replaced with the scalar expression
926 // instead of creating an unnecessary for loop here.
927 29 body := Equation.replaceIteratorList(body, iterators[i], ranges[i]);
928 else
929 22 body := {Equation.FOR(iterators[i], SOME(ranges[i]), body, NFInstNode.NO_SCOPE, DAE.emptyElementSource)};
930 end if;
931 end for;
932
933 36 equations := List.append_reverse(body, equations);
934 end generateForLoop;
935
936 function getOffset
937 "The smallest element of the vertex containing aset."
938 input SBAtomicSet aset;
939 input VertexSets vertexSets;
940 output array<Integer> res = listArray({});
941 protected
942 SBAtomicSet vset;
943 algorithm
944
2/2
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 30 times.
78 if UnorderedMap.contains(aset, vertexSets) then
945 48 res := SBAtomicSet.minElem(aset);
946 48 return;
947 end if;
948
949
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
64 for i in 1:UnorderedMap.size(vertexSets) loop
950 64 vset := UnorderedMap.keyAt(vertexSets, i);
951
952
2/2
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 34 times.
64 if not SBAtomicSet.isEmpty(SBAtomicSet.intersection(aset, vset)) then
953 30 res := SBAtomicSet.minElem(vset);
954 30 return;
955 end if;
956 end for;
957 end getOffset;
958
959 function applyOffset
960 input SBMultiInterval mi;
961 input array<Integer> off;
962 output SBMultiInterval outMI;
963 protected
964 array<SBInterval> ints, res;
965 SBInterval i;
966 Integer o;
967 algorithm
968
2/4
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 78 times.
156 if SBMultiInterval.ndim(mi) <> arrayLength(off) or arrayEmpty(off) then
969 ✗ outMI := SBMultiInterval.newEmpty();
970 else
971 78 ints := SBMultiInterval.intervals(mi);
972 78 res := arrayCreateNoInit(arrayLength(ints), ints[1]);
973
974
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
167 for j in 1:arrayLength(ints) loop
975 89 i := ints[j];
976 89 o := off[j];
977 89 res[j] := SBInterval.new(SBInterval.lowerBound(i) - o + 1,
978 SBInterval.stepValue(i),
979 SBInterval.upperBound(i) - o + 1);
980 end for;
981
982 78 outMI := SBMultiInterval.fromArray(res);
983 end if;
984 end applyOffset;
985
986 function memberName
987 "The path of a connector variable inside its connector, e.g. v for line.a.v
988 of the connector line.a, empty if the connector is the variable itself
989 (connector RealInput = input Real)."
990 input ComponentRef var;
991 input ComponentRef conn;
992 output String name;
993 protected
994 list<String> var_names = crefNames(var);
995 algorithm
996
1/2
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
240 for i in 1:listLength(crefNames(conn)) loop
997 168 var_names := List.restOrEmpty(var_names);
998 end for;
999 72 name := stringDelimitList(var_names, ".");
1000 end memberName;
1001
1002 function crefNames
1003 "The identifiers of a cref from the outermost one, without subscripts."
1004 input ComponentRef cref;
1005 output list<String> names = {};
1006 protected
1007 ComponentRef c = cref;
1008 algorithm
1009
2/2
✓ Branch 1 taken 460 times.
✓ Branch 2 taken 144 times.
604 while not ComponentRef.isEmpty(c) loop
1010 460 names := ComponentRef.firstName(c) :: names;
1011 460 c := ComponentRef.rest(c);
1012 end while;
1013 end crefNames;
1014
1015 function getVars
1016 "The variables of the connectors of the vertices that intersect aset, with
1017 the number of dimensions of their connector and their path inside it."
1018 input SBAtomicSet aset;
1019 input VertexSets vertexSets;
1020 input array<list<ConnVar>> vertexVars;
1021 output list<ConnVar> res;
1022 protected
1023 Option<VertexDescriptor> od;
1024 VertexDescriptor d;
1025 list<list<ConnVar>> varsl = {};
1026 algorithm
1027 60 od := UnorderedMap.get(aset, vertexSets);
1028
1029
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 36 times.
60 if isSome(od) then
1030 36 SOME(d) := od;
1031 36 res := vertexVars[d];
1032 36 return;
1033 end if;
1034
1035
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
102 for i in 1:UnorderedMap.size(vertexSets) loop
1036
2/2
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 54 times.
78 if not SBAtomicSet.isEmpty(SBAtomicSet.intersection(aset, UnorderedMap.keyAt(vertexSets, i))) then
1037 24 varsl := vertexVars[UnorderedMap.valueAt(vertexSets, i)] :: varsl;
1038 end if;
1039 end for;
1040
1041 24 res := List.flatten(listReverseInPlace(varsl));
1042 end getVars;
1043
1044 function transMulti
1045 input SBMultiInterval mi1;
1046 input SBMultiInterval mi2;
1047 input array<InstNode> iterators;
1048 input Boolean forFlow;
1049 output list<Expression> outExpl = {};
1050 output Boolean flowRange = false;
1051 protected
1052 array<SBInterval> ints1, ints2;
1053 SBInterval i1, i2;
1054 Integer i1_sz, i2_sz, m_int;
1055 Expression x, m, h, e;
1056 algorithm
1057
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
48 if SBMultiInterval.ndim(mi1) <> SBMultiInterval.ndim(mi2) then
1058 ✗ return;
1059 end if;
1060
1061 48 ints1 := SBMultiInterval.intervals(mi1);
1062 48 ints2 := SBMultiInterval.intervals(mi2);
1063
1064
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
103 for i in 1:arrayLength(ints1) loop
1065 55 i1 := ints1[i];
1066 55 i2 := ints2[i];
1067 55 i1_sz := SBInterval.size(i1);
1068 55 i2_sz := SBInterval.size(i2);
1069
1070 55 x := Expression.fromCref(ComponentRef.makeIterator(iterators[i], Type.INTEGER()));
1071
1072
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 4 times.
55 if i1_sz == i2_sz then
1073
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
51 m_int := intDiv(SBInterval.stepValue(i2), SBInterval.stepValue(i1));
1074 51 m := Expression.INTEGER(m_int);
1075 51 h := Expression.INTEGER(-m_int * SBInterval.lowerBound(i1) + SBInterval.lowerBound(i2));
1076
1077 // m * x + h
1078 51 e := Expression.BINARY(
1079 Expression.BINARY(m, Operator.makeMul(Type.INTEGER()), x),
1080 Operator.makeAdd(Type.INTEGER()),
1081 h
1082 );
1083
1084 outExpl := e :: outExpl;
1085 elseif i2_sz == 1 and not forFlow then
1086 2 outExpl := Expression.INTEGER(SBInterval.lowerBound(i2)) :: outExpl;
1087 elseif i1_sz == 1 and forFlow then
1088 2 e := Expression.makeIntegerRange(
1089 SBInterval.lowerBound(i2), SBInterval.stepValue(i2), SBInterval.upperBound(i2));
1090 outExpl := e :: outExpl;
1091 flowRange := true;
1092 else
1093 ✗ Error.terminate(getInstanceName() + " got invalid intervals.", sourceInfo());
1094 end if;
1095 end for;
1096
1097 48 outExpl := listReverseInPlace(outExpl);
1098 end transMulti;
1099
1100 annotation(__OpenModelica_Interface="nf_frontend");
1101 end NFArrayConnections;
1102