OMCompiler/Compiler/Util/SBPWLinearMap.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 uniontype SBPWLinearMap | ||
| 37 | import SBAtomicSet; | ||
| 38 | import SBSet; | ||
| 39 | import SBLinearMap; | ||
| 40 | import SBPWAtomicLinearMap; | ||
| 41 | |||
| 42 | protected | ||
| 43 | import Array; | ||
| 44 | import MetaModelica.Dangerous.*; | ||
| 45 | import System; | ||
| 46 | import Vector; | ||
| 47 | |||
| 48 | public | ||
| 49 | record PW_LINEAR_MAP | ||
| 50 | array<SBSet> dom; | ||
| 51 | array<SBLinearMap> lmap; | ||
| 52 | Integer ndim; | ||
| 53 | end PW_LINEAR_MAP; | ||
| 54 | |||
| 55 | function new | ||
| 56 | input array<SBSet> dom; | ||
| 57 | input array<SBLinearMap> lmap; | ||
| 58 | output SBPWLinearMap map; | ||
| 59 | protected | ||
| 60 | Integer dim = 0; | ||
| 61 | Boolean same_dims = false; | ||
| 62 | algorithm | ||
| 63 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 625 times.
|
625 | if arrayLength(dom) <> arrayLength(lmap) then |
| 64 | // Warning: Domain size should be equal to map size. | ||
| 65 | ✗ | map := newEmpty(); | |
| 66 | ✗ | return; | |
| 67 | end if; | ||
| 68 | |||
| 69 |
1/2✓ Branch 0 taken 625 times.
✗ Branch 1 not taken.
|
625 | if not arrayEmpty(dom) then |
| 70 | 625 | dim := SBSet.ndim(dom[1]); | |
| 71 | |||
| 72 |
2/4✓ Branch 4 taken 625 times.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 625 times.
|
625 | same_dims := Array.all(dom, function SBSet.isDim(dim = dim)) and |
| 73 | Array.all(lmap, function SBLinearMap.isDim(dim = dim)); | ||
| 74 | end if; | ||
| 75 | |||
| 76 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 625 times.
|
625 | if not same_dims then |
| 77 | // Warning: Sets and maps should have the same dimension. | ||
| 78 | ✗ | map := newEmpty(); | |
| 79 | else | ||
| 80 | 625 | map := PW_LINEAR_MAP(arrayCopy(dom), arrayCopy(lmap), dim); | |
| 81 | end if; | ||
| 82 | end new; | ||
| 83 | |||
| 84 | function newScalar | ||
| 85 | input SBSet dom; | ||
| 86 | input SBLinearMap lmap; | ||
| 87 | output SBPWLinearMap map; | ||
| 88 | algorithm | ||
| 89 |
1/2✓ Branch 2 taken 273 times.
✗ Branch 3 not taken.
|
273 | if SBSet.ndim(dom) == SBLinearMap.ndim(lmap) then |
| 90 | 273 | map := PW_LINEAR_MAP(arrayCreate(1, dom), arrayCreate(1, lmap), 1); | |
| 91 | else | ||
| 92 | // Warning: Sets and maps should have the same dimension. | ||
| 93 | ✗ | map := newEmpty(); | |
| 94 | end if; | ||
| 95 | end newScalar; | ||
| 96 | |||
| 97 | function newEmpty | ||
| 98 | output SBPWLinearMap map; | ||
| 99 | algorithm | ||
| 100 | 88 | map := PW_LINEAR_MAP(listArray({}), listArray({}), 0); | |
| 101 | end newEmpty; | ||
| 102 | |||
| 103 | function newIdentity | ||
| 104 | input SBSet set; | ||
| 105 | output SBPWLinearMap map; | ||
| 106 | protected | ||
| 107 | SBLinearMap lmap = SBLinearMap.newIdentity(SBSet.ndim(set)); | ||
| 108 | algorithm | ||
| 109 | 7 | map := PW_LINEAR_MAP(arrayCreate(1, set), arrayCreate(1, lmap), 1); | |
| 110 | end newIdentity; | ||
| 111 | |||
| 112 | function copy | ||
| 113 | input output SBPWLinearMap map; | ||
| 114 | algorithm | ||
| 115 | 15 | map.dom := Array.map(map.dom, SBSet.copy); | |
| 116 | map.lmap := Array.map(map.lmap, SBLinearMap.copy); | ||
| 117 | end copy; | ||
| 118 | |||
| 119 | function dom | ||
| 120 | input SBPWLinearMap map; | ||
| 121 | output array<SBSet> dom = map.dom; | ||
| 122 | end dom; | ||
| 123 | |||
| 124 | function lmap | ||
| 125 | input SBPWLinearMap map; | ||
| 126 | output array<SBLinearMap> lmap = map.lmap; | ||
| 127 | end lmap; | ||
| 128 | |||
| 129 | function ndim | ||
| 130 | input SBPWLinearMap map; | ||
| 131 | output Integer ndim = map.ndim; | ||
| 132 | end ndim; | ||
| 133 | |||
| 134 | function isEmpty | ||
| 135 | input SBPWLinearMap map; | ||
| 136 | output Boolean empty = arrayEmpty(map.dom); | ||
| 137 | end isEmpty; | ||
| 138 | |||
| 139 | function image | ||
| 140 | input SBPWLinearMap map; | ||
| 141 | input SBSet set; | ||
| 142 | output SBSet outSet = SBSet.newEmpty(); | ||
| 143 | protected | ||
| 144 | array<SBSet> dom = map.dom; | ||
| 145 | array<SBLinearMap> lmap = map.lmap; | ||
| 146 | SBSet ss, partial_res; | ||
| 147 | algorithm | ||
| 148 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 951 times.
|
4706 | for i in 1:arrayLength(dom) loop |
| 149 | 3755 | ss := dom[i]; | |
| 150 | 3755 | ss := SBSet.intersection(ss, set); | |
| 151 | |||
| 152 | 3755 | partial_res := UnorderedSet.fold(SBSet.asets(ss), | |
| 153 | function imageAddSet(map = lmap[i]), SBSet.newEmpty()); | ||
| 154 | |||
| 155 | 3755 | outSet := SBSet.union(outSet, partial_res); | |
| 156 | end for; | ||
| 157 | end image; | ||
| 158 | |||
| 159 | function fullImage | ||
| 160 | "The image of the whole domain of the map." | ||
| 161 | input SBPWLinearMap map; | ||
| 162 | output SBSet outSet = SBSet.newEmpty(); | ||
| 163 | protected | ||
| 164 | SBSet partial_res; | ||
| 165 | algorithm | ||
| 166 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
|
47 | for i in 1:arrayLength(map.dom) loop |
| 167 | 27 | partial_res := UnorderedSet.fold(SBSet.asets(map.dom[i]), | |
| 168 | function imageAddSet(map = map.lmap[i]), SBSet.newEmpty()); | ||
| 169 | 27 | outSet := SBSet.union(outSet, partial_res); | |
| 170 | end for; | ||
| 171 | end fullImage; | ||
| 172 | |||
| 173 | function imageAddSet | ||
| 174 | input SBAtomicSet aset; | ||
| 175 | input SBLinearMap map; | ||
| 176 | input output SBSet set; | ||
| 177 | protected | ||
| 178 | SBPWAtomicLinearMap aux_map; | ||
| 179 | algorithm | ||
| 180 | 1025 | aux_map := SBPWAtomicLinearMap.new(aset, map); | |
| 181 | 1025 | set := SBSet.addAtomicSet(SBPWAtomicLinearMap.image(aux_map, aset), set); | |
| 182 | end imageAddSet; | ||
| 183 | |||
| 184 | function preImage | ||
| 185 | input SBPWLinearMap map; | ||
| 186 | input SBSet set; | ||
| 187 | output SBSet outSet = SBSet.newEmpty(); | ||
| 188 | protected | ||
| 189 | array<SBSet> dom = map.dom; | ||
| 190 | array<SBLinearMap> lmap = map.lmap; | ||
| 191 | SBSet ss, partial_res; | ||
| 192 | array<SBAtomicSet> sets; | ||
| 193 | |||
| 194 | function add_set | ||
| 195 | input SBAtomicSet aset; | ||
| 196 | input SBLinearMap map; | ||
| 197 | input array<SBAtomicSet> sets; | ||
| 198 | input output SBSet set; | ||
| 199 | protected | ||
| 200 | SBPWAtomicLinearMap aux_map; | ||
| 201 | algorithm | ||
| 202 | 3492 | aux_map := SBPWAtomicLinearMap.new(aset, map); | |
| 203 | |||
| 204 |
2/2✓ Branch 1 taken 778 times.
✓ Branch 2 taken 3492 times.
|
4270 | for as2 in sets loop |
| 205 | 778 | set := SBSet.addAtomicSet(SBPWAtomicLinearMap.preImage(aux_map, as2), set); | |
| 206 | end for; | ||
| 207 | end add_set; | ||
| 208 | algorithm | ||
| 209 | 808 | sets := UnorderedSet.toArray(SBSet.asets(set)); | |
| 210 | |||
| 211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 808 times.
|
4297 | for i in 1:arrayLength(dom) loop |
| 212 | 3489 | ss := dom[i]; | |
| 213 | 3489 | partial_res := SBSet.newEmpty(); | |
| 214 | |||
| 215 | 3489 | partial_res := UnorderedSet.fold(SBSet.asets(ss), | |
| 216 | function add_set(map = lmap[i], sets = sets), SBSet.newEmpty()); | ||
| 217 | |||
| 218 | 3489 | outSet := SBSet.union(outSet, partial_res); | |
| 219 | end for; | ||
| 220 | end preImage; | ||
| 221 | |||
| 222 | function compPW | ||
| 223 | input SBPWLinearMap map1; | ||
| 224 | input SBPWLinearMap map2; | ||
| 225 | output SBPWLinearMap outMap; | ||
| 226 | protected | ||
| 227 | array<SBSet> dom1 = map1.dom, dom2 = map2.dom; | ||
| 228 | Vector<SBSet> ress; | ||
| 229 | array<SBLinearMap> lmap1 = map1.lmap, lmap2 = map2.lmap; | ||
| 230 | Vector<SBLinearMap> reslm; | ||
| 231 | SBSet aux_dom, new_dom, d1, d2; | ||
| 232 | SBLinearMap l1, l2, new_lm; | ||
| 233 | algorithm | ||
| 234 |
2/4✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 94 times.
|
94 | if SBPWLinearMap.isEmpty(map1) or SBPWLinearMap.isEmpty(map2) then |
| 235 | ✗ | outMap := SBPWLinearMap.newEmpty(); | |
| 236 | ✗ | return; | |
| 237 | end if; | ||
| 238 | |||
| 239 | 94 | ress := Vector.new<SBSet>(); | |
| 240 | 94 | reslm := Vector.new<SBLinearMap>(); | |
| 241 | |||
| 242 |
1/2✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
|
370 | for i in 1:arrayLength(dom1) loop |
| 243 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 276 times.
|
276 | d1 := arrayGetNoBoundsChecking(dom1, i); |
| 244 | |||
| 245 |
1/2✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
|
1072 | for j in 1:arrayLength(dom2) loop |
| 246 | 796 | d2 := arrayGetNoBoundsChecking(dom2, j); | |
| 247 | |||
| 248 | 796 | aux_dom := image(map2, d2); | |
| 249 | 796 | aux_dom := SBSet.intersection(aux_dom, d1); | |
| 250 | 796 | aux_dom := preImage(map2, aux_dom); | |
| 251 | 796 | new_dom := SBSet.intersection(aux_dom, d2); | |
| 252 | |||
| 253 |
2/2✓ Branch 1 taken 213 times.
✓ Branch 2 taken 583 times.
|
796 | if not SBSet.isEmpty(new_dom) then |
| 254 | 213 | l1 := lmap1[i]; | |
| 255 | 213 | l2 := lmap2[j]; | |
| 256 | 213 | new_lm := SBLinearMap.compose(l1, l2); | |
| 257 | 213 | Vector.push(ress, new_dom); | |
| 258 | 213 | Vector.push(reslm, new_lm); | |
| 259 | end if; | ||
| 260 | end for; | ||
| 261 | end for; | ||
| 262 | |||
| 263 | 94 | outMap := new(Vector.toArray(ress), Vector.toArray(reslm)); | |
| 264 | end compPW; | ||
| 265 | |||
| 266 | function minInvCompact | ||
| 267 | input SBPWLinearMap map; | ||
| 268 | output SBPWLinearMap outMap; | ||
| 269 | protected | ||
| 270 | SBSet aux_dom, dom_inv; | ||
| 271 | SBLinearMap aux_map, map_inv; | ||
| 272 | array<Integer> min; | ||
| 273 | array<Real> resg, reso, g, o; | ||
| 274 | algorithm | ||
| 275 | ✗ | if arrayLength(map.dom) <> 1 then | |
| 276 | // Warning: There should be only one component. | ||
| 277 | ✗ | outMap := newEmpty(); | |
| 278 | ✗ | return; | |
| 279 | end if; | ||
| 280 | |||
| 281 | aux_dom := arrayGet(map.dom, 1); | ||
| 282 | ✗ | dom_inv := image(map, aux_dom); | |
| 283 | ✗ | aux_map := arrayGet(map.lmap, 1); | |
| 284 | ✗ | map_inv := SBLinearMap.inverse(aux_map); | |
| 285 | ✗ | min := SBSet.minElem(aux_dom); | |
| 286 | |||
| 287 | ✗ | g := SBLinearMap.gain(map_inv); | |
| 288 | ✗ | o := SBLinearMap.offset(map_inv); | |
| 289 | |||
| 290 | ✗ | resg := arrayCreateNoInit(arrayLength(g), 0.0); | |
| 291 | ✗ | reso := arrayCreateNoInit(arrayLength(o), 0.0); | |
| 292 | |||
| 293 | ✗ | for i in 1:arrayLength(g) loop | |
| 294 | ✗ | if g[i] == intReal(System.intMaxLit()) then | |
| 295 | ✗ | resg[i] := 0; | |
| 296 | ✗ | reso[i] := intReal(min[i]); | |
| 297 | else | ||
| 298 | ✗ | resg[i] := g[i]; | |
| 299 | ✗ | reso[i] := o[i]; | |
| 300 | end if; | ||
| 301 | end for; | ||
| 302 | |||
| 303 | ✗ | outMap := new(arrayCreate(1, dom_inv), arrayCreate(1, SBLinearMap.new(resg, reso))); | |
| 304 | end minInvCompact; | ||
| 305 | |||
| 306 | function wholeDom | ||
| 307 | input SBPWLinearMap map; | ||
| 308 | output SBSet set; | ||
| 309 | algorithm | ||
| 310 | 221 | set := SBSet.newEmpty(); | |
| 311 | |||
| 312 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 221 times.
✓ Branch 3 taken 237 times.
✓ Branch 4 taken 221 times.
|
679 | for s in map.dom loop |
| 313 | 237 | set := SBSet.union(set, s); | |
| 314 | end for; | ||
| 315 | end wholeDom; | ||
| 316 | |||
| 317 | function combine | ||
| 318 | input SBPWLinearMap map1; | ||
| 319 | input SBPWLinearMap map2; | ||
| 320 | output SBPWLinearMap outMap; | ||
| 321 | protected | ||
| 322 | Vector<SBSet> sres; | ||
| 323 | Vector<SBLinearMap> lres; | ||
| 324 | array<SBSet> dom2; | ||
| 325 | array<SBLinearMap> lm2; | ||
| 326 | SBSet aux1, s2, new_dom; | ||
| 327 | algorithm | ||
| 328 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 221 times.
|
221 | if SBPWLinearMap.isEmpty(map1) then |
| 329 | ✗ | outMap := copy(map2); | |
| 330 | ✗ | return; | |
| 331 | end if; | ||
| 332 | |||
| 333 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 221 times.
|
221 | if SBPWLinearMap.isEmpty(map2) then |
| 334 | ✗ | outMap := copy(map1); | |
| 335 | ✗ | return; | |
| 336 | end if; | ||
| 337 | |||
| 338 | 221 | sres := Vector.fromArray(map1.dom); | |
| 339 | 221 | lres := Vector.fromArray(map1.lmap); | |
| 340 | |||
| 341 | 221 | dom2 := map2.dom; | |
| 342 | 221 | lm2 := map2.lmap; | |
| 343 | 221 | aux1 := wholeDom(map1); | |
| 344 | |||
| 345 |
1/2✓ Branch 0 taken 221 times.
✗ Branch 1 not taken.
|
608 | for i in 1:arrayLength(dom2) loop |
| 346 | 387 | s2 := dom2[i]; | |
| 347 | 387 | new_dom := SBSet.complement(s2, aux1); | |
| 348 | |||
| 349 |
2/2✓ Branch 1 taken 274 times.
✓ Branch 2 taken 113 times.
|
387 | if not SBSet.isEmpty(new_dom) then |
| 350 | 274 | Vector.push(sres, new_dom); | |
| 351 | 274 | Vector.push(lres, lm2[i]); | |
| 352 | end if; | ||
| 353 | end for; | ||
| 354 | |||
| 355 | 221 | outMap := new(Vector.toArray(sres), Vector.toArray(lres)); | |
| 356 | end combine; | ||
| 357 | |||
| 358 | function atomize | ||
| 359 | input SBPWLinearMap map; | ||
| 360 | output SBPWLinearMap outMap; | ||
| 361 | protected | ||
| 362 | list<SBSet> dres = {}; | ||
| 363 | array<SBSet> dom = map.dom; | ||
| 364 | list<SBLinearMap> lres = {}; | ||
| 365 | array<SBLinearMap> lm = map.lmap; | ||
| 366 | SBSet d, aux; | ||
| 367 | SBLinearMap l; | ||
| 368 | array<SBAtomicSet> asets; | ||
| 369 | algorithm | ||
| 370 | ✗ | for i in 1:arrayLength(dom) loop | |
| 371 | ✗ | d := dom[i]; | |
| 372 | ✗ | l := lm[i]; | |
| 373 | ✗ | asets := UnorderedSet.toArray(SBSet.asets(d)); | |
| 374 | |||
| 375 | ✗ | for s in asets loop | |
| 376 | ✗ | aux := SBSet.newEmpty(); | |
| 377 | ✗ | aux := SBSet.addAtomicSet(s, aux); | |
| 378 | |||
| 379 | dres := aux :: dres; | ||
| 380 | lres := l :: lres; | ||
| 381 | end for; | ||
| 382 | end for; | ||
| 383 | |||
| 384 | ✗ | outMap := new(listArray(listReverseInPlace(dres)), | |
| 385 | listArray(listReverseInPlace(lres))); | ||
| 386 | end atomize; | ||
| 387 | |||
| 388 | function isEqual | ||
| 389 | input SBPWLinearMap map1; | ||
| 390 | input SBPWLinearMap map2; | ||
| 391 | output Boolean equal; | ||
| 392 | algorithm | ||
| 393 | ✗ | equal := Array.isEqualOnTrue(map1.dom, map2.dom, SBSet.isEqual) and | |
| 394 | Array.isEqualOnTrue(map1.lmap, map2.lmap, SBLinearMap.isEqual); | ||
| 395 | end isEqual; | ||
| 396 | |||
| 397 | function toString | ||
| 398 | input SBPWLinearMap map; | ||
| 399 | output String str; | ||
| 400 | protected | ||
| 401 | array<SBSet> dom = map.dom; | ||
| 402 | array<SBLinearMap> lmap = map.lmap; | ||
| 403 | list<String> strl = {}; | ||
| 404 | |||
| 405 | function helper | ||
| 406 | input SBAtomicSet set; | ||
| 407 | input SBLinearMap lm; | ||
| 408 | output String str; | ||
| 409 | algorithm | ||
| 410 | ✗ | str := "{" + SBPWAtomicLinearMap.toString(SBPWAtomicLinearMap.PW_ATOMIC_LINEAR_MAP(set, lm)) + "}"; | |
| 411 | end helper; | ||
| 412 | algorithm | ||
| 413 | ✗ | for i in arrayLength(dom):-1:1 loop | |
| 414 | ✗ | strl := UnorderedSet.toString(SBSet.asets(dom[i]), function helper(lm = lmap[i]), "U") :: strl; | |
| 415 | end for; | ||
| 416 | |||
| 417 | ✗ | str := "[" + stringDelimitList(strl, ",") + "]"; | |
| 418 | end toString; | ||
| 419 | |||
| 420 | annotation(__OpenModelica_Interface="util"); | ||
| 421 | end SBPWLinearMap; | ||
| 422 |