OMCompiler/Compiler/NFFrontEnd/NFExpandExp.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 NFExpandExp | ||
| 37 | import Expression = NFExpression; | ||
| 38 | |||
| 39 | protected | ||
| 40 | import RangeIterator = NFRangeIterator; | ||
| 41 | import ExpressionIterator = NFExpressionIterator; | ||
| 42 | import Subscript = NFSubscript; | ||
| 43 | import Type = NFType; | ||
| 44 | import Call = NFCall; | ||
| 45 | import NFCallAttributes; | ||
| 46 | import Dimension = NFDimension; | ||
| 47 | import ComponentRef = NFComponentRef; | ||
| 48 | import NFFunction.Function; | ||
| 49 | import Operator = NFOperator; | ||
| 50 | import Ceval = NFCeval; | ||
| 51 | import NFInstNode.InstNode; | ||
| 52 | import SimplifyExp = NFSimplifyExp; | ||
| 53 | import NFPrefixes.{Variability, Purity}; | ||
| 54 | import MetaModelica.Dangerous.*; | ||
| 55 | import Absyn; | ||
| 56 | import EvalTarget = NFCeval.EvalTarget; | ||
| 57 | import Array; | ||
| 58 | import Util; | ||
| 59 | import List; | ||
| 60 | |||
| 61 | public | ||
| 62 | function expand | ||
| 63 | input output Expression exp; | ||
| 64 | input Boolean backend = false; | ||
| 65 | input Boolean resize = false; | ||
| 66 | output Boolean expanded; | ||
| 67 | algorithm | ||
| 68 | (exp, expanded) := match exp | ||
| 69 | local | ||
| 70 | array<Expression> arr; | ||
| 71 | |||
| 72 | 27411 | case Expression.INTEGER() then (exp, true); | |
| 73 | 58787 | case Expression.REAL() then (exp, true); | |
| 74 | 7497 | case Expression.STRING() then (exp, true); | |
| 75 | 454 | case Expression.BOOLEAN() then (exp, true); | |
| 76 | ✗ | case Expression.ENUM_LITERAL() then (exp, true); | |
| 77 | |||
| 78 | 17394 | case Expression.CREF(ty = Type.ARRAY()) then expandCref(exp, backend, resize); | |
| 79 | |||
| 80 | // One-dimensional arrays are already expanded. | ||
| 81 | 137155 | case Expression.ARRAY() guard Type.isVector(exp.ty) then (exp, true); | |
| 82 | |||
| 83 | case Expression.ARRAY() | ||
| 84 | algorithm | ||
| 85 | 22240 | (arr, expanded) := expandArray(exp.elements); | |
| 86 | 22240 | exp.elements := arr; | |
| 87 | 22240 | then | |
| 88 | (exp, expanded); | ||
| 89 | |||
| 90 | 1 | case Expression.TYPENAME() then (expandTypename(exp.ty), true); | |
| 91 | 1677 | case Expression.RANGE() then expandRange(exp); | |
| 92 | 7825 | case Expression.CALL() then expandCall(exp.call, exp, resize); | |
| 93 | 1 | case Expression.SIZE() then expandSize(exp); | |
| 94 | 765622 | case Expression.BINARY() then expandBinary(exp, exp.operator, resize); | |
| 95 | 86 | case Expression.MULTARY() then expand(SimplifyExp.splitMultary(exp), resize); | |
| 96 | 51365 | case Expression.UNARY() then expandUnary(exp); | |
| 97 | ✗ | case Expression.LBINARY() then expandLogicalBinary(exp); | |
| 98 | ✗ | case Expression.LUNARY() then expandLogicalUnary(exp); | |
| 99 | ✗ | case Expression.RELATION() then (exp, true); | |
| 100 | 14 | case Expression.CAST() then expandCast(exp); | |
| 101 | ✗ | case Expression.FILENAME() then (exp, true); | |
| 102 | 46397 | else expandGeneric(exp, resize); | |
| 103 | end match; | ||
| 104 | end expand; | ||
| 105 | |||
| 106 | function expandArray | ||
| 107 | "Expands an array of Expressions." | ||
| 108 | input array<Expression> arr; | ||
| 109 | output array<Expression> outArray; | ||
| 110 | output Boolean expanded = true; | ||
| 111 | protected | ||
| 112 | Boolean res; | ||
| 113 | Expression e; | ||
| 114 | algorithm | ||
| 115 | 22240 | outArray := arrayCopy(arr); | |
| 116 | |||
| 117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22240 times.
|
57353 | for i in 1:arrayLength(outArray) loop |
| 118 | 35113 | (e, res) := expand(arrayGetNoBoundsChecking(outArray, i)); | |
| 119 | |||
| 120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35113 times.
|
35113 | if not res then |
| 121 | expanded := false; | ||
| 122 | ✗ | return; | |
| 123 | end if; | ||
| 124 | |||
| 125 | arrayUpdateNoBoundsChecking(outArray, i, e); | ||
| 126 | end for; | ||
| 127 | end expandArray; | ||
| 128 | |||
| 129 | function expandList | ||
| 130 | "Expands a list of Expressions. If abortOnFailure is true the function will | ||
| 131 | stop if it fails to expand an element and the original list will be | ||
| 132 | returned unchanged. If abortOnFailure is false it will instead continue and | ||
| 133 | try to expand the whole list. In both cases the output 'expanded' indicates | ||
| 134 | whether the whole list could be expanded or not." | ||
| 135 | input list<Expression> expl; | ||
| 136 | input Boolean abortOnFailure = true; | ||
| 137 | output list<Expression> outExpl = {}; | ||
| 138 | output Boolean expanded = true; | ||
| 139 | protected | ||
| 140 | Boolean res; | ||
| 141 | algorithm | ||
| 142 |
2/2✓ Branch 0 taken 16099 times.
✓ Branch 1 taken 5671 times.
|
21770 | for exp in expl loop |
| 143 | 16099 | (exp, res) := expand(exp); | |
| 144 |
3/4✓ Branch 0 taken 16063 times.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16063 times.
|
16099 | expanded := res and expanded; |
| 145 | |||
| 146 |
3/4✓ Branch 0 taken 36 times.
✓ Branch 1 taken 16063 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
|
16099 | if not res and abortOnFailure then |
| 147 | outExpl := expl; | ||
| 148 | 36 | return; | |
| 149 | end if; | ||
| 150 | |||
| 151 | outExpl := exp :: outExpl; | ||
| 152 | end for; | ||
| 153 | |||
| 154 | 5671 | outExpl := listReverseInPlace(outExpl); | |
| 155 | end expandList; | ||
| 156 | |||
| 157 | function expandCref | ||
| 158 | input Expression crefExp; | ||
| 159 | input Boolean backend = false; | ||
| 160 | input Boolean resize = false; | ||
| 161 | output Expression arrayExp; | ||
| 162 | output Boolean expanded; | ||
| 163 | protected | ||
| 164 | list<list<Subscript>> subs; | ||
| 165 | algorithm | ||
| 166 | (arrayExp, expanded) := match crefExp | ||
| 167 | case Expression.CREF(cref = ComponentRef.CREF()) | ||
| 168 | algorithm | ||
| 169 |
2/2✓ Branch 1 taken 454 times.
✓ Branch 2 taken 25768 times.
|
26222 | if Type.hasZeroDimension(crefExp.ty) then |
| 170 | 454 | arrayExp := Expression.makeEmptyArray(crefExp.ty); | |
| 171 | expanded := true; | ||
| 172 | elseif Type.hasKnownSize(crefExp.ty) then | ||
| 173 | 25207 | subs := expandCref2(crefExp.cref, backend, resize); | |
| 174 | 25207 | arrayExp := expandCref3(subs, crefExp.cref, Type.arrayElementType(crefExp.ty)); | |
| 175 | expanded := true; | ||
| 176 | else | ||
| 177 | arrayExp := crefExp; | ||
| 178 | expanded := false; | ||
| 179 | end if; | ||
| 180 | then | ||
| 181 | (arrayExp, expanded); | ||
| 182 | |||
| 183 | else (crefExp, false); | ||
| 184 | end match; | ||
| 185 | end expandCref; | ||
| 186 | |||
| 187 | function expandCref2 | ||
| 188 | input ComponentRef cref; | ||
| 189 | input Boolean backend; | ||
| 190 | input Boolean resize; | ||
| 191 | input output list<list<Subscript>> subs = {}; | ||
| 192 | protected | ||
| 193 | list<Subscript> cr_subs = {}; | ||
| 194 | list<Dimension> dims; | ||
| 195 | |||
| 196 | import NFComponentRef.Origin; | ||
| 197 | algorithm | ||
| 198 | subs := match cref | ||
| 199 | case ComponentRef.CREF() guard(backend or cref.origin == Origin.CREF) | ||
| 200 | algorithm | ||
| 201 | 34284 | dims := Type.arrayDims(cref.ty); | |
| 202 | 34284 | cr_subs := Subscript.expandList(cref.subscripts, dims, resize); | |
| 203 |
3/4✓ Branch 0 taken 8791 times.
✓ Branch 1 taken 25493 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8791 times.
|
68568 | then |
| 204 | if listEmpty(cr_subs) and not listEmpty(dims) then | ||
| 205 | {} else expandCref2(cref.restCref, backend, resize, cr_subs :: subs); | ||
| 206 | |||
| 207 | else subs; | ||
| 208 | end match; | ||
| 209 | end expandCref2; | ||
| 210 | |||
| 211 | function expandCref3 | ||
| 212 | input list<list<Subscript>> subs; | ||
| 213 | input ComponentRef cref; | ||
| 214 | input Type crefType; | ||
| 215 | input list<list<Subscript>> accum = {}; | ||
| 216 | output Expression arrayExp; | ||
| 217 | algorithm | ||
| 218 | arrayExp := match subs | ||
| 219 | 85346 | case {} then Expression.CREF(crefType, ComponentRef.setSubscriptsList(accum, cref)); | |
| 220 | 38472 | else expandCref4(listHead(subs), {}, accum, listRest(subs), cref, crefType); | |
| 221 | end match; | ||
| 222 | end expandCref3; | ||
| 223 | |||
| 224 | function expandCref4 | ||
| 225 | input list<Subscript> subs; | ||
| 226 | input list<Subscript> comb = {}; | ||
| 227 | input list<list<Subscript>> accum = {}; | ||
| 228 | input list<list<Subscript>> restSubs; | ||
| 229 | input ComponentRef cref; | ||
| 230 | input Type crefType; | ||
| 231 | output Expression arrayExp; | ||
| 232 | protected | ||
| 233 | array<Expression> expl; | ||
| 234 | Type arr_ty; | ||
| 235 | list<Subscript> slice, rest; | ||
| 236 | Integer i; | ||
| 237 | algorithm | ||
| 238 | arrayExp := match subs | ||
| 239 | 197222 | case {} then expandCref3(restSubs, cref, crefType, listReverse(comb) :: accum); | |
| 240 | |||
| 241 | case Subscript.EXPANDED_SLICE(indices = slice) :: rest | ||
| 242 | algorithm | ||
| 243 | 31895 | expl := arrayCreateNoInit(listLength(slice), Expression.INTEGER(0)); | |
| 244 | i := 1; | ||
| 245 | |||
| 246 |
2/2✓ Branch 1 taken 92034 times.
✓ Branch 2 taken 31895 times.
|
123929 | for idx in slice loop |
| 247 | 92034 | arrayUpdateNoBoundsChecking(expl, i, | |
| 248 | expandCref4(rest, idx :: comb, accum, restSubs, cref, crefType)); | ||
| 249 | 92034 | i := i + 1; | |
| 250 | end for; | ||
| 251 | |||
| 252 | 63790 | arr_ty := Type.liftArrayLeft(Expression.typeOf(arrayGet(expl, 1)), Dimension.fromExpArray(expl)); | |
| 253 | 31895 | then | |
| 254 | Expression.makeArray(arr_ty, expl); | ||
| 255 | |||
| 256 | 7742 | else expandCref4(listRest(subs), listHead(subs) :: comb, accum, restSubs, cref, crefType); | |
| 257 | end match; | ||
| 258 | end expandCref4; | ||
| 259 | |||
| 260 | function expandTypename | ||
| 261 | input Type ty; | ||
| 262 | output Expression outExp; | ||
| 263 | algorithm | ||
| 264 | outExp := match ty | ||
| 265 | local | ||
| 266 | list<Expression> lits; | ||
| 267 | |||
| 268 | case Type.ARRAY(elementType = Type.BOOLEAN()) | ||
| 269 | ✗ | then Expression.makeArray(ty, listArray({Expression.BOOLEAN(false), Expression.BOOLEAN(true)}), true); | |
| 270 | |||
| 271 | case Type.ARRAY(elementType = Type.ENUMERATION()) | ||
| 272 | algorithm | ||
| 273 | 2 | lits := Expression.makeEnumLiterals(ty.elementType); | |
| 274 | 2 | then | |
| 275 | Expression.makeArray(ty, listArray(lits), true); | ||
| 276 | |||
| 277 | else | ||
| 278 | algorithm | ||
| 279 | ✗ | Error.addInternalError(getInstanceName() + " got invalid typename", sourceInfo()); | |
| 280 | ✗ | then | |
| 281 | fail(); | ||
| 282 | end match; | ||
| 283 | end expandTypename; | ||
| 284 | |||
| 285 | function expandRange | ||
| 286 | input Expression exp; | ||
| 287 | output Expression outExp; | ||
| 288 | output Boolean expanded; | ||
| 289 | protected | ||
| 290 | Type ty; | ||
| 291 | algorithm | ||
| 292 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1677 times.
|
1677 | Expression.RANGE(ty = ty) := exp; |
| 293 | 1677 | expanded := Expression.isLiteral(exp); | |
| 294 | |||
| 295 |
2/2✓ Branch 0 taken 1642 times.
✓ Branch 1 taken 35 times.
|
1677 | if expanded then |
| 296 | 1642 | outExp := Ceval.evalExp(exp); | |
| 297 | else | ||
| 298 | 35 | (outExp, expanded) := expandNonLiteralRange(exp, ty); | |
| 299 | end if; | ||
| 300 | end expandRange; | ||
| 301 | |||
| 302 | function expandNonLiteralRange | ||
| 303 | "Expands a numeric range whose bounds are not literals but whose size is | ||
| 304 | known, since the i:th element is start + (i - 1) * step." | ||
| 305 | input Expression exp; | ||
| 306 | input Type ty; | ||
| 307 | output Expression outExp; | ||
| 308 | output Boolean expanded; | ||
| 309 | protected | ||
| 310 | Type ety; | ||
| 311 | Expression start_exp, step_exp, e; | ||
| 312 | Option<Expression> ostep_exp; | ||
| 313 | Integer sz; | ||
| 314 | list<Expression> expl = {}; | ||
| 315 | algorithm | ||
| 316 | 35 | ety := Type.arrayElementType(ty); | |
| 317 | |||
| 318 |
3/6✓ Branch 1 taken 12 times.
✓ Branch 2 taken 23 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
35 | if not (Type.hasKnownSize(ty) and (Type.isInteger(ety) or Type.isReal(ety))) then |
| 319 | outExp := exp; | ||
| 320 | expanded := false; | ||
| 321 | 23 | return; | |
| 322 | end if; | ||
| 323 | |||
| 324 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | Expression.RANGE(start = start_exp, step = ostep_exp) := exp; |
| 325 | 12 | step_exp := Util.getOptionOrDefault(ostep_exp, Expression.makeOne(ety)); | |
| 326 | 12 | sz := Dimension.size(Type.nthDimension(ty, 1)); | |
| 327 | |||
| 328 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
48 | for i in sz:-1:1 loop |
| 329 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
|
36 | if i == 1 then |
| 330 | e := start_exp; | ||
| 331 | else | ||
| 332 | 24 | e := Expression.BINARY(makeIndexOffset(i - 1, ety), Operator.makeMul(ety), step_exp); | |
| 333 | 24 | e := SimplifyExp.simplify(Expression.BINARY(start_exp, Operator.makeAdd(ety), e)); | |
| 334 | end if; | ||
| 335 | |||
| 336 | expl := e :: expl; | ||
| 337 | end for; | ||
| 338 | |||
| 339 | 12 | outExp := Expression.makeArray(ty, listArray(expl)); | |
| 340 | expanded := true; | ||
| 341 | end expandNonLiteralRange; | ||
| 342 | |||
| 343 | function makeIndexOffset | ||
| 344 | input Integer offset; | ||
| 345 | input Type ty; | ||
| 346 | output Expression exp = if Type.isReal(ty) then Expression.REAL(intReal(offset)) else Expression.INTEGER(offset); | ||
| 347 | end makeIndexOffset; | ||
| 348 | |||
| 349 | function expandCall | ||
| 350 | input Call call; | ||
| 351 | input Expression exp; | ||
| 352 | input Boolean resize; | ||
| 353 | output Expression outExp; | ||
| 354 | output Boolean expanded; | ||
| 355 | algorithm | ||
| 356 | (outExp, expanded) := matchcontinue call | ||
| 357 | case Call.TYPED_CALL() | ||
| 358 | guard Function.isBuiltin(call.fn) and not Function.isImpure(call.fn) | ||
| 359 | 2984 | then expandBuiltinCall(call.fn, call.arguments, call, resize); | |
| 360 | |||
| 361 | case Call.TYPED_ARRAY_CONSTRUCTOR() | ||
| 362 | 3009 | then expandArrayConstructor(call.exp, call.ty, call.iters); | |
| 363 | |||
| 364 | 3350 | else expandGeneric(exp, resize); | |
| 365 | end matchcontinue; | ||
| 366 | end expandCall; | ||
| 367 | |||
| 368 | function expandBuiltinCall | ||
| 369 | input Function fn; | ||
| 370 | input list<Expression> args; | ||
| 371 | input Call call; | ||
| 372 | input Boolean resize; | ||
| 373 | output Expression outExp; | ||
| 374 | output Boolean expanded; | ||
| 375 | protected | ||
| 376 | Absyn.Path fn_path = Function.nameConsiderBuiltin(fn); | ||
| 377 | algorithm | ||
| 378 | (outExp, expanded) := match AbsynUtil.pathFirstIdent(fn_path) | ||
| 379 | 4 | case "cat" then expandBuiltinCat(args, call, resize); | |
| 380 | 1380 | case "der" then expandBuiltinGeneric(call); | |
| 381 | 1 | case "diagonal" then expandBuiltinDiagonal(listHead(args)); | |
| 382 | 108 | case "fill" then expandBuiltinFill(args); | |
| 383 | 10 | case "pre" then expandBuiltinGeneric(call); | |
| 384 | ✗ | case "previous" then expandBuiltinGeneric(call); | |
| 385 | ✗ | case "promote" then expandBuiltinPromote(args); | |
| 386 | ✗ | case "transpose" then expandBuiltinTranspose(listHead(args)); | |
| 387 | end match; | ||
| 388 | end expandBuiltinCall; | ||
| 389 | |||
| 390 | function expandBuiltinCat | ||
| 391 | input list<Expression> args; | ||
| 392 | input Call call; | ||
| 393 | input Boolean resize; | ||
| 394 | output Expression exp; | ||
| 395 | output Boolean expanded; | ||
| 396 | protected | ||
| 397 | list<Expression> expl = {}; | ||
| 398 | algorithm | ||
| 399 | 5707 | (expl, expanded) := expandList(listRest(args)); | |
| 400 | |||
| 401 |
2/2✓ Branch 0 taken 5671 times.
✓ Branch 1 taken 36 times.
|
5707 | if expanded then |
| 402 | // This relies on the fact that Ceval.evalBuiltinCat doesn't actually do any | ||
| 403 | // actual constant evaluation, and works on non-constant arrays too as long | ||
| 404 | // as they're expanded. | ||
| 405 | 5671 | exp := Ceval.evalBuiltinCat(listHead(args), expl, NFCeval.noTarget); | |
| 406 | else | ||
| 407 | 36 | exp := expandGeneric(Expression.CALL(call), resize); | |
| 408 | end if; | ||
| 409 | end expandBuiltinCat; | ||
| 410 | |||
| 411 | function expandBuiltinPromote | ||
| 412 | input list<Expression> args; | ||
| 413 | output Expression exp; | ||
| 414 | output Boolean expanded; | ||
| 415 | protected | ||
| 416 | Integer n; | ||
| 417 | Expression eexp, nexp; | ||
| 418 | algorithm | ||
| 419 | ✗ | eexp :: nexp :: {} := args; | |
| 420 | ✗ | Expression.INTEGER(value = n) := nexp; | |
| 421 | ✗ | (eexp, expanded) := expand(eexp); | |
| 422 | ✗ | exp := Expression.promote(eexp, Expression.typeOf(eexp), n); | |
| 423 | end expandBuiltinPromote; | ||
| 424 | |||
| 425 | function expandBuiltinDiagonal | ||
| 426 | input Expression arg; | ||
| 427 | output Expression outExp; | ||
| 428 | output Boolean expanded; | ||
| 429 | algorithm | ||
| 430 | 1 | (outExp, expanded) := expand(arg); | |
| 431 | |||
| 432 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
|
1 | if expanded then |
| 433 | 1 | outExp := Ceval.evalBuiltinDiagonal(outExp); | |
| 434 | end if; | ||
| 435 | end expandBuiltinDiagonal; | ||
| 436 | |||
| 437 | function expandBuiltinFill | ||
| 438 | input list<Expression> args; | ||
| 439 | output Expression outExp; | ||
| 440 | output Boolean expanded = true; | ||
| 441 | algorithm | ||
| 442 | 108 | outExp := Expression.fillArgs(listHead(args), listRest(args)); | |
| 443 | end expandBuiltinFill; | ||
| 444 | |||
| 445 | function expandBuiltinTranspose | ||
| 446 | input Expression arg; | ||
| 447 | output Expression outExp; | ||
| 448 | output Boolean expanded; | ||
| 449 | algorithm | ||
| 450 | ✗ | (outExp, expanded) := expand(arg); | |
| 451 | |||
| 452 | ✗ | if expanded then | |
| 453 | ✗ | outExp := Expression.transposeArray(outExp); | |
| 454 | end if; | ||
| 455 | end expandBuiltinTranspose; | ||
| 456 | |||
| 457 | function expandBuiltinGeneric | ||
| 458 | input Call call; | ||
| 459 | output Expression outExp; | ||
| 460 | output Boolean expanded = true; | ||
| 461 | protected | ||
| 462 | Function fn; | ||
| 463 | Type ty; | ||
| 464 | Variability var; | ||
| 465 | Purity pur; | ||
| 466 | NFCallAttributes attr; | ||
| 467 | Expression arg; | ||
| 468 | algorithm | ||
| 469 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 1390 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1390 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1390 times.
|
1390 | Call.TYPED_CALL(fn, ty, var, pur, {arg}, attr) := call; |
| 470 | 1390 | ty := Type.arrayElementType(ty); | |
| 471 | |||
| 472 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1390 times.
|
1390 | (arg, true) := expand(arg); |
| 473 | 1390 | outExp := expandBuiltinGeneric2(arg, fn, ty, var, pur, attr); | |
| 474 | end expandBuiltinGeneric; | ||
| 475 | |||
| 476 | function expandBuiltinGeneric2 | ||
| 477 | input output Expression exp; | ||
| 478 | input Function fn; | ||
| 479 | input Type ty; | ||
| 480 | input Variability var; | ||
| 481 | input Purity pur; | ||
| 482 | input NFCallAttributes attr; | ||
| 483 | algorithm | ||
| 484 | exp := match exp | ||
| 485 | local | ||
| 486 | array<Expression> arr; | ||
| 487 | |||
| 488 | case Expression.ARRAY(literal = true) then exp; | ||
| 489 | |||
| 490 | case Expression.ARRAY() | ||
| 491 | algorithm | ||
| 492 | 1380 | arr := Array.map(exp.elements, | |
| 493 | function expandBuiltinGeneric2(fn = fn, ty = ty, var = var, pur = pur, attr = attr)); | ||
| 494 | 1380 | then | |
| 495 | Expression.makeArray(Type.setArrayElementType(exp.ty, ty), arr); | ||
| 496 | |||
| 497 | 3987 | else Expression.CALL(Call.TYPED_CALL(fn, ty, var, pur, {exp}, attr)); | |
| 498 | end match; | ||
| 499 | end expandBuiltinGeneric2; | ||
| 500 | |||
| 501 | function expandArrayConstructor | ||
| 502 | input Expression exp; | ||
| 503 | input Type ty; | ||
| 504 | input list<tuple<InstNode, Expression>> iterators; | ||
| 505 | output Expression result; | ||
| 506 | output Boolean expanded = true; | ||
| 507 | protected | ||
| 508 | Expression e = exp, range; | ||
| 509 | InstNode node; | ||
| 510 | list<Expression> ranges = {}; | ||
| 511 | Mutable<Expression> iter; | ||
| 512 | list<Mutable<Expression>> iters = {}; | ||
| 513 | algorithm | ||
| 514 |
4/4✓ Branch 2 taken 3007 times.
✓ Branch 3 taken 6 times.
✓ Branch 6 taken 617 times.
✓ Branch 7 taken 2390 times.
|
3013 | if Type.hasKnownSize(ty) and not List.any(iterators, function usesIterator(exp = exp)) then |
| 515 | 2390 | result := fillArrayConstructor(expand(SimplifyExp.simplify(exp)), ty, listLength(iterators)); | |
| 516 | 2390 | return; | |
| 517 | end if; | ||
| 518 | |||
| 519 |
2/2✓ Branch 0 taken 630 times.
✓ Branch 1 taken 617 times.
|
1247 | for i in iterators loop |
| 520 | 630 | (node, range) := i; | |
| 521 | 630 | iter := Mutable.create(Expression.EMPTY(InstNode.getType(node))); | |
| 522 | 630 | e := Expression.replaceIterator(e, node, Expression.MUTABLE(iter)); | |
| 523 | iters := iter :: iters; | ||
| 524 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 624 times.
|
630 | (range, true) := expand(range); |
| 525 | ranges := range :: ranges; | ||
| 526 | end for; | ||
| 527 | |||
| 528 | 617 | result := expandArrayConstructor2(e, ty, ranges, iters); | |
| 529 | end expandArrayConstructor; | ||
| 530 | |||
| 531 | function usesIterator | ||
| 532 | input tuple<InstNode, Expression> iterator; | ||
| 533 | input Expression exp; | ||
| 534 | output Boolean used = Expression.containsIterator(exp, Util.tuple21(iterator)); | ||
| 535 | end usesIterator; | ||
| 536 | |||
| 537 | function fillArrayConstructor | ||
| 538 | "The body does not depend on the iterators: every element is the same expression." | ||
| 539 | input Expression value; | ||
| 540 | input Type ty; | ||
| 541 | input Integer levels; | ||
| 542 | output Expression result; | ||
| 543 | algorithm | ||
| 544 |
2/2✓ Branch 0 taken 2738 times.
✓ Branch 1 taken 2390 times.
|
5128 | result := if levels == 0 then value else |
| 545 | Expression.makeArray(ty, arrayCreate(Dimension.size(Type.nthDimension(ty, 1)), | ||
| 546 | fillArrayConstructor(value, Type.unliftArray(ty), levels - 1))); | ||
| 547 | end fillArrayConstructor; | ||
| 548 | |||
| 549 | function expandArrayConstructor2 | ||
| 550 | input Expression exp; | ||
| 551 | input Type ty; | ||
| 552 | input list<Expression> ranges; | ||
| 553 | input list<Mutable<Expression>> iterators; | ||
| 554 | output Expression result; | ||
| 555 | protected | ||
| 556 | Expression range; | ||
| 557 | list<Expression> ranges_rest, expl = {}; | ||
| 558 | Mutable<Expression> iter; | ||
| 559 | list<Mutable<Expression>> iters_rest; | ||
| 560 | ExpressionIterator range_iter; | ||
| 561 | Expression value; | ||
| 562 | Type el_ty; | ||
| 563 | algorithm | ||
| 564 |
2/2✓ Branch 0 taken 2173 times.
✓ Branch 1 taken 649 times.
|
2822 | if listEmpty(ranges) then |
| 565 | // Normally it wouldn't be the expansion's task to simplify expressions, | ||
| 566 | // but we make an exception here since the generated expressions contain | ||
| 567 | // MUTABLE expressions that we need to get rid of. Also, expansion of | ||
| 568 | // array constructors is often done during the scalarization phase, after | ||
| 569 | // the simplification phase, so they wouldn't otherwise be simplified. | ||
| 570 | 2173 | result := expand(SimplifyExp.simplify(exp)); | |
| 571 | else | ||
| 572 | 649 | range :: ranges_rest := ranges; | |
| 573 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 649 times.
|
649 | iter :: iters_rest := iterators; |
| 574 | 649 | range_iter := ExpressionIterator.fromExp(range); | |
| 575 | 649 | el_ty := Type.unliftArray(ty); | |
| 576 | |||
| 577 |
2/2✓ Branch 1 taken 2205 times.
✓ Branch 2 taken 649 times.
|
2854 | while ExpressionIterator.hasNext(range_iter) loop |
| 578 | 2205 | (range_iter, value) := ExpressionIterator.next(range_iter); | |
| 579 | 2205 | Mutable.update(iter, value); | |
| 580 | 2205 | expl := expandArrayConstructor2(exp, el_ty, ranges_rest, iters_rest) :: expl; | |
| 581 | end while; | ||
| 582 | |||
| 583 | 649 | result := Expression.makeArray(ty, listArray(listReverseInPlace(expl))); | |
| 584 | end if; | ||
| 585 | end expandArrayConstructor2; | ||
| 586 | |||
| 587 | function expandSize | ||
| 588 | input Expression exp; | ||
| 589 | output Expression outExp; | ||
| 590 | output Boolean expanded = true; | ||
| 591 | algorithm | ||
| 592 | outExp := match exp | ||
| 593 | local | ||
| 594 | Integer dims; | ||
| 595 | Expression e; | ||
| 596 | Type ty; | ||
| 597 | list<Expression> expl; | ||
| 598 | |||
| 599 | case Expression.SIZE(exp = e, dimIndex = NONE()) | ||
| 600 | algorithm | ||
| 601 | 1 | ty := Expression.typeOf(e); | |
| 602 | 1 | dims := Type.dimensionCount(ty); | |
| 603 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
3 | expl := list(Expression.SIZE(e, SOME(Expression.INTEGER(i))) for i in 1:dims); |
| 604 | 2 | then | |
| 605 | Expression.makeArray(Type.ARRAY(ty, {Dimension.fromInteger(dims)}), listArray(expl)); | ||
| 606 | |||
| 607 | // Size with an index is scalar, and thus already maximally expanded. | ||
| 608 | else exp; | ||
| 609 | end match; | ||
| 610 | end expandSize; | ||
| 611 | |||
| 612 | function expandBinary | ||
| 613 | input Expression exp; | ||
| 614 | input Operator op; | ||
| 615 | input Boolean resize; | ||
| 616 | output Expression outExp; | ||
| 617 | output Boolean expanded; | ||
| 618 | |||
| 619 | import NFOperator.Op; | ||
| 620 | algorithm | ||
| 621 | (outExp, expanded) := match op.op | ||
| 622 | 4 | case Op.ADD_SCALAR_ARRAY then expandBinaryScalarArray(exp, Op.ADD); | |
| 623 | 3 | case Op.ADD_ARRAY_SCALAR then expandBinaryArrayScalar(exp, Op.ADD); | |
| 624 | 1 | case Op.SUB_SCALAR_ARRAY then expandBinaryScalarArray(exp, Op.SUB); | |
| 625 | 1 | case Op.SUB_ARRAY_SCALAR then expandBinaryArrayScalar(exp, Op.SUB); | |
| 626 | 989 | case Op.MUL_SCALAR_ARRAY then expandBinaryScalarArray(exp, Op.MUL); | |
| 627 | 887 | case Op.MUL_ARRAY_SCALAR then expandBinaryArrayScalar(exp, Op.MUL); | |
| 628 | 3 | case Op.MUL_VECTOR_MATRIX then expandBinaryVectorMatrix(exp); | |
| 629 | 2273 | case Op.MUL_MATRIX_VECTOR then expandBinaryMatrixVector(exp); | |
| 630 | 1136 | case Op.SCALAR_PRODUCT then expandBinaryDotProduct(exp); | |
| 631 | 792 | case Op.MATRIX_PRODUCT then expandBinaryMatrixProduct(exp); | |
| 632 | ✗ | case Op.DIV_SCALAR_ARRAY then expandBinaryScalarArray(exp, Op.DIV); | |
| 633 | 714 | case Op.DIV_ARRAY_SCALAR then expandBinaryArrayScalar(exp, Op.DIV); | |
| 634 | 2 | case Op.POW_SCALAR_ARRAY then expandBinaryScalarArray(exp, Op.POW); | |
| 635 | 47 | case Op.POW_ARRAY_SCALAR then expandBinaryArrayScalar(exp, Op.POW); | |
| 636 | 6 | case Op.POW_MATRIX then expandBinaryPowMatrix(exp, resize); | |
| 637 | 758764 | else expandBinaryElementWise(exp); | |
| 638 | end match; | ||
| 639 | |||
| 640 |
2/2✓ Branch 0 taken 765290 times.
✓ Branch 1 taken 332 times.
|
765622 | if not expanded then |
| 641 | outExp := exp; | ||
| 642 | end if; | ||
| 643 | end expandBinary; | ||
| 644 | |||
| 645 | function expandBinaryElementWise | ||
| 646 | input Expression exp; | ||
| 647 | output Expression outExp; | ||
| 648 | output Boolean expanded; | ||
| 649 | protected | ||
| 650 | Expression exp1, exp2; | ||
| 651 | Operator op; | ||
| 652 | algorithm | ||
| 653 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 758764 times.
|
758764 | Expression.BINARY(exp1 = exp1, operator = op, exp2 = exp2) := exp; |
| 654 | |||
| 655 |
2/2✓ Branch 2 taken 2763 times.
✓ Branch 3 taken 756001 times.
|
758764 | if Type.isArray(Operator.typeOf(op)) then |
| 656 | 2763 | (exp1, expanded) := expand(exp1); | |
| 657 | |||
| 658 |
2/2✓ Branch 0 taken 2722 times.
✓ Branch 1 taken 41 times.
|
2763 | if expanded then |
| 659 | 2722 | (exp2, expanded) := expand(exp2); | |
| 660 | end if; | ||
| 661 | |||
| 662 |
2/2✓ Branch 0 taken 2722 times.
✓ Branch 1 taken 41 times.
|
2763 | if expanded then |
| 663 | 2722 | outExp := expandBinaryElementWise2(exp1, Operator.stripEW(op), exp2, SimplifyExp.simplifyBinaryOp); | |
| 664 | else | ||
| 665 | outExp := exp; | ||
| 666 | end if; | ||
| 667 | else | ||
| 668 | outExp := exp; | ||
| 669 | 756001 | expanded := true; | |
| 670 | end if; | ||
| 671 | end expandBinaryElementWise; | ||
| 672 | |||
| 673 | function expandBinaryElementWise2 | ||
| 674 | input Expression exp1; | ||
| 675 | input Operator op; | ||
| 676 | input Expression exp2; | ||
| 677 | input MakeFn func; | ||
| 678 | output Expression exp; | ||
| 679 | |||
| 680 | partial function MakeFn | ||
| 681 | input Expression exp1; | ||
| 682 | input Operator op; | ||
| 683 | input Expression exp2; | ||
| 684 | output Expression exp; | ||
| 685 | end MakeFn; | ||
| 686 | protected | ||
| 687 | array<Expression> expl1, expl2, expl; | ||
| 688 | Type ty; | ||
| 689 | Operator eop; | ||
| 690 | algorithm | ||
| 691 | 2729 | expl1 := Expression.arrayElements(exp1); | |
| 692 | 2729 | expl2 := Expression.arrayElements(exp2); | |
| 693 | 2729 | ty := Operator.typeOf(op); | |
| 694 | 2729 | eop := Operator.setType(Type.unliftArray(ty), op); | |
| 695 | |||
| 696 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2726 times.
|
2729 | if Type.dimensionCount(ty) > 1 then |
| 697 | 3 | expl := Array.threadMap(expl1, expl2, function expandBinaryElementWise2(op = eop, func = func)); | |
| 698 | else | ||
| 699 | 2726 | expl := Array.threadMap(expl1, expl2, function func(op = eop)); | |
| 700 | //expl := list(func(e1, eop, e2) threaded for e1 in expl1, e2 in expl2); | ||
| 701 | end if; | ||
| 702 | |||
| 703 | 2729 | exp := Expression.makeArray(ty, expl); | |
| 704 | end expandBinaryElementWise2; | ||
| 705 | |||
| 706 | function expandBinaryScalarArray | ||
| 707 | input Expression exp; | ||
| 708 | input NFOperator.Op scalarOp; | ||
| 709 | output Expression outExp; | ||
| 710 | output Boolean expanded; | ||
| 711 | protected | ||
| 712 | Expression exp1, exp2; | ||
| 713 | Operator op; | ||
| 714 | algorithm | ||
| 715 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 996 times.
|
996 | Expression.BINARY(exp1 = exp1, operator = op, exp2 = exp2) := exp; |
| 716 | 996 | (exp2, expanded) := expand(exp2); | |
| 717 | |||
| 718 |
2/2✓ Branch 0 taken 984 times.
✓ Branch 1 taken 12 times.
|
996 | if expanded then |
| 719 | 984 | op := Operator.OPERATOR(Type.arrayElementType(Operator.typeOf(op)), scalarOp); | |
| 720 | 984 | outExp := Expression.mapArrayElements(exp2, | |
| 721 | function SimplifyExp.simplifyBinaryOp(op = op, exp1 = exp1)); | ||
| 722 | else | ||
| 723 | outExp := exp; | ||
| 724 | end if; | ||
| 725 | end expandBinaryScalarArray; | ||
| 726 | |||
| 727 | function makeScalarArrayBinary_traverser | ||
| 728 | input Expression exp1; | ||
| 729 | input Operator op; | ||
| 730 | input Expression exp2; | ||
| 731 | output Expression exp; | ||
| 732 | algorithm | ||
| 733 | exp := match exp2 | ||
| 734 | case Expression.ARRAY() then exp2; | ||
| 735 | ✗ | else SimplifyExp.simplifyBinaryOp(exp1, op, exp2); | |
| 736 | end match; | ||
| 737 | end makeScalarArrayBinary_traverser; | ||
| 738 | |||
| 739 | function expandBinaryArrayScalar | ||
| 740 | input Expression exp; | ||
| 741 | input NFOperator.Op scalarOp; | ||
| 742 | output Expression outExp; | ||
| 743 | output Boolean expanded; | ||
| 744 | protected | ||
| 745 | Expression exp1, exp2; | ||
| 746 | Operator op; | ||
| 747 | algorithm | ||
| 748 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1652 times.
|
1652 | Expression.BINARY(exp1 = exp1, operator = op, exp2 = exp2) := exp; |
| 749 | 1652 | (exp1, expanded) := expand(exp1); | |
| 750 | |||
| 751 |
2/2✓ Branch 0 taken 1449 times.
✓ Branch 1 taken 203 times.
|
1652 | if expanded then |
| 752 | 1449 | op := Operator.OPERATOR(Type.arrayElementType(Operator.typeOf(op)), scalarOp); | |
| 753 | 1449 | outExp := Expression.mapArrayElements(exp1, | |
| 754 | function SimplifyExp.simplifyBinaryOp(op = op, exp2 = exp2)); | ||
| 755 | else | ||
| 756 | outExp := exp; | ||
| 757 | end if; | ||
| 758 | end expandBinaryArrayScalar; | ||
| 759 | |||
| 760 | function expandBinaryVectorMatrix | ||
| 761 | "Expands a vector*matrix expression, c[m] = a[n] * b[n, m]." | ||
| 762 | input Expression exp; | ||
| 763 | output Expression outExp; | ||
| 764 | output Boolean expanded; | ||
| 765 | protected | ||
| 766 | Expression exp1, exp2; | ||
| 767 | array<Expression> arr; | ||
| 768 | Type ty; | ||
| 769 | Dimension m; | ||
| 770 | algorithm | ||
| 771 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | Expression.BINARY(exp1 = exp1, exp2 = exp2) := exp; |
| 772 | 3 | (exp2, expanded) := expand(exp2); | |
| 773 | |||
| 774 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if expanded then |
| 775 |
5/10✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
|
3 | Expression.ARRAY(Type.ARRAY(ty, {m, _}), arr) := Expression.transposeArray(exp2); |
| 776 | 3 | ty := Type.ARRAY(ty, {m}); | |
| 777 | |||
| 778 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
|
3 | if arrayEmpty(arr) or Type.isEmptyArray(ty) then |
| 779 | ✗ | outExp := Expression.makeZero(ty); | |
| 780 | else | ||
| 781 | 3 | (exp1, expanded) := expand(exp1); | |
| 782 | |||
| 783 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if expanded then |
| 784 | // c[i] = a * b[:, i] for i in 1:m | ||
| 785 | 3 | arr := Array.map(arr, function makeScalarProduct(exp1 = exp1)); | |
| 786 | 3 | outExp := Expression.makeArray(ty, arr); | |
| 787 | else | ||
| 788 | outExp := exp; | ||
| 789 | end if; | ||
| 790 | end if; | ||
| 791 | else | ||
| 792 | outExp := exp; | ||
| 793 | end if; | ||
| 794 | end expandBinaryVectorMatrix; | ||
| 795 | |||
| 796 | function expandBinaryMatrixVector | ||
| 797 | "Expands a matrix*vector expression, c[n] = a[n, m] * b[m]." | ||
| 798 | input Expression exp; | ||
| 799 | output Expression outExp; | ||
| 800 | output Boolean expanded; | ||
| 801 | protected | ||
| 802 | Expression exp1, exp2; | ||
| 803 | array<Expression> arr; | ||
| 804 | Type ty; | ||
| 805 | Dimension n; | ||
| 806 | algorithm | ||
| 807 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2273 times.
|
2273 | Expression.BINARY(exp1 = exp1, exp2 = exp2) := exp; |
| 808 | 2273 | (exp1, expanded) := expand(exp1); | |
| 809 | |||
| 810 |
2/2✓ Branch 0 taken 2270 times.
✓ Branch 1 taken 3 times.
|
2273 | if expanded then |
| 811 |
5/10✗ Branch 0 not taken.
✓ Branch 1 taken 2270 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2270 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2270 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2270 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2270 times.
|
2270 | Expression.ARRAY(Type.ARRAY(ty, {n, _}), arr) := exp1; |
| 812 | 2270 | ty := Type.ARRAY(ty, {n}); | |
| 813 | |||
| 814 |
2/4✓ Branch 0 taken 2270 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2270 times.
|
2270 | if arrayEmpty(arr) or Type.isEmptyArray(ty) then |
| 815 | ✗ | outExp := Expression.makeZero(ty); | |
| 816 | else | ||
| 817 | 2270 | (exp2, expanded) := expand(exp2); | |
| 818 | |||
| 819 |
1/2✓ Branch 0 taken 2270 times.
✗ Branch 1 not taken.
|
2270 | if expanded then |
| 820 | // c[i] = a[i, :] * b for i in 1:n | ||
| 821 | 2270 | arr := Array.map(arr, function makeScalarProduct(exp2 = exp2)); | |
| 822 | 2270 | outExp := Expression.makeArray(ty, arr); | |
| 823 | else | ||
| 824 | outExp := exp; | ||
| 825 | end if; | ||
| 826 | end if; | ||
| 827 | else | ||
| 828 | outExp := exp; | ||
| 829 | end if; | ||
| 830 | end expandBinaryMatrixVector; | ||
| 831 | |||
| 832 | function expandBinaryDotProduct | ||
| 833 | "Expands a vector*vector expression, c = a[n] * b[n]." | ||
| 834 | input Expression exp; | ||
| 835 | output Expression outExp; | ||
| 836 | output Boolean expanded; | ||
| 837 | protected | ||
| 838 | Expression exp1, exp2; | ||
| 839 | algorithm | ||
| 840 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1136 times.
|
1136 | Expression.BINARY(exp1 = exp1, exp2 = exp2) := exp; |
| 841 | 1136 | (exp1, expanded) := expand(exp1); | |
| 842 | |||
| 843 |
2/2✓ Branch 0 taken 1063 times.
✓ Branch 1 taken 73 times.
|
1136 | if expanded then |
| 844 | 1063 | (exp2, expanded) := expand(exp2); | |
| 845 | end if; | ||
| 846 | |||
| 847 |
2/2✓ Branch 0 taken 1063 times.
✓ Branch 1 taken 73 times.
|
1136 | if expanded then |
| 848 | 1063 | outExp := makeScalarProduct(exp1, exp2); | |
| 849 | else | ||
| 850 | outExp := exp; | ||
| 851 | end if; | ||
| 852 | end expandBinaryDotProduct; | ||
| 853 | |||
| 854 | function makeScalarProduct | ||
| 855 | input Expression exp1; | ||
| 856 | input Expression exp2; | ||
| 857 | output Expression exp; | ||
| 858 | protected | ||
| 859 | array<Expression> arr1, arr2; | ||
| 860 | Type ty, elem_ty; | ||
| 861 | Operator mul_op, add_op; | ||
| 862 | algorithm | ||
| 863 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14786 times.
|
14786 | Expression.ARRAY(ty, arr1) := exp1; |
| 864 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14786 times.
|
14786 | Expression.ARRAY( _, arr2) := exp2; |
| 865 | 14786 | elem_ty := Type.unliftArray(ty); | |
| 866 | |||
| 867 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 14720 times.
|
14786 | if arrayEmpty(arr1) then |
| 868 | // Scalar product of two empty arrays. The result is defined in the spec | ||
| 869 | // by sum, so we return 0 since that's the default value of sum. | ||
| 870 | 66 | exp := Expression.makeZero(elem_ty); | |
| 871 | else | ||
| 872 | 14720 | mul_op := Operator.makeMul(elem_ty); | |
| 873 | 14720 | add_op := Operator.makeAdd(elem_ty); | |
| 874 | 14720 | arr1 := Array.threadMap(arr1, arr2, function SimplifyExp.simplifyBinaryOp(op = mul_op)); | |
| 875 | 14720 | exp := Array.reduce(arr1, function SimplifyExp.simplifyBinaryOp(op = add_op)); | |
| 876 | end if; | ||
| 877 | end makeScalarProduct; | ||
| 878 | |||
| 879 | function expandBinaryMatrixProduct | ||
| 880 | "Expands a matrix*matrix expression, c[n, p] = a[n, m] * b[m, p]." | ||
| 881 | input Expression exp; | ||
| 882 | output Expression outExp; | ||
| 883 | output Boolean expanded; | ||
| 884 | protected | ||
| 885 | Expression exp1, exp2; | ||
| 886 | algorithm | ||
| 887 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 792 times.
|
792 | Expression.BINARY(exp1 = exp1, exp2 = exp2) := exp; |
| 888 | 792 | (exp1, expanded) := expand(exp1); | |
| 889 | |||
| 890 |
1/2✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
|
792 | if expanded then |
| 891 | 792 | (exp2, expanded) := expand(exp2); | |
| 892 | end if; | ||
| 893 | |||
| 894 |
1/2✓ Branch 0 taken 792 times.
✗ Branch 1 not taken.
|
792 | if expanded then |
| 895 | 792 | outExp := makeBinaryMatrixProduct(exp1, exp2); | |
| 896 | else | ||
| 897 | outExp := exp; | ||
| 898 | end if; | ||
| 899 | end expandBinaryMatrixProduct; | ||
| 900 | |||
| 901 | function makeBinaryMatrixProduct | ||
| 902 | input Expression exp1; | ||
| 903 | input Expression exp2; | ||
| 904 | output Expression exp; | ||
| 905 | protected | ||
| 906 | array<Expression> arr1, arr2, arr; | ||
| 907 | Type ty, row_ty, mat_ty; | ||
| 908 | Dimension n, p; | ||
| 909 | Integer len; | ||
| 910 | Expression e; | ||
| 911 | algorithm | ||
| 912 |
5/10✗ Branch 0 not taken.
✓ Branch 1 taken 797 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 797 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 797 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 797 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 797 times.
|
797 | Expression.ARRAY(Type.ARRAY(ty, {n, _}), arr1) := exp1; |
| 913 | // Transpose the second matrix. This makes it easier to do the multiplication, | ||
| 914 | // since we can do row-row multiplications instead of row-column. | ||
| 915 |
5/10✗ Branch 1 not taken.
✓ Branch 2 taken 797 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 797 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 797 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 797 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 797 times.
|
797 | Expression.ARRAY(Type.ARRAY(dimensions = {p, _}), arr2) := Expression.transposeArray(exp2); |
| 916 | 797 | mat_ty := Type.ARRAY(ty, {n, p}); | |
| 917 | |||
| 918 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 797 times.
|
797 | if arrayEmpty(arr2) then |
| 919 | // If any of the matrices' dimensions are zero, the result will be a matrix | ||
| 920 | // of zeroes (the default value of sum). Only arr2 needs to be checked here, | ||
| 921 | // the normal case can handle arr1 being empty. | ||
| 922 | ✗ | exp := Expression.makeZero(mat_ty); | |
| 923 | else | ||
| 924 | // c[i, j] = a[i, :] * b[:, j] for i in 1:n, j in 1:p. | ||
| 925 | 797 | row_ty := Type.ARRAY(ty, {p}); | |
| 926 | len := arrayLength(arr1); | ||
| 927 | 797 | arr := arrayCreateNoInit(len, exp1); | |
| 928 | |||
| 929 |
1/2✓ Branch 0 taken 797 times.
✗ Branch 1 not taken.
|
3174 | for i in 1:len loop |
| 930 | 2377 | e := arrayGetNoBoundsChecking(arr1, i); | |
| 931 | 2377 | arrayUpdateNoBoundsChecking(arr, i, | |
| 932 | Expression.makeArray(row_ty, makeBinaryMatrixProduct2(e, arr2))); | ||
| 933 | end for; | ||
| 934 | |||
| 935 | 797 | exp := Expression.makeArray(mat_ty, arr); | |
| 936 | end if; | ||
| 937 | end makeBinaryMatrixProduct; | ||
| 938 | |||
| 939 | function makeBinaryMatrixProduct2 | ||
| 940 | input Expression row; | ||
| 941 | input array<Expression> matrix; | ||
| 942 | output array<Expression> outRow; | ||
| 943 | algorithm | ||
| 944 | 2377 | outRow := Array.map(matrix, function makeScalarProduct(exp1 = row)); | |
| 945 | end makeBinaryMatrixProduct2; | ||
| 946 | |||
| 947 | function expandBinaryPowMatrix | ||
| 948 | input Expression exp; | ||
| 949 | input Boolean resize; | ||
| 950 | output Expression outExp = exp; | ||
| 951 | output Boolean expanded; | ||
| 952 | protected | ||
| 953 | Expression exp1, exp2; | ||
| 954 | Operator op; | ||
| 955 | Integer n; | ||
| 956 | algorithm | ||
| 957 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | Expression.BINARY(exp1 = exp1, operator = op, exp2 = exp2) := exp; |
| 958 | |||
| 959 | (outExp, expanded) := match exp2 | ||
| 960 | // a ^ 0 = identity(size(a, 1)) | ||
| 961 | case Expression.INTEGER(0) | ||
| 962 | algorithm | ||
| 963 | 1 | n := Dimension.size(listHead(Type.arrayDims(Operator.typeOf(op)))); | |
| 964 | 1 | then | |
| 965 | (Expression.makeIdentityMatrix(n, Type.REAL()), true); | ||
| 966 | |||
| 967 | // a ^ n where n is a literal value. | ||
| 968 | case Expression.INTEGER(n) | ||
| 969 | guard n > 0 | ||
| 970 | algorithm | ||
| 971 | 4 | (exp1, expanded) := expand(exp1); | |
| 972 | |||
| 973 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if expanded then |
| 974 | 4 | outExp := expandBinaryPowMatrix2(exp1, n); | |
| 975 | end if; | ||
| 976 | 4 | then | |
| 977 | (outExp, expanded); | ||
| 978 | |||
| 979 | // a ^ n where n is unknown, subscript the whole expression. | ||
| 980 | 1 | else expandGeneric(exp, resize); | |
| 981 | end match; | ||
| 982 | end expandBinaryPowMatrix; | ||
| 983 | |||
| 984 | function expandBinaryPowMatrix2 | ||
| 985 | input Expression matrix; | ||
| 986 | input Integer n; | ||
| 987 | output Expression exp; | ||
| 988 | algorithm | ||
| 989 | exp := match n | ||
| 990 | // A^1 = A | ||
| 991 | case 1 then matrix; | ||
| 992 | // A^2 = A * A | ||
| 993 | 3 | case 2 then makeBinaryMatrixProduct(matrix, matrix); | |
| 994 | |||
| 995 | // A^n = A^m * A^m where n = 2*m | ||
| 996 | case _ guard intMod(n, 2) == 0 | ||
| 997 | algorithm | ||
| 998 | 1 | exp := expandBinaryPowMatrix2(matrix, intDiv(n, 2)); | |
| 999 | 1 | then | |
| 1000 | makeBinaryMatrixProduct(exp, exp); | ||
| 1001 | |||
| 1002 | // A^n = A * A^(n-1) | ||
| 1003 | else | ||
| 1004 | algorithm | ||
| 1005 | 1 | exp := expandBinaryPowMatrix2(matrix, n - 1); | |
| 1006 | 1 | then | |
| 1007 | makeBinaryMatrixProduct(matrix, exp); | ||
| 1008 | |||
| 1009 | end match; | ||
| 1010 | end expandBinaryPowMatrix2; | ||
| 1011 | |||
| 1012 | function expandUnary | ||
| 1013 | input Expression exp; | ||
| 1014 | output Expression outExp; | ||
| 1015 | output Boolean expanded; | ||
| 1016 | protected | ||
| 1017 | Expression operand; | ||
| 1018 | Operator op, scalar_op; | ||
| 1019 | algorithm | ||
| 1020 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51365 times.
|
51365 | Expression.UNARY(op, operand) := exp; |
| 1021 | 51365 | (operand, expanded) := expand(operand); | |
| 1022 | |||
| 1023 |
2/2✓ Branch 0 taken 51364 times.
✓ Branch 1 taken 1 time.
|
51365 | if expanded then |
| 1024 | 51364 | scalar_op := Operator.scalarize(op); | |
| 1025 | 51364 | outExp := Expression.mapArrayElements(operand, | |
| 1026 | function SimplifyExp.simplifyUnaryOp(op = scalar_op)); | ||
| 1027 | else | ||
| 1028 | outExp := exp; | ||
| 1029 | end if; | ||
| 1030 | end expandUnary; | ||
| 1031 | |||
| 1032 | function expandLogicalBinary | ||
| 1033 | input Expression exp; | ||
| 1034 | output Expression outExp; | ||
| 1035 | output Boolean expanded; | ||
| 1036 | protected | ||
| 1037 | Expression exp1, exp2; | ||
| 1038 | Operator op; | ||
| 1039 | algorithm | ||
| 1040 | ✗ | Expression.LBINARY(exp1 = exp1, operator = op, exp2 = exp2) := exp; | |
| 1041 | |||
| 1042 | ✗ | if Type.isArray(Operator.typeOf(op)) then | |
| 1043 | ✗ | (exp1, expanded) := expand(exp1); | |
| 1044 | |||
| 1045 | ✗ | if expanded then | |
| 1046 | ✗ | (exp2, expanded) := expand(exp2); | |
| 1047 | end if; | ||
| 1048 | |||
| 1049 | ✗ | if expanded then | |
| 1050 | ✗ | outExp := expandBinaryElementWise2(exp1, op, exp2, makeLBinaryOp); | |
| 1051 | else | ||
| 1052 | outExp := exp; | ||
| 1053 | end if; | ||
| 1054 | else | ||
| 1055 | outExp := exp; | ||
| 1056 | ✗ | expanded := true; | |
| 1057 | end if; | ||
| 1058 | end expandLogicalBinary; | ||
| 1059 | |||
| 1060 | function makeLBinaryOp | ||
| 1061 | input Expression exp1; | ||
| 1062 | input Operator op; | ||
| 1063 | input Expression exp2; | ||
| 1064 | output Expression exp; | ||
| 1065 | algorithm | ||
| 1066 | ✗ | if Expression.isScalarLiteral(exp1) and Expression.isScalarLiteral(exp2) then | |
| 1067 | ✗ | exp := Ceval.evalLogicBinaryOp(exp1, op, exp2); | |
| 1068 | else | ||
| 1069 | ✗ | exp := Expression.LBINARY(exp1, op, exp2); | |
| 1070 | end if; | ||
| 1071 | end makeLBinaryOp; | ||
| 1072 | |||
| 1073 | function expandLogicalUnary | ||
| 1074 | input Expression exp; | ||
| 1075 | output Expression outExp; | ||
| 1076 | output Boolean expanded; | ||
| 1077 | protected | ||
| 1078 | Expression operand; | ||
| 1079 | Operator op, scalar_op; | ||
| 1080 | algorithm | ||
| 1081 | ✗ | Expression.LUNARY(op, operand) := exp; | |
| 1082 | ✗ | (operand, expanded) := expand(operand); | |
| 1083 | |||
| 1084 | ✗ | if expanded then | |
| 1085 | ✗ | scalar_op := Operator.scalarize(op); | |
| 1086 | ✗ | outExp := Expression.mapArrayElements(operand, function makeLogicalUnaryOp(op = scalar_op)); | |
| 1087 | else | ||
| 1088 | outExp := exp; | ||
| 1089 | end if; | ||
| 1090 | end expandLogicalUnary; | ||
| 1091 | |||
| 1092 | function makeLogicalUnaryOp | ||
| 1093 | input Expression exp1; | ||
| 1094 | input Operator op; | ||
| 1095 | output Expression exp = Expression.LUNARY(op, exp1); | ||
| 1096 | end makeLogicalUnaryOp; | ||
| 1097 | |||
| 1098 | function expandCast | ||
| 1099 | input Expression castExp; | ||
| 1100 | output Expression outExp; | ||
| 1101 | output Boolean expanded; | ||
| 1102 | protected | ||
| 1103 | Expression exp; | ||
| 1104 | Type ty; | ||
| 1105 | algorithm | ||
| 1106 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | Expression.CAST(exp = exp, ty = ty) := castExp; |
| 1107 | 14 | (outExp, expanded) := expand(exp); | |
| 1108 | |||
| 1109 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | if expanded and not referenceEq(exp, outExp) then |
| 1110 | 14 | outExp := Expression.typeCast(outExp, ty); | |
| 1111 | else | ||
| 1112 | outExp := castExp; | ||
| 1113 | end if; | ||
| 1114 | end expandCast; | ||
| 1115 | |||
| 1116 | function expandGeneric | ||
| 1117 | input Expression exp; | ||
| 1118 | input Boolean resize; | ||
| 1119 | output Expression outExp; | ||
| 1120 | output Boolean expanded; | ||
| 1121 | protected | ||
| 1122 | Type ty; | ||
| 1123 | list<Dimension> dims; | ||
| 1124 | list<list<Subscript>> subs; | ||
| 1125 | algorithm | ||
| 1126 | 49784 | ty := Expression.typeOf(exp); | |
| 1127 | |||
| 1128 |
2/2✓ Branch 1 taken 852 times.
✓ Branch 2 taken 48932 times.
|
49784 | if Type.isArray(ty) then |
| 1129 | 852 | expanded := Type.hasKnownSize(ty); | |
| 1130 | |||
| 1131 |
2/2✓ Branch 0 taken 776 times.
✓ Branch 1 taken 76 times.
|
852 | if expanded then |
| 1132 | 776 | dims := Type.arrayDims(ty); | |
| 1133 |
8/8✓ Branch 0 taken 888 times.
✓ Branch 1 taken 776 times.
✓ Branch 2 taken 888 times.
✓ Branch 3 taken 776 times.
✓ Branch 6 taken 2863 times.
✓ Branch 7 taken 888 times.
✓ Branch 8 taken 2863 times.
✓ Branch 9 taken 888 times.
|
4527 | subs := list(list(Subscript.INDEX(e) for e in RangeIterator.toList(RangeIterator.fromDim(d, resize))) for d in dims); |
| 1134 | 776 | outExp := expandGeneric2(subs, exp, ty); | |
| 1135 | else | ||
| 1136 | outExp := exp; | ||
| 1137 | end if; | ||
| 1138 | else | ||
| 1139 | outExp := exp; | ||
| 1140 | expanded := true; | ||
| 1141 | end if; | ||
| 1142 | end expandGeneric; | ||
| 1143 | |||
| 1144 | function expandGeneric2 | ||
| 1145 | input list<list<Subscript>> subs; | ||
| 1146 | input Expression exp; | ||
| 1147 | input Type ty; | ||
| 1148 | input list<Subscript> accum = {}; | ||
| 1149 | output Expression outExp; | ||
| 1150 | protected | ||
| 1151 | Type t; | ||
| 1152 | list<Subscript> sub; | ||
| 1153 | array<Expression> expl; | ||
| 1154 | list<list<Subscript>> rest_subs; | ||
| 1155 | Integer i; | ||
| 1156 | algorithm | ||
| 1157 | outExp := match subs | ||
| 1158 | case sub :: rest_subs | ||
| 1159 | algorithm | ||
| 1160 | 1139 | t := Type.unliftArray(ty); | |
| 1161 | 1139 | expl := arrayCreateNoInit(listLength(sub), exp); | |
| 1162 | i := 1; | ||
| 1163 | |||
| 1164 |
2/2✓ Branch 1 taken 3569 times.
✓ Branch 2 taken 1139 times.
|
4708 | for s in sub loop |
| 1165 | 3569 | arrayUpdateNoBoundsChecking(expl, i, | |
| 1166 | expandGeneric2(rest_subs, exp, t, s :: accum)); | ||
| 1167 | 3569 | i := i + 1; | |
| 1168 | end for; | ||
| 1169 | 1139 | then | |
| 1170 | Expression.makeArray(ty, expl); | ||
| 1171 | |||
| 1172 | case {} | ||
| 1173 | algorithm | ||
| 1174 | outExp := exp; | ||
| 1175 |
2/2✓ Branch 1 taken 4238 times.
✓ Branch 2 taken 3206 times.
|
7444 | for s in listReverse(accum) loop |
| 1176 | 4238 | outExp := Expression.applySubscript(s, outExp); | |
| 1177 | end for; | ||
| 1178 | then | ||
| 1179 | outExp; | ||
| 1180 | |||
| 1181 | end match; | ||
| 1182 | end expandGeneric2; | ||
| 1183 | |||
| 1184 | function expandCallArgs | ||
| 1185 | input output Expression exp; | ||
| 1186 | protected | ||
| 1187 | Call call; | ||
| 1188 | algorithm | ||
| 1189 | () := match exp | ||
| 1190 | case Expression.CALL(call = call as Call.TYPED_CALL()) | ||
| 1191 | algorithm | ||
| 1192 |
4/4✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
|
3 | call.arguments := list(expand(arg) for arg in call.arguments); |
| 1193 | 1 | exp.call := call; | |
| 1194 | then | ||
| 1195 | (); | ||
| 1196 | |||
| 1197 | else (); | ||
| 1198 | end match; | ||
| 1199 | end expandCallArgs; | ||
| 1200 | |||
| 1201 | annotation(__OpenModelica_Interface="nf_frontend"); | ||
| 1202 | end NFExpandExp; | ||
| 1203 |