OMCompiler/Compiler/NFFrontEnd/NFSBGraphUtil.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 NFSBGraphUtil | ||
| 37 | |||
| 38 | protected | ||
| 39 | import SBGraph.VertexDescriptor; | ||
| 40 | import SBGraph.IncidenceList; | ||
| 41 | import Array; | ||
| 42 | import Ceval = NFCeval; | ||
| 43 | import Dimension = NFDimension; | ||
| 44 | import MetaModelica.Dangerous.*; | ||
| 45 | import Error; | ||
| 46 | import Expression = NFExpression; | ||
| 47 | import Operator = NFOperator; | ||
| 48 | import Op = NFOperator.Op; | ||
| 49 | import SBInterval; | ||
| 50 | import SBLinearMap; | ||
| 51 | import SBMultiInterval; | ||
| 52 | import SBPWLinearMap; | ||
| 53 | import SBSet; | ||
| 54 | import SimplifyExp = NFSimplifyExp; | ||
| 55 | import Subscript = NFSubscript; | ||
| 56 | import System; | ||
| 57 | import Vector; | ||
| 58 | |||
| 59 | public | ||
| 60 | function multiIntervalFromDimensions | ||
| 61 | input list<Dimension> dims; | ||
| 62 | input Vector<Integer> vCount; | ||
| 63 | output SBMultiInterval multiInt; | ||
| 64 | protected | ||
| 65 | Vector<Integer> new_vCount; | ||
| 66 | Integer vc, dim_size, index; | ||
| 67 | array<SBInterval> ints; | ||
| 68 | SBInterval int; | ||
| 69 | algorithm | ||
| 70 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 10 times.
|
23 | if listEmpty(dims) then |
| 71 | 13 | vc := Vector.get(vCount, 1); | |
| 72 | 13 | Vector.update(vCount, 1, vc + 1); | |
| 73 | |||
| 74 | 13 | multiInt := SBMultiInterval.fromArray(arrayCreate(Vector.size(vCount), SBInterval.new(vc, 1, vc))); | |
| 75 | else | ||
| 76 | 10 | ints := arrayCreate(Vector.size(vCount), SBInterval.newEmpty()); | |
| 77 | 10 | new_vCount := Vector.copy(vCount); | |
| 78 | index := 1; | ||
| 79 | |||
| 80 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | for dim in dims loop |
| 81 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if not Dimension.isKnown(dim) then |
| 82 | ✗ | Error.terminate(getInstanceName() + ": unknown dimension " + Dimension.toString(dim), | |
| 83 | sourceInfo()); | ||
| 84 | end if; | ||
| 85 | |||
| 86 | 10 | dim_size := Dimension.size(dim); | |
| 87 | 10 | vc := Vector.get(vCount, index); | |
| 88 | 10 | int := SBInterval.new(vc, 1, vc + dim_size - 1); | |
| 89 | |||
| 90 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if SBInterval.isEmpty(int) then |
| 91 | ✗ | ints := listArray({}); | |
| 92 | ✗ | break; | |
| 93 | else | ||
| 94 | 10 | ints[index] := int; | |
| 95 | 10 | Vector.update(new_vCount, index, vc + dim_size); | |
| 96 | end if; | ||
| 97 | |||
| 98 | 10 | index := index + 1; | |
| 99 | end for; | ||
| 100 | |||
| 101 |
2/2✓ Branch 2 taken 1 time.
✓ Branch 3 taken 9 times.
|
11 | for i in listLength(dims)+1:Vector.size(vCount) loop |
| 102 | 1 | vc := Vector.get(vCount, 1); | |
| 103 | 1 | ints[i] := SBInterval.new(vc, 1, vc); | |
| 104 | end for; | ||
| 105 | |||
| 106 | 10 | multiInt := SBMultiInterval.fromArray(ints); | |
| 107 | |||
| 108 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if not SBMultiInterval.isEmpty(multiInt) then |
| 109 | 10 | Vector.swap(new_vCount, vCount); | |
| 110 | end if; | ||
| 111 | end if; | ||
| 112 | end multiIntervalFromDimensions; | ||
| 113 | |||
| 114 | function multiIntervalFromSubscripts | ||
| 115 | input list<Subscript> subs; | ||
| 116 | input Vector<Integer> vCount; | ||
| 117 | input output SBMultiInterval multiInt; | ||
| 118 | protected | ||
| 119 | array<SBInterval> mi, miv; | ||
| 120 | SBInterval int; | ||
| 121 | Integer index, aux_lo; | ||
| 122 | Expression sub_exp; | ||
| 123 | algorithm | ||
| 124 | 30 | miv := SBMultiInterval.intervals(multiInt); | |
| 125 | |||
| 126 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 16 times.
|
30 | if listEmpty(subs) then |
| 127 | 14 | mi := Array.map(miv, make_lo_interval); | |
| 128 | else | ||
| 129 | index := 1; | ||
| 130 | 16 | mi := arrayCopy(miv); | |
| 131 | |||
| 132 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
|
32 | for s in subs loop |
| 133 | 16 | sub_exp := evalCrefs(Subscript.toExp(s)); | |
| 134 | 16 | int := intervalFromExp(sub_exp); | |
| 135 | 16 | aux_lo := SBInterval.lowerBound(miv[index]) - 1; | |
| 136 | 16 | int := SBInterval.new(aux_lo + SBInterval.lowerBound(int), | |
| 137 | SBInterval.stepValue(int), | ||
| 138 | aux_lo + SBInterval.upperBound(int)); | ||
| 139 | |||
| 140 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | if not SBInterval.isEmpty(int) then |
| 141 | 16 | mi[index] := int; | |
| 142 | else | ||
| 143 | ✗ | mi := listArray({}); | |
| 144 | ✗ | break; | |
| 145 | end if; | ||
| 146 | |||
| 147 | 16 | index := index + 1; | |
| 148 | end for; | ||
| 149 | |||
| 150 |
3/4✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 13 times.
|
35 | for i in listLength(subs)+1:arrayLength(mi) loop |
| 151 | 3 | aux_lo := SBInterval.lowerBound(miv[i]); | |
| 152 | 3 | mi[index] := SBInterval.new(aux_lo, 1, aux_lo); | |
| 153 | end for; | ||
| 154 | end if; | ||
| 155 | |||
| 156 | 30 | multiInt := SBMultiInterval.fromArray(mi); | |
| 157 | end multiIntervalFromSubscripts; | ||
| 158 | |||
| 159 | function make_lo_interval | ||
| 160 | input SBInterval i; | ||
| 161 | output SBInterval res; | ||
| 162 | protected | ||
| 163 | Integer lo = SBInterval.lowerBound(i); | ||
| 164 | algorithm | ||
| 165 | 15 | res := SBInterval.new(lo, 1, lo); | |
| 166 | end make_lo_interval; | ||
| 167 | |||
| 168 | function evalCrefs | ||
| 169 | input output Expression e; | ||
| 170 | protected | ||
| 171 | function evalCref | ||
| 172 | input Expression e; | ||
| 173 | output Expression outExp; | ||
| 174 | algorithm | ||
| 175 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
|
48 | if Expression.isCref(e) then |
| 176 | ✗ | outExp := Ceval.evalExp(e, Ceval.EvalTarget.new(Absyn.dummyInfo, NFInstContext.ITERATION_RANGE)); | |
| 177 | else | ||
| 178 | outExp := e; | ||
| 179 | end if; | ||
| 180 | end evalCref; | ||
| 181 | algorithm | ||
| 182 | 16 | e := Expression.map(e, evalCref); | |
| 183 | end evalCrefs; | ||
| 184 | |||
| 185 | function intervalFromExp | ||
| 186 | input Expression e; | ||
| 187 | output SBInterval i; | ||
| 188 | algorithm | ||
| 189 | i := match e | ||
| 190 | 6 | case Expression.INTEGER() then SBInterval.new(e.value, 1, e.value); | |
| 191 | ✗ | case Expression.BOOLEAN() then SBInterval.new(Util.boolInt(e.value), 1, Util.boolInt(e.value)); | |
| 192 | ✗ | case Expression.REAL() then SBInterval.new(realInt(e.value), 1, realInt(e.value)); | |
| 193 | 3 | case Expression.BINARY() then intervalFromBinaryExp(e.exp1, e.operator, e.exp2); | |
| 194 | ✗ | case Expression.UNARY() then intervalFromUnaryExp(e.exp); | |
| 195 | 13 | case Expression.RANGE() then intervalFromRange(e); | |
| 196 | else | ||
| 197 | algorithm | ||
| 198 | ✗ | Error.terminate(getInstanceName() + " got unknown expression " + | |
| 199 | Expression.toString(e), sourceInfo()); | ||
| 200 | ✗ | then | |
| 201 | fail(); | ||
| 202 | end match; | ||
| 203 | end intervalFromExp; | ||
| 204 | |||
| 205 | function intervalFromBinaryExp | ||
| 206 | input Expression lhs; | ||
| 207 | input Operator op; | ||
| 208 | input Expression rhs; | ||
| 209 | output SBInterval i; | ||
| 210 | protected | ||
| 211 | SBInterval lhs_i, rhs_i; | ||
| 212 | Integer lhs_sz, rhs_sz, res; | ||
| 213 | Integer llo, rlo, lhi, rhi, step; | ||
| 214 | algorithm | ||
| 215 | 3 | lhs_i := intervalFromExp(lhs); | |
| 216 | 3 | rhs_i := intervalFromExp(rhs); | |
| 217 | |||
| 218 | 3 | lhs_sz := SBInterval.size(lhs_i); | |
| 219 | 3 | rhs_sz := SBInterval.size(rhs_i); | |
| 220 | |||
| 221 | 3 | llo := SBInterval.lowerBound(lhs_i); | |
| 222 | 3 | rlo := SBInterval.lowerBound(rhs_i); | |
| 223 | |||
| 224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if lhs_sz == 1 and rhs_sz == 1 then |
| 225 | ✗ | Expression.INTEGER(value = res) := | |
| 226 | Ceval.evalBinaryOp_dispatch(Expression.INTEGER(llo), op, Expression.INTEGER(rlo)); | ||
| 227 | ✗ | i := SBInterval.new(res, 1, res); | |
| 228 | elseif lhs_sz == 1 or rhs_sz == 1 then | ||
| 229 | 3 | lhi := SBInterval.upperBound(lhs_i); | |
| 230 | 3 | rhi := SBInterval.upperBound(rhs_i); | |
| 231 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
6 | step := SBInterval.stepValue(if lhs_sz == 1 then rhs_i else lhs_i); |
| 232 | |||
| 233 | i := match op.op | ||
| 234 | 3 | case Op.ADD then SBInterval.new(llo + rlo, step, lhi + rhi); | |
| 235 | ✗ | case Op.SUB then SBInterval.new(llo - rlo, step, lhi - rhi); | |
| 236 | ✗ | case Op.MUL then SBInterval.new(llo * rlo, llo * step, lhi * rhi); | |
| 237 | else | ||
| 238 | algorithm | ||
| 239 | ✗ | Error.terminate(getInstanceName() + | |
| 240 | " got unknown operator " + Operator.symbol(op), sourceInfo()); | ||
| 241 | ✗ | then | |
| 242 | fail(); | ||
| 243 | end match; | ||
| 244 | else | ||
| 245 | ✗ | Error.terminate(getInstanceName() + " got unknown expression " + | |
| 246 | Expression.toString(Expression.BINARY(lhs, op, rhs)) + "\n", sourceInfo()); | ||
| 247 | end if; | ||
| 248 | end intervalFromBinaryExp; | ||
| 249 | |||
| 250 | function intervalFromUnaryExp | ||
| 251 | input Expression e; | ||
| 252 | output SBInterval i; | ||
| 253 | algorithm | ||
| 254 | ✗ | i := intervalFromExp(e); | |
| 255 | ✗ | i := SBInterval.new(-SBInterval.lowerBound(i), 1, -SBInterval.upperBound(i)); | |
| 256 | end intervalFromUnaryExp; | ||
| 257 | |||
| 258 | function intervalFromRange | ||
| 259 | input Expression e; | ||
| 260 | output SBInterval i; | ||
| 261 | protected | ||
| 262 | Expression start, stop; | ||
| 263 | Option<Expression> ostep; | ||
| 264 | Integer lo, step, hi; | ||
| 265 | algorithm | ||
| 266 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
13 | Expression.RANGE(start = start, step = ostep, stop = stop) := SimplifyExp.simplify(e); |
| 267 | 13 | lo := Expression.toInteger(start); | |
| 268 | 13 | hi := Expression.toInteger(stop); | |
| 269 | |||
| 270 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
|
13 | if isSome(ostep) then |
| 271 | ✗ | step := Expression.toInteger(Util.getOption(ostep)); | |
| 272 | else | ||
| 273 | step := 1; | ||
| 274 | end if; | ||
| 275 | |||
| 276 | 13 | i := SBInterval.new(lo, step, hi); | |
| 277 | end intervalFromRange; | ||
| 278 | |||
| 279 | function linearMapFromIntervals | ||
| 280 | input VertexDescriptor d1; | ||
| 281 | input VertexDescriptor d2; | ||
| 282 | input SBMultiInterval mi1; | ||
| 283 | input SBMultiInterval mi2; | ||
| 284 | input Vector<Integer> eCount; | ||
| 285 | output String name; | ||
| 286 | output SBPWLinearMap pw1; | ||
| 287 | output SBPWLinearMap pw2; | ||
| 288 | protected | ||
| 289 | array<SBInterval> ints1, ints2, mi; | ||
| 290 | Integer mi1_sz, mi2_sz, sz, sz1, sz2; | ||
| 291 | Integer count, aux_ec; | ||
| 292 | array<Real> g1, g2, o1, o2; | ||
| 293 | Real g1i, g2i, o1i, o2i; | ||
| 294 | SBInterval i1, i2; | ||
| 295 | Vector<Integer> new_ec; | ||
| 296 | SBSet s; | ||
| 297 | SBLinearMap lm1, lm2; | ||
| 298 | algorithm | ||
| 299 | 15 | ints1 := SBMultiInterval.intervals(mi1); | |
| 300 | 15 | mi1_sz := SBMultiInterval.size(mi1); | |
| 301 | |||
| 302 | 15 | ints2 := SBMultiInterval.intervals(mi2); | |
| 303 | 15 | mi2_sz := SBMultiInterval.size(mi2); | |
| 304 | |||
| 305 |
1/4✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
15 | if SBMultiInterval.ndim(mi1) <> SBMultiInterval.ndim(mi2) and |
| 306 | mi1_sz <> 1 and mi2_sz <> 1 then | ||
| 307 | ✗ | Error.terminate(getInstanceName() + " got incompatible connect", sourceInfo()); | |
| 308 | end if; | ||
| 309 | |||
| 310 | sz := arrayLength(ints1); | ||
| 311 | 15 | g1 := arrayCreateNoInit(sz, 0.0); | |
| 312 | 15 | g2 := arrayCreateNoInit(sz, 0.0); | |
| 313 | 15 | o1 := arrayCreateNoInit(sz, 0.0); | |
| 314 | 15 | o2 := arrayCreateNoInit(sz, 0.0); | |
| 315 | 15 | mi := arrayCreateNoInit(sz, ints1[1]); | |
| 316 | 15 | new_ec := Vector.new<Integer>(); | |
| 317 | |||
| 318 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
32 | for i in 1:sz loop |
| 319 | 17 | sz1 := SBInterval.size(ints1[i]); | |
| 320 | 17 | sz2 := SBInterval.size(ints2[i]); | |
| 321 | |||
| 322 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
17 | if sz1 <> sz2 and sz1 <> 1 and sz2 <> 1 then |
| 323 | ✗ | Error.terminate(getInstanceName() + " got incompatible connect", sourceInfo()); | |
| 324 | end if; | ||
| 325 | |||
| 326 | count := max(sz1, sz2); | ||
| 327 | 17 | aux_ec := Vector.get(eCount, i); | |
| 328 | 17 | mi[i] := SBInterval.new(aux_ec, 1, aux_ec + count - 1); | |
| 329 | |||
| 330 | 17 | i1 := ints1[i]; | |
| 331 | 17 | i2 := ints2[i]; | |
| 332 | |||
| 333 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
|
17 | if sz1 == 1 then |
| 334 | 11 | g1[i] := 0.0; | |
| 335 | 11 | o1[i] := SBInterval.lowerBound(i1); | |
| 336 | else | ||
| 337 | 6 | g1i := SBInterval.stepValue(i1); | |
| 338 | 6 | o1i := -g1i * aux_ec + SBInterval.lowerBound(i1); | |
| 339 | 6 | g1[i] := g1i; | |
| 340 | 6 | o1[i] := o1i; | |
| 341 | end if; | ||
| 342 | |||
| 343 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 7 times.
|
17 | if sz2 == 1 then |
| 344 | 10 | g2[i] := 0.0; | |
| 345 | 10 | o2[i] := SBInterval.lowerBound(i2); | |
| 346 | else | ||
| 347 | 7 | g2i := SBInterval.stepValue(i2); | |
| 348 | 7 | o2i := -g2i * aux_ec + SBInterval.lowerBound(i2); | |
| 349 | 7 | g2[i] := g2i; | |
| 350 | 7 | o2[i] := o2i; | |
| 351 | end if; | ||
| 352 | |||
| 353 | 17 | Vector.push(new_ec, aux_ec + count); | |
| 354 | end for; | ||
| 355 | |||
| 356 | 15 | Vector.swap(eCount, new_ec); | |
| 357 | |||
| 358 | 15 | s := SBSet.newEmpty(); | |
| 359 | 15 | s := SBSet.addAtomicSet(SBAtomicSet.new(SBMultiInterval.fromArray(mi)), s); | |
| 360 | |||
| 361 | 15 | lm1 := SBLinearMap.new(g1, o1); | |
| 362 | 15 | lm2 := SBLinearMap.new(g2, o2); | |
| 363 | |||
| 364 | 15 | pw1 := SBPWLinearMap.newScalar(s, lm1); | |
| 365 | 15 | pw2 := SBPWLinearMap.newScalar(s, lm2); | |
| 366 | |||
| 367 | 15 | name := "E" + String(System.tmpTick()); | |
| 368 | end linearMapFromIntervals; | ||
| 369 | |||
| 370 | annotation(__OpenModelica_Interface="nf_frontend"); | ||
| 371 | end NFSBGraphUtil; | ||
| 372 |