OMCompiler/Compiler/Util/SBFunctions.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 SBFunctions | ||
| 37 | import SBAtomicSet; | ||
| 38 | import SBInterval; | ||
| 39 | import SBLinearMap; | ||
| 40 | import SBMultiInterval; | ||
| 41 | import SBPWLinearMap; | ||
| 42 | import SBSet; | ||
| 43 | |||
| 44 | protected | ||
| 45 | import Array; | ||
| 46 | import MetaModelica.Dangerous.*; | ||
| 47 | import System; | ||
| 48 | import Util; | ||
| 49 | import Vector; | ||
| 50 | |||
| 51 | public | ||
| 52 | function minAtomPW | ||
| 53 | input SBAtomicSet dom; | ||
| 54 | input SBLinearMap lm1; | ||
| 55 | input SBLinearMap lm2; | ||
| 56 | output SBPWLinearMap outMap; | ||
| 57 | protected | ||
| 58 | array<Real> g1, g2, resg; | ||
| 59 | array<Real> o1, o2, reso; | ||
| 60 | array<SBInterval> ints; | ||
| 61 | SBAtomicSet as_aux; | ||
| 62 | SBLinearMap lm_aux; | ||
| 63 | array<SBSet> dom_res; | ||
| 64 | array<SBLinearMap> lm_res; | ||
| 65 | SBSet d1, d2; | ||
| 66 | Real g1i, g2i, o1i, o2i, xinter; | ||
| 67 | SBInterval inti, i1, i2; | ||
| 68 | |||
| 69 | function make_result | ||
| 70 | input SBAtomicSet aset; | ||
| 71 | input SBLinearMap map; | ||
| 72 | output SBPWLinearMap outMap; | ||
| 73 | protected | ||
| 74 | array<SBSet> dom; | ||
| 75 | array<SBLinearMap> lm; | ||
| 76 | algorithm | ||
| 77 | 147 | dom := arrayCreate(1, SBSet.addAtomicSet(aset, SBSet.newEmpty())); | |
| 78 | 147 | lm := arrayCreate(1, map); | |
| 79 | 147 | outMap := SBPWLinearMap.new(dom, lm); | |
| 80 | end make_result; | ||
| 81 | algorithm | ||
| 82 | 147 | g1 := SBLinearMap.gain(lm1); | |
| 83 | 147 | o1 := SBLinearMap.offset(lm1); | |
| 84 | 147 | g2 := SBLinearMap.gain(lm2); | |
| 85 | 147 | o2 := SBLinearMap.offset(lm2); | |
| 86 | 147 | ints := SBMultiInterval.intervals(SBAtomicSet.aset(dom)); | |
| 87 | 147 | as_aux := SBAtomicSet.copy(dom); | |
| 88 | 147 | lm_aux := SBLinearMap.copy(lm1); | |
| 89 | 147 | resg := arrayCopy(g1); | |
| 90 | 147 | reso := arrayCopy(o1); | |
| 91 | |||
| 92 |
1/2✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
|
256 | for i in 1:arrayLength(g1) loop |
| 93 | 160 | g1i := g1[i]; | |
| 94 | 160 | g2i := g2[i]; | |
| 95 | 160 | o1i := o1[i]; | |
| 96 | 160 | o2i := o2[i]; | |
| 97 | 160 | inti := ints[i]; | |
| 98 | |||
| 99 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 137 times.
|
160 | if g1i <> g2i then |
| 100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | xinter := (o2i - o1i) / (g1i - g2i); |
| 101 | |||
| 102 |
2/2✓ Branch 1 taken 18 times.
✓ Branch 2 taken 5 times.
|
23 | if xinter <= SBInterval.lowerBound(inti) then // Intersection before domain. |
| 103 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
|
18 | if g2i < g1i then |
| 104 | 6 | lm_aux := SBLinearMap.copy(lm2); | |
| 105 | end if; | ||
| 106 | |||
| 107 | 18 | outMap := make_result(as_aux, lm_aux); | |
| 108 | elseif xinter >= SBInterval.upperBound(inti) then // Intersection after domain. | ||
| 109 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 time.
|
5 | if g2i > g1i then |
| 110 | 4 | lm_aux := SBLinearMap.copy(lm2); | |
| 111 | end if; | ||
| 112 | |||
| 113 | 5 | outMap := make_result(as_aux, lm_aux); | |
| 114 | else // Intersection in domain. | ||
| 115 | ✗ | i1 := SBInterval.new(SBInterval.lowerBound(inti), | |
| 116 | SBInterval.stepValue(inti), | ||
| 117 | realInt(floor(xinter))); | ||
| 118 | ✗ | i2 := SBInterval.new(SBInterval.upperBound(i1) + SBInterval.stepValue(i1), | |
| 119 | SBInterval.stepValue(inti), | ||
| 120 | SBInterval.upperBound(inti)); | ||
| 121 | |||
| 122 | ✗ | d1 := SBSet.addAtomicSet(SBAtomicSet.replace(i1, i, as_aux), SBSet.newEmpty()); | |
| 123 | ✗ | d2 := SBSet.addAtomicSet(SBAtomicSet.replace(i2, i, as_aux), SBSet.newEmpty()); | |
| 124 | |||
| 125 | ✗ | dom_res := listArray({d1, d2}); | |
| 126 | |||
| 127 | ✗ | if g1i > g2i then | |
| 128 | ✗ | lm_res := listArray({SBLinearMap.copy(lm1), SBLinearMap.copy(lm2)}); | |
| 129 | else | ||
| 130 | ✗ | lm_res := listArray({SBLinearMap.copy(lm2), SBLinearMap.copy(lm1)}); | |
| 131 | end if; | ||
| 132 | |||
| 133 | ✗ | outMap := SBPWLinearMap.new(dom_res, lm_res); | |
| 134 | end if; | ||
| 135 | |||
| 136 | 23 | return; | |
| 137 | elseif o1i <> o2i then | ||
| 138 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 22 times.
|
28 | if o2i < o1i then |
| 139 | 6 | lm_aux := SBLinearMap.copy(lm2); | |
| 140 | end if; | ||
| 141 | |||
| 142 | 28 | outMap := make_result(as_aux, lm_aux); | |
| 143 | 28 | return; | |
| 144 | end if; | ||
| 145 | end for; | ||
| 146 | |||
| 147 | 96 | outMap := make_result(as_aux, lm_aux); | |
| 148 | end minAtomPW; | ||
| 149 | |||
| 150 | function minPW | ||
| 151 | input SBSet dom; | ||
| 152 | input SBLinearMap lm1; | ||
| 153 | input SBLinearMap lm2; | ||
| 154 | output SBPWLinearMap outMap; | ||
| 155 | protected | ||
| 156 | array<SBSet> aux_dom; | ||
| 157 | array<SBLinearMap> aux_lm; | ||
| 158 | SBSet sres1, sres2, d; | ||
| 159 | SBLinearMap lres1, lres2, l; | ||
| 160 | array<SBAtomicSet> asets; | ||
| 161 | SBPWLinearMap aux; | ||
| 162 | SBAtomicSet as_aux; | ||
| 163 | list<SBSet> sres = {}; | ||
| 164 | list<SBLinearMap> lres = {}; | ||
| 165 | algorithm | ||
| 166 | 147 | sres1 := SBSet.newEmpty(); | |
| 167 | 147 | lres1 := SBLinearMap.newEmpty(); | |
| 168 | 147 | sres2 := SBSet.newEmpty(); | |
| 169 | 147 | lres2 := SBLinearMap.newEmpty(); | |
| 170 | |||
| 171 |
1/2✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
|
147 | if not SBSet.isEmpty(dom) then |
| 172 | 147 | asets := UnorderedSet.toArray(SBSet.asets(dom)); | |
| 173 | as_aux := asets[1]; | ||
| 174 | 147 | aux := minAtomPW(as_aux, lm1, lm2); | |
| 175 | |||
| 176 |
1/2✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
|
147 | if not SBPWLinearMap.isEmpty(aux) then |
| 177 | 147 | sres1 := arrayGet(SBPWLinearMap.dom(aux), 1); | |
| 178 | 147 | lres1 := arrayGet(SBPWLinearMap.lmap(aux), 1); | |
| 179 | |||
| 180 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
|
147 | for i in 2:arrayLength(asets) loop |
| 181 | ✗ | aux := minAtomPW(asets[i], lm1, lm2); | |
| 182 | ✗ | aux_dom := SBPWLinearMap.dom(aux); | |
| 183 | ✗ | aux_lm := SBPWLinearMap.lmap(aux); | |
| 184 | |||
| 185 | ✗ | for i in 1:arrayLength(aux_dom) loop | |
| 186 | ✗ | d := aux_dom[i]; | |
| 187 | ✗ | l := aux_lm[i]; | |
| 188 | |||
| 189 | ✗ | if SBLinearMap.isEqual(l, lres1) then | |
| 190 | ✗ | sres1 := SBSet.union(sres1, d); | |
| 191 | else | ||
| 192 | ✗ | if SBSet.isEmpty(sres2) then | |
| 193 | ✗ | sres2 := SBSet.copy(d); | |
| 194 | ✗ | lres2 := SBLinearMap.copy(l); | |
| 195 | else | ||
| 196 | ✗ | sres2 := SBSet.union(sres2, d); | |
| 197 | end if; | ||
| 198 | end if; | ||
| 199 | end for; | ||
| 200 | end for; | ||
| 201 | end if; | ||
| 202 | end if; | ||
| 203 | |||
| 204 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
147 | if not SBSet.isEmpty(sres2) and not SBLinearMap.isEmpty(lres2) then |
| 205 | sres := sres2 :: sres; | ||
| 206 | lres := lres2 :: lres; | ||
| 207 | end if; | ||
| 208 | |||
| 209 |
2/4✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 147 times.
✗ Branch 5 not taken.
|
147 | if not SBSet.isEmpty(sres1) and not SBLinearMap.isEmpty(lres1) then |
| 210 | sres := sres1 :: sres; | ||
| 211 | lres := lres1 :: lres; | ||
| 212 | end if; | ||
| 213 | |||
| 214 | 147 | outMap := SBPWLinearMap.new(listArray(sres), listArray(lres)); | |
| 215 | end minPW; | ||
| 216 | |||
| 217 | function minMap | ||
| 218 | input SBPWLinearMap pw1; | ||
| 219 | input SBPWLinearMap pw2; | ||
| 220 | output SBPWLinearMap outMap = SBPWLinearMap.newEmpty(); | ||
| 221 | protected | ||
| 222 | array<SBSet> d1, d2; | ||
| 223 | array<SBLinearMap> lm1, lm2; | ||
| 224 | SBSet d1i, dom; | ||
| 225 | SBLinearMap lm1i; | ||
| 226 | SBPWLinearMap aux; | ||
| 227 | algorithm | ||
| 228 |
2/4✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 88 times.
|
88 | if SBPWLinearMap.isEmpty(pw1) or SBPWLinearMap.isEmpty(pw2) then |
| 229 | ✗ | return; | |
| 230 | end if; | ||
| 231 | |||
| 232 | 88 | d1 := SBPWLinearMap.dom(pw1); | |
| 233 | 88 | lm1 := SBPWLinearMap.lmap(pw1); | |
| 234 | 88 | d2 := SBPWLinearMap.dom(pw2); | |
| 235 | 88 | lm2 := SBPWLinearMap.lmap(pw2); | |
| 236 | |||
| 237 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
256 | for i in 1:arrayLength(d1) loop |
| 238 | 168 | d1i := d1[i]; | |
| 239 | 168 | lm1i := lm1[i]; | |
| 240 | |||
| 241 |
1/2✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
|
578 | for j in 1:arrayLength(d2) loop |
| 242 | 410 | dom := SBSet.intersection(d1i, d2[j]); | |
| 243 | |||
| 244 |
2/2✓ Branch 1 taken 147 times.
✓ Branch 2 taken 263 times.
|
410 | if not SBSet.isEmpty(dom) then |
| 245 | 147 | aux := minPW(dom, lm1i, lm2[j]); | |
| 246 |
2/2✓ Branch 1 taken 74 times.
✓ Branch 2 taken 73 times.
|
147 | outMap := if SBPWLinearMap.isEmpty(outMap) then |
| 247 | aux else SBPWLinearMap.combine(aux, outMap); | ||
| 248 | end if; | ||
| 249 | end for; | ||
| 250 | end for; | ||
| 251 | end minMap; | ||
| 252 | |||
| 253 | function reduceMapN | ||
| 254 | input SBPWLinearMap pw; | ||
| 255 | input Integer dim; | ||
| 256 | output SBPWLinearMap outMap; | ||
| 257 | protected | ||
| 258 | array<SBSet> dom, new_s; | ||
| 259 | Vector<SBSet> sres; | ||
| 260 | array<SBLinearMap> lmap, new_l; | ||
| 261 | Vector<SBLinearMap> lres; | ||
| 262 | SBPWLinearMap pw_copy, new_map; | ||
| 263 | SBSet di, new_domi; | ||
| 264 | SBLinearMap li; | ||
| 265 | Real gdim, odim; | ||
| 266 | Integer off; | ||
| 267 | SBMultiInterval mi; | ||
| 268 | SBInterval idim, new_inter; | ||
| 269 | Integer loint, hiint; | ||
| 270 | array<Real> resg, reso; | ||
| 271 | SBAtomicSet aux_as; | ||
| 272 | UnorderedSet<SBAtomicSet> aux_newd; | ||
| 273 | array<SBAtomicSet> asets; | ||
| 274 | algorithm | ||
| 275 | 15 | dom := SBPWLinearMap.dom(pw); | |
| 276 | 15 | lmap := SBPWLinearMap.lmap(pw); | |
| 277 | |||
| 278 | 15 | pw_copy := SBPWLinearMap.copy(pw); | |
| 279 | 15 | sres := Vector.fromArray(SBPWLinearMap.dom(pw_copy)); | |
| 280 | 15 | lres := Vector.fromArray(SBPWLinearMap.lmap(pw_copy)); | |
| 281 | |||
| 282 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
73 | for i in 1:arrayLength(dom) loop |
| 283 | 58 | di := dom[i]; | |
| 284 | 58 | li := lmap[i]; | |
| 285 | 58 | gdim := arrayGet(SBLinearMap.gain(li), dim); | |
| 286 | 58 | odim := arrayGet(SBLinearMap.offset(li), dim); | |
| 287 | |||
| 288 |
4/4✓ Branch 0 taken 29 times.
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 14 times.
|
58 | if gdim == 1 and odim < 0 then |
| 289 | 15 | off := realInt(-odim); | |
| 290 | 15 | asets := UnorderedSet.toArray(SBSet.asets(di)); | |
| 291 | |||
| 292 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
|
30 | for adom in asets loop |
| 293 | 15 | mi := SBAtomicSet.aset(adom); | |
| 294 | 15 | idim := arrayGet(SBMultiInterval.intervals(mi), dim); | |
| 295 | 15 | loint := SBInterval.lowerBound(idim); | |
| 296 | 15 | hiint := SBInterval.upperBound(idim); | |
| 297 | |||
| 298 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 14 times.
|
15 | if intReal(hiint - loint) > intReal(off) * intReal(off) then |
| 299 | 1 | new_s := arrayCreateNoInit(off, di); | |
| 300 | 1 | new_l := arrayCreateNoInit(off, li); | |
| 301 | |||
| 302 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
2 | for k in 1:off loop |
| 303 | 1 | resg := arrayCopy(SBLinearMap.gain(li)); | |
| 304 | 1 | reso := arrayCopy(SBLinearMap.offset(li)); | |
| 305 | 1 | resg[dim] := 0; | |
| 306 | 1 | reso[dim] := loint + k - off - 1; | |
| 307 | |||
| 308 | 1 | new_l[k] := SBLinearMap.new(resg, reso); | |
| 309 | |||
| 310 | 1 | new_inter := SBInterval.new(loint + k - 1, off, hiint); | |
| 311 | 1 | aux_as := SBAtomicSet.replace(new_inter, dim, adom); | |
| 312 | 1 | new_s[k] := SBSet.addAtomicSet(aux_as, SBSet.newEmpty()); | |
| 313 | end for; | ||
| 314 | |||
| 315 | 1 | new_map := SBPWLinearMap.new(new_s, new_l); | |
| 316 | |||
| 317 | 1 | aux_newd := UnorderedSet.new(SBAtomicSet.hash, SBAtomicSet.isEqual); | |
| 318 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
|
2 | for aux_asi in asets loop |
| 319 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
|
1 | if not SBAtomicSet.isEqual(aux_asi, adom) then |
| 320 | ✗ | UnorderedSet.add(aux_asi, aux_newd); | |
| 321 | end if; | ||
| 322 | end for; | ||
| 323 | |||
| 324 | 1 | new_domi := SBSet.new(aux_newd); | |
| 325 | |||
| 326 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
1 | if SBSet.isEmpty(new_domi) then |
| 327 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
1 | if i < Vector.size(sres) then |
| 328 | 1 | Vector.remove(sres, i); | |
| 329 | 1 | Vector.remove(lres, i); | |
| 330 | else | ||
| 331 | ✗ | Vector.shrink(sres, i + 1); | |
| 332 | ✗ | Vector.shrink(lres, i + 1); | |
| 333 | end if; | ||
| 334 | else | ||
| 335 | ✗ | Vector.update(sres, i, new_domi); | |
| 336 | end if; | ||
| 337 | |||
| 338 | 1 | Vector.appendArray(sres, SBPWLinearMap.dom(new_map)); | |
| 339 | 1 | Vector.appendArray(lres, SBPWLinearMap.lmap(new_map)); | |
| 340 | end if; | ||
| 341 | end for; | ||
| 342 | end if; | ||
| 343 | end for; | ||
| 344 | |||
| 345 | 15 | outMap := SBPWLinearMap.new(Vector.toArray(sres), Vector.toArray(lres)); | |
| 346 | end reduceMapN; | ||
| 347 | |||
| 348 | function mapInf | ||
| 349 | input SBPWLinearMap pw; | ||
| 350 | output SBPWLinearMap outMap; | ||
| 351 | protected | ||
| 352 | Integer max_it; | ||
| 353 | array<SBSet> dom; | ||
| 354 | array<SBLinearMap> lmap; | ||
| 355 | SBSet d; | ||
| 356 | SBLinearMap lm; | ||
| 357 | array<Real> gain, off; | ||
| 358 | Real a, b, its; | ||
| 359 | |||
| 360 | function max_inter | ||
| 361 | input SBAtomicSet aset; | ||
| 362 | input Real offset; | ||
| 363 | input Integer dim; | ||
| 364 | input output Real its; | ||
| 365 | protected | ||
| 366 | array<SBInterval> is; | ||
| 367 | SBInterval i; | ||
| 368 | Real hi, lo; | ||
| 369 | algorithm | ||
| 370 | 14 | is := SBMultiInterval.intervals(SBAtomicSet.aset(aset)); | |
| 371 | 14 | i := is[dim]; | |
| 372 | 14 | hi := SBInterval.upperBound(i); | |
| 373 | 14 | lo := SBInterval.lowerBound(i); | |
| 374 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | its := max(its, ceil((hi - lo) / abs(offset))); |
| 375 | end max_inter; | ||
| 376 | algorithm | ||
| 377 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
13 | if SBPWLinearMap.isEmpty(pw) then |
| 378 | ✗ | outMap := SBPWLinearMap.newEmpty(); | |
| 379 | ✗ | return; | |
| 380 | end if; | ||
| 381 | |||
| 382 | 13 | outMap := reduceMapN(pw, 1); | |
| 383 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 11 times.
|
15 | for i in 2:SBPWLinearMap.ndim(outMap) loop |
| 384 | 2 | outMap := reduceMapN(pw, i); | |
| 385 | end for; | ||
| 386 | |||
| 387 | max_it := 0; | ||
| 388 | 13 | dom := SBPWLinearMap.dom(outMap); | |
| 389 | 13 | lmap := SBPWLinearMap.lmap(outMap); | |
| 390 | |||
| 391 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
63 | for i in 1:arrayLength(dom) loop |
| 392 | 50 | d := dom[i]; | |
| 393 | 50 | lm := lmap[i]; | |
| 394 | 50 | gain := SBLinearMap.gain(lm); | |
| 395 | 50 | off := SBLinearMap.offset(lm); | |
| 396 | |||
| 397 | a := 0; | ||
| 398 | b := gain[1]; | ||
| 399 | |||
| 400 |
1/2✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
|
50 | for j in 1:arrayLength(gain) loop |
| 401 | 58 | a := realMax(a, gain[j] * abs(off[j])); | |
| 402 | 58 | b := realMin(b, gain[j]); | |
| 403 | end for; | ||
| 404 | |||
| 405 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 36 times.
|
50 | if a > 0 then |
| 406 | its := 0; | ||
| 407 | |||
| 408 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
32 | for dim in 1:SBPWLinearMap.ndim(outMap) loop |
| 409 |
3/4✓ Branch 1 taken 14 times.
✓ Branch 2 taken 4 times.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
18 | if gain[dim] == 1 and off[dim] < 0 then |
| 410 | 14 | its := UnorderedSet.fold(SBSet.asets(d), | |
| 411 | function max_inter(offset = off[dim], dim = dim), its); | ||
| 412 | end if; | ||
| 413 | end for; | ||
| 414 | |||
| 415 | 14 | max_it := max_it + realInt(its); | |
| 416 | elseif b == 0 then | ||
| 417 | 23 | max_it := max_it + 1; | |
| 418 | end if; | ||
| 419 | end for; | ||
| 420 | |||
| 421 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
37 | for i in 1:Util.msb(max_it) loop |
| 422 | 24 | outMap := SBPWLinearMap.compPW(outMap, outMap); | |
| 423 | end for; | ||
| 424 | end mapInf; | ||
| 425 | |||
| 426 | function minAdjCompMap | ||
| 427 | input SBPWLinearMap pw2; | ||
| 428 | input SBPWLinearMap pw1; | ||
| 429 | output SBPWLinearMap outMap; | ||
| 430 | protected | ||
| 431 | array<SBSet> dom; | ||
| 432 | array<SBLinearMap> lmap; | ||
| 433 | SBSet d, dom_inv, aux; | ||
| 434 | SBLinearMap lm_inv, aux_lm1, aux_lm2, lm_res; | ||
| 435 | SBPWLinearMap inv_pw, aux_inv, aux_res; | ||
| 436 | Real inf, g; | ||
| 437 | array<Integer> min_aux; | ||
| 438 | array<Real> resg, reso, gain, off, gres, oi, ginv; | ||
| 439 | algorithm | ||
| 440 | 88 | dom := SBPWLinearMap.dom(pw2); | |
| 441 | 88 | lmap := SBPWLinearMap.lmap(pw2); | |
| 442 | |||
| 443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if arrayLength(dom) <> 1 then |
| 444 | // Warning: There should be only one pair in the map. | ||
| 445 | ✗ | outMap := SBPWLinearMap.newEmpty(); | |
| 446 | ✗ | return; | |
| 447 | end if; | ||
| 448 | |||
| 449 | d := dom[1]; | ||
| 450 | 88 | dom_inv := SBPWLinearMap.image(pw2, d); | |
| 451 | 88 | lm_inv := SBLinearMap.inverse(lmap[1]); | |
| 452 | |||
| 453 | 88 | inv_pw := SBPWLinearMap.newScalar(dom_inv, lm_inv); | |
| 454 | 88 | inf := intReal(System.intMaxLit()); | |
| 455 | |||
| 456 |
2/2✓ Branch 2 taken 34 times.
✓ Branch 3 taken 54 times.
|
88 | if Array.maxElement(SBLinearMap.gain(lm_inv), realLt) < inf then |
| 457 | 34 | outMap := SBPWLinearMap.compPW(pw1, inv_pw); | |
| 458 | elseif Array.minElement(SBLinearMap.gain(lm_inv), realLt) == inf then | ||
| 459 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | if not SBPWLinearMap.isEmpty(pw2) then |
| 460 | 44 | aux := SBPWLinearMap.image(pw1, d); | |
| 461 | 44 | min_aux := SBSet.minElem(aux); | |
| 462 | 44 | resg := arrayCreate(arrayLength(min_aux), 0.0); | |
| 463 | 44 | reso := Array.map(min_aux, intReal); | |
| 464 | 44 | lm_res := SBLinearMap.new(resg, reso); | |
| 465 | 44 | outMap := SBPWLinearMap.newScalar(dom_inv, lm_res); | |
| 466 | else | ||
| 467 | ✗ | outMap := SBPWLinearMap.newEmpty(); | |
| 468 | end if; | ||
| 469 | else | ||
| 470 | 10 | min_aux := SBSet.minElem(d); | |
| 471 | 10 | gain := SBLinearMap.gain(lm_inv); | |
| 472 | 10 | off := SBLinearMap.offset(lm_inv); | |
| 473 | 10 | resg := arrayCreateNoInit(arrayLength(gain), 0.0); | |
| 474 | 10 | reso := arrayCreateNoInit(arrayLength(gain), 0.0); | |
| 475 | |||
| 476 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
30 | for i in 1:arrayLength(gain) loop |
| 477 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | g := arrayGetNoBoundsChecking(gain, i); |
| 478 | |||
| 479 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | if g == inf then |
| 480 | 10 | resg[i] := 0.0; | |
| 481 | 10 | reso[i] := intReal(min_aux[i]); | |
| 482 | else | ||
| 483 | 10 | resg[i] := g; | |
| 484 | 10 | reso[i] := off[i]; | |
| 485 | end if; | ||
| 486 | end for; | ||
| 487 | |||
| 488 | 10 | aux_lm1 := SBLinearMap.new(resg, reso); | |
| 489 | 10 | aux_inv := SBPWLinearMap.newScalar(dom_inv, aux_lm1); | |
| 490 | 10 | aux_res := SBPWLinearMap.compPW(pw1, aux_inv); | |
| 491 | |||
| 492 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
|
10 | if SBPWLinearMap.isEmpty(aux_res) then |
| 493 | ✗ | outMap := SBPWLinearMap.newEmpty(); | |
| 494 | else | ||
| 495 | 10 | aux := SBPWLinearMap.image(pw1, d); | |
| 496 | 10 | min_aux := SBSet.minElem(aux); | |
| 497 | 10 | lm_res := arrayGet(SBPWLinearMap.lmap(aux_res), 1); | |
| 498 | 10 | gres := SBLinearMap.gain(lm_res); | |
| 499 | 10 | oi := SBLinearMap.offset(lm_res); | |
| 500 | 10 | ginv := SBLinearMap.gain(lm_inv); | |
| 501 | |||
| 502 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
30 | for i in 1:arrayLength(gain) loop |
| 503 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | g := arrayGetNoBoundsChecking(gain, i); |
| 504 | |||
| 505 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | if g == inf then |
| 506 | 10 | resg[i] := 0.0; | |
| 507 | 10 | reso[i] := intReal(min_aux[i]); | |
| 508 | else | ||
| 509 | 10 | resg[i] := gres[i]; | |
| 510 | 10 | reso[i] := oi[i]; | |
| 511 | end if; | ||
| 512 | end for; | ||
| 513 | |||
| 514 | 10 | aux_lm2 := SBLinearMap.new(resg, reso); | |
| 515 | 20 | outMap := SBPWLinearMap.newScalar(arrayGet(SBPWLinearMap.dom(aux_res), 1), aux_lm2); | |
| 516 | end if; | ||
| 517 | end if; | ||
| 518 | end minAdjCompMap; | ||
| 519 | |||
| 520 | function minAdjMap | ||
| 521 | input SBPWLinearMap pw2; | ||
| 522 | input SBPWLinearMap pw1; | ||
| 523 | output SBPWLinearMap outMap; | ||
| 524 | protected | ||
| 525 | array<SBSet> dom2; | ||
| 526 | array<SBLinearMap> lm2; | ||
| 527 | SBPWLinearMap map1, mapi, min_adj, min_m; | ||
| 528 | algorithm | ||
| 529 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
|
26 | if SBPWLinearMap.isEmpty(pw2) then |
| 530 | ✗ | outMap := SBPWLinearMap.newEmpty(); | |
| 531 | ✗ | return; | |
| 532 | end if; | ||
| 533 | |||
| 534 | 26 | dom2 := SBPWLinearMap.dom(pw2); | |
| 535 | 26 | lm2 := SBPWLinearMap.lmap(pw2); | |
| 536 | 26 | map1 := SBPWLinearMap.newScalar(dom2[1], lm2[1]); | |
| 537 | 26 | outMap := minAdjCompMap(map1, pw1); | |
| 538 | |||
| 539 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
88 | for i in 1:arrayLength(dom2) loop |
| 540 | 62 | mapi := SBPWLinearMap.newScalar(dom2[i], lm2[i]); | |
| 541 | 62 | min_adj := minAdjCompMap(mapi, pw1); | |
| 542 | 62 | min_m := minMap(outMap, min_adj); | |
| 543 | |||
| 544 | 62 | outMap := SBPWLinearMap.combine(min_adj, outMap); | |
| 545 | |||
| 546 |
2/2✓ Branch 1 taken 47 times.
✓ Branch 2 taken 15 times.
|
62 | if not SBPWLinearMap.isEmpty(min_m) then |
| 547 | 47 | outMap := SBPWLinearMap.combine(min_m, outMap); | |
| 548 | end if; | ||
| 549 | end for; | ||
| 550 | end minAdjMap; | ||
| 551 | |||
| 552 | function connectedComponents | ||
| 553 | input SBSet vss; | ||
| 554 | input SBPWLinearMap emap1; | ||
| 555 | input SBPWLinearMap emap2; | ||
| 556 | output SBPWLinearMap outMap; | ||
| 557 | protected | ||
| 558 | SBPWLinearMap ermap1, ermap2, rmap1, rmap2, new_res; | ||
| 559 | SBSet last_im, new_im, diff_im; | ||
| 560 | algorithm | ||
| 561 | 6 | outMap := SBPWLinearMap.newIdentity(vss); | |
| 562 | |||
| 563 | new_im := vss; | ||
| 564 | diff_im := vss; | ||
| 565 | |||
| 566 |
2/2✓ Branch 1 taken 13 times.
✓ Branch 2 taken 6 times.
|
19 | while not SBSet.isEmpty(diff_im) loop |
| 567 | 13 | ermap1 := SBPWLinearMap.compPW(outMap, emap1); | |
| 568 | 13 | ermap2 := SBPWLinearMap.compPW(outMap, emap2); | |
| 569 | |||
| 570 | 13 | rmap1 := minAdjMap(ermap1, ermap2); | |
| 571 | 13 | rmap2 := minAdjMap(ermap2, ermap1); | |
| 572 | 13 | rmap1 := SBPWLinearMap.combine(rmap1, outMap); | |
| 573 | 13 | rmap2 := SBPWLinearMap.combine(rmap2, outMap); | |
| 574 | |||
| 575 | // Without outMap two vertices can map onto each other. | ||
| 576 | 13 | new_res := minMap(minMap(rmap1, rmap2), outMap); | |
| 577 | 13 | outMap := mapInf(new_res); | |
| 578 | |||
| 579 | last_im := new_im; | ||
| 580 | 13 | new_im := SBPWLinearMap.image(outMap, vss); | |
| 581 | 13 | diff_im := SBSet.complement(last_im, new_im); | |
| 582 | end while; | ||
| 583 | end connectedComponents; | ||
| 584 | |||
| 585 | |||
| 586 | function test | ||
| 587 | algorithm | ||
| 588 | ✗ | test1(); | |
| 589 | ✗ | test2(); | |
| 590 | ✗ | test3(); | |
| 591 | end test; | ||
| 592 | |||
| 593 | function make_set | ||
| 594 | input list<SBInterval> i; | ||
| 595 | output SBSet s; | ||
| 596 | protected | ||
| 597 | UnorderedSet<SBAtomicSet> ss; | ||
| 598 | algorithm | ||
| 599 | ✗ | ss := UnorderedSet.new(SBAtomicSet.hash, SBAtomicSet.isEqual); | |
| 600 | ✗ | UnorderedSet.add(SBAtomicSet.new(SBMultiInterval.fromList(i)), ss); | |
| 601 | ✗ | s := SBSet.new(ss); | |
| 602 | end make_set; | ||
| 603 | |||
| 604 | function make_pw | ||
| 605 | input list<SBInterval> i; | ||
| 606 | input list<Real> gain; | ||
| 607 | input list<Real> offset; | ||
| 608 | output SBPWLinearMap pw; | ||
| 609 | protected | ||
| 610 | SBSet dom; | ||
| 611 | SBLinearMap lmap; | ||
| 612 | algorithm | ||
| 613 | ✗ | dom := make_set(i); | |
| 614 | ✗ | lmap := SBLinearMap.new(listArray(gain), listArray(offset)); | |
| 615 | ✗ | pw := SBPWLinearMap.newScalar(dom, lmap); | |
| 616 | end make_pw; | ||
| 617 | |||
| 618 | function test1 | ||
| 619 | protected | ||
| 620 | SBSet vss; | ||
| 621 | SBPWLinearMap emap1, emap2; | ||
| 622 | list<SBSet> sets; | ||
| 623 | list<SBPWLinearMap> pws1, pws2; | ||
| 624 | SBPWLinearMap res; | ||
| 625 | algorithm | ||
| 626 | ✗ | sets := { | |
| 627 | make_set({SBInterval.new(1 , 1, 1)}), | ||
| 628 | make_set({SBInterval.new(2 , 1, 1001)}), | ||
| 629 | make_set({SBInterval.new(1002, 1, 1002)}), | ||
| 630 | make_set({SBInterval.new(1003, 1, 1003)}), | ||
| 631 | make_set({SBInterval.new(1004, 1, 2003)}), | ||
| 632 | make_set({SBInterval.new(2004, 1, 3003)}), | ||
| 633 | make_set({SBInterval.new(3004, 1, 4003)}) | ||
| 634 | }; | ||
| 635 | |||
| 636 | ✗ | vss := SBSet.newEmpty(); | |
| 637 | ✗ | for s in sets loop | |
| 638 | ✗ | vss := SBSet.union(vss, s); | |
| 639 | end for; | ||
| 640 | |||
| 641 | ✗ | pws1 := { | |
| 642 | make_pw({SBInterval.new(1, 1, 1)} , {0.0}, {1.0}), | ||
| 643 | make_pw({SBInterval.new(2, 1, 2)} , {0.0}, {1002.0}), | ||
| 644 | make_pw({SBInterval.new(3, 1, 1001)} , {1.0}, {1001.0}), | ||
| 645 | make_pw({SBInterval.new(1002, 1, 2001)}, {1.0}, {1002.0}), | ||
| 646 | make_pw({SBInterval.new(2002, 1, 3001)}, {1.0}, {1002.0}) | ||
| 647 | }; | ||
| 648 | |||
| 649 | ✗ | emap1 :: pws1 := pws1; | |
| 650 | ✗ | for pw in pws1 loop | |
| 651 | ✗ | emap1 := SBPWLinearMap.combine(pw, emap1); | |
| 652 | end for; | ||
| 653 | |||
| 654 | ✗ | pws2 := { | |
| 655 | make_pw({SBInterval.new(1, 1, 1)} , {0.0}, {2.0}), | ||
| 656 | make_pw({SBInterval.new(2, 1, 2)} , {0.0}, {1003.0}), | ||
| 657 | make_pw({SBInterval.new(3, 1, 1001)} , {1.0}, {0.0}), | ||
| 658 | make_pw({SBInterval.new(1002, 1, 2001)}, {1.0}, {2.0}), | ||
| 659 | make_pw({SBInterval.new(2002, 1, 3001)}, {0.0}, {1003.0}) | ||
| 660 | }; | ||
| 661 | |||
| 662 | ✗ | emap2 :: pws2 := pws2; | |
| 663 | ✗ | for pw in pws2 loop | |
| 664 | ✗ | emap2 := SBPWLinearMap.combine(pw, emap2); | |
| 665 | end for; | ||
| 666 | |||
| 667 | ✗ | res := connectedComponents(vss, emap1, emap2); | |
| 668 | ✗ | print(SBPWLinearMap.toString(res) + "\n"); | |
| 669 | end test1; | ||
| 670 | |||
| 671 | function test2 | ||
| 672 | protected | ||
| 673 | SBSet vss; | ||
| 674 | SBPWLinearMap emap1, emap2; | ||
| 675 | list<SBSet> sets; | ||
| 676 | list<SBPWLinearMap> pws1, pws2; | ||
| 677 | SBPWLinearMap res; | ||
| 678 | algorithm | ||
| 679 | ✗ | sets := { | |
| 680 | make_set({SBInterval.new(1, 1, 1)}), | ||
| 681 | make_set({SBInterval.new(2, 1, 1001)}), | ||
| 682 | make_set({SBInterval.new(1002, 1, 1002)}), | ||
| 683 | make_set({SBInterval.new(1003, 1, 1003)}), | ||
| 684 | make_set({SBInterval.new(1004, 1, 2003)}), | ||
| 685 | make_set({SBInterval.new(2004, 1, 3003)}), | ||
| 686 | make_set({SBInterval.new(3004, 1, 4003)}) | ||
| 687 | }; | ||
| 688 | |||
| 689 | ✗ | vss := SBSet.newEmpty(); | |
| 690 | ✗ | for s in sets loop | |
| 691 | ✗ | vss := SBSet.union(vss, s); | |
| 692 | end for; | ||
| 693 | |||
| 694 | ✗ | pws1 := { | |
| 695 | make_pw({SBInterval.new(1, 1, 1)} , {0.0}, {1.0}), | ||
| 696 | make_pw({SBInterval.new(2, 1, 2)} , {0.0}, {1002.0}), | ||
| 697 | make_pw({SBInterval.new(3, 1, 3)} , {0.0}, {1004.0}), | ||
| 698 | make_pw({SBInterval.new(4, 1, 1002)} , {1.0}, {2000.0}), | ||
| 699 | make_pw({SBInterval.new(1003, 1, 2001)}, {1.0}, {2.0}), | ||
| 700 | make_pw({SBInterval.new(2002, 1, 3001)}, {1.0}, {1002.0}) | ||
| 701 | }; | ||
| 702 | |||
| 703 | ✗ | emap1 :: pws1 := pws1; | |
| 704 | ✗ | for pw in pws1 loop | |
| 705 | ✗ | emap1 := SBPWLinearMap.combine(pw, emap1); | |
| 706 | end for; | ||
| 707 | |||
| 708 | ✗ | pws2 := { | |
| 709 | make_pw({SBInterval.new(1, 1, 1)} , {0.0}, {2.0}), | ||
| 710 | make_pw({SBInterval.new(2, 1, 2)} , {0.0}, {1003.0}), | ||
| 711 | make_pw({SBInterval.new(3, 1, 3)} , {0.0}, {1003.0}), | ||
| 712 | make_pw({SBInterval.new(4, 1, 1002)} , {1.0}, {-1.0}), | ||
| 713 | make_pw({SBInterval.new(1003, 1, 2001)}, {1.0}, {1.0}), | ||
| 714 | make_pw({SBInterval.new(2002, 1, 3001)}, {1.0}, {2.0}) | ||
| 715 | }; | ||
| 716 | |||
| 717 | ✗ | emap2 :: pws2 := pws2; | |
| 718 | ✗ | for pw in pws2 loop | |
| 719 | ✗ | emap2 := SBPWLinearMap.combine(pw, emap2); | |
| 720 | end for; | ||
| 721 | |||
| 722 | ✗ | res := connectedComponents(vss, emap1, emap2); | |
| 723 | ✗ | print(SBPWLinearMap.toString(res) + "\n"); | |
| 724 | end test2; | ||
| 725 | |||
| 726 | function test3 | ||
| 727 | protected | ||
| 728 | SBSet vss; | ||
| 729 | SBPWLinearMap emap1, emap2, res; | ||
| 730 | list<SBSet> sets; | ||
| 731 | list<SBPWLinearMap> pws1, pws2; | ||
| 732 | algorithm | ||
| 733 | ✗ | sets := { | |
| 734 | make_set({SBInterval.new(1, 1, 1000), SBInterval.new(1, 1, 100)}), | ||
| 735 | make_set({SBInterval.new(1001, 1, 2000), SBInterval.new(101, 1, 200)}), | ||
| 736 | make_set({SBInterval.new(2001, 1, 3000), SBInterval.new(201, 1, 300)}), | ||
| 737 | make_set({SBInterval.new(3001, 1, 4000), SBInterval.new(301, 1, 400)}), | ||
| 738 | make_set({SBInterval.new(4001, 1, 4001)}), | ||
| 739 | make_set({SBInterval.new(4002, 1, 4002)}) | ||
| 740 | }; | ||
| 741 | |||
| 742 | ✗ | vss := SBSet.newEmpty(); | |
| 743 | ✗ | for s in sets loop | |
| 744 | ✗ | vss := SBSet.union(vss, s); | |
| 745 | end for; | ||
| 746 | |||
| 747 | ✗ | pws1 := { | |
| 748 | make_pw({SBInterval.new(1, 1, 999) , SBInterval.new(1, 1, 99)} , {1.0, 1.0}, {0.0, 0.0}), | ||
| 749 | make_pw({SBInterval.new(1000, 1, 1998), SBInterval.new(100, 1, 198)}, {1.0, 1.0}, {1001.0, 101.0}), | ||
| 750 | make_pw({SBInterval.new(1999, 1, 2998), SBInterval.new(199, 1, 199)}, {1.0, 0.0}, {-1998.0, 100.0}), | ||
| 751 | make_pw({SBInterval.new(2999, 1, 2999), SBInterval.new(200, 1, 299)}, {0.0, 1.0}, {3001.0, 101.0}), | ||
| 752 | make_pw({SBInterval.new(3000, 1, 3000), SBInterval.new(300, 1, 399)}, {0.0, 1.0}, {3000.0, -99.0}) | ||
| 753 | }; | ||
| 754 | |||
| 755 | ✗ | emap1 :: pws1 := pws1; | |
| 756 | ✗ | for pw in pws1 loop | |
| 757 | ✗ | emap1 := SBPWLinearMap.combine(pw, emap1); | |
| 758 | end for; | ||
| 759 | |||
| 760 | ✗ | pws2 := { | |
| 761 | make_pw({SBInterval.new(1, 1, 999) , SBInterval.new(1, 1, 99)} , {1.0, 1.0}, {1000.0, 101.0}), | ||
| 762 | make_pw({SBInterval.new(1000, 1, 1998), SBInterval.new(100, 1, 198)}, {1.0, 1.0}, {2002.0, 201.0}), | ||
| 763 | make_pw({SBInterval.new(1999, 1, 2998), SBInterval.new(199, 1, 199)}, {1.0, 0.0}, {-998.0, 101.0}), | ||
| 764 | make_pw({SBInterval.new(2999, 1, 2999), SBInterval.new(200, 1, 299)}, {0.0, 0.0}, {4001.0, 4001.0}), | ||
| 765 | make_pw({SBInterval.new(3000, 1, 3000), SBInterval.new(300, 1, 399)}, {0.0, 0.0}, {4002.0, 4002.0}) | ||
| 766 | }; | ||
| 767 | |||
| 768 | ✗ | emap2 :: pws2 := pws2; | |
| 769 | ✗ | for pw in pws2 loop | |
| 770 | ✗ | emap2 := SBPWLinearMap.combine(pw, emap2); | |
| 771 | end for; | ||
| 772 | |||
| 773 | ✗ | res := connectedComponents(vss, emap1, emap2); | |
| 774 | ✗ | print(SBPWLinearMap.toString(res) + "\n"); | |
| 775 | end test3; | ||
| 776 | annotation(__OpenModelica_Interface="util"); | ||
| 777 | end SBFunctions; | ||
| 778 |