OMCompiler/Compiler/NBackEnd/Util/NBSlice.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 NBSlice<T> | ||
| 37 | " file: NBSlice.mo | ||
| 38 | package: NBSlice | ||
| 39 | description: This file contains util functions for slicing operations. | ||
| 40 | " | ||
| 41 | |||
| 42 | protected | ||
| 43 | import Slice = NBSlice; | ||
| 44 | |||
| 45 | // NF imports | ||
| 46 | import Call = NFCall; | ||
| 47 | import ComplexType = NFComplexType; | ||
| 48 | import ComponentRef = NFComponentRef; | ||
| 49 | import Dimension = NFDimension; | ||
| 50 | import Expression = NFExpression; | ||
| 51 | import Operator = NFOperator; | ||
| 52 | import SimplifyExp = NFSimplifyExp; | ||
| 53 | import Subscript = NFSubscript; | ||
| 54 | import Type = NFType; | ||
| 55 | import NFPrefixes.Variability; | ||
| 56 | import Variable = NFVariable; | ||
| 57 | |||
| 58 | // NB imports | ||
| 59 | import NBAdjacency.{IntMatrix, Mapping, Mode, ModeTable, Modes, Dependency}; | ||
| 60 | import BackendUtil = NBBackendUtil; | ||
| 61 | import NBEquation.{Equation, Iterator, Frame, FrameLocation, RecollectStatus, FrameOrderingStatus}; | ||
| 62 | import Replacements = NBReplacements; | ||
| 63 | import BVariable = NBVariable; | ||
| 64 | import NBVariable.VariablePointers; | ||
| 65 | |||
| 66 | // Util imports | ||
| 67 | import List; | ||
| 68 | import UnorderedMap; | ||
| 69 | |||
| 70 | public | ||
| 71 | type IntLst = list<Integer>; | ||
| 72 | |||
| 73 | record SLICE | ||
| 74 | T t; | ||
| 75 | IntLst indices; | ||
| 76 | end SLICE; | ||
| 77 | |||
| 78 | // ############################################################ | ||
| 79 | // Member Functions | ||
| 80 | // ############################################################ | ||
| 81 | |||
| 82 | function getT | ||
| 83 | input Slice<T> slice; | ||
| 84 | output T t = slice.t; | ||
| 85 | end getT; | ||
| 86 | |||
| 87 | function hash | ||
| 88 | input Slice<T> slice; | ||
| 89 | input hashT func; | ||
| 90 | output Integer h = func(slice.t); | ||
| 91 | algorithm | ||
| 92 | // first index should be unique enough | ||
| 93 |
2/2✓ Branch 1 taken 78 times.
✓ Branch 2 taken 6457 times.
|
6535 | for i in List.firstOrEmpty(slice.indices) loop |
| 94 | 78 | h := stringHashDjb2Continue(intString(i), h); | |
| 95 | end for; | ||
| 96 | end hash; | ||
| 97 | |||
| 98 | function isEqual | ||
| 99 | input Slice<T> slice1; | ||
| 100 | input Slice<T> slice2; | ||
| 101 | input isEqualT func; | ||
| 102 | output Boolean b = func(slice1.t, slice2.t) and List.isEqualOnTrue(slice1.indices, slice2.indices, intEq); | ||
| 103 | end isEqual; | ||
| 104 | |||
| 105 | function toString | ||
| 106 | input Slice<T> slice; | ||
| 107 | input toStringT func; | ||
| 108 | input Integer maxLength = 10; | ||
| 109 | output String str; | ||
| 110 | algorithm | ||
| 111 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 27 times.
|
48 | str := func(slice.t); |
| 112 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
|
48 | if maxLength > 0 and not listEmpty(slice.indices) then |
| 113 | ✗ | str := str + "\n\tslice: " + List.toStringCustom(inList = slice.indices, inPrintFunc = intString, maxLength = maxLength); | |
| 114 | end if; | ||
| 115 | end toString; | ||
| 116 | |||
| 117 | function lstToString | ||
| 118 | input list<Slice<T>> lst; | ||
| 119 | input toStringT_ func; | ||
| 120 | input String indent = ""; | ||
| 121 | input Integer maxLength = 10; | ||
| 122 | partial function toStringT_ = toStringT "ugly hack to make type T known to subfunction"; | ||
| 123 | output String str = List.toStringCustom(lst, function toString(func = func, maxLength = maxLength), "", indent, "\n" + indent, "", false); | ||
| 124 | end lstToString; | ||
| 125 | |||
| 126 | function isFull | ||
| 127 | input Slice<T> slice; | ||
| 128 | output Boolean b = listEmpty(slice.indices); | ||
| 129 | end isFull; | ||
| 130 | |||
| 131 | function size | ||
| 132 | input Slice<T> slice; | ||
| 133 | input sizeT func; | ||
| 134 | output Integer s; | ||
| 135 | algorithm | ||
| 136 |
2/2✓ Branch 0 taken 120 times.
✓ Branch 1 taken 302 times.
|
422 | if listEmpty(slice.indices) then |
| 137 |
1/2✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
|
120 | s := func(slice.t); |
| 138 | else | ||
| 139 | 302 | s := listLength(slice.indices); | |
| 140 | end if; | ||
| 141 | end size; | ||
| 142 | |||
| 143 | function simplify | ||
| 144 | "only to be used for unordered purposes! | ||
| 145 | lists of all indices are meaningful if they are not in the natural ascending order | ||
| 146 | and can indicate range reversal in for loops." | ||
| 147 | input output Slice<T> slice; | ||
| 148 | input sizeT func; | ||
| 149 | algorithm | ||
| 150 |
3/4✓ Branch 1 taken 8234 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8160 times.
✓ Branch 6 taken 74 times.
|
8234 | if listLength(slice.indices) == func(slice.t) then |
| 151 | 8160 | slice.indices := {}; | |
| 152 | else | ||
| 153 | 74 | slice.indices := List.sort(slice.indices, intGt); | |
| 154 | end if; | ||
| 155 | end simplify; | ||
| 156 | |||
| 157 | function addToSliceMap | ||
| 158 | input T t; | ||
| 159 | input Integer i; | ||
| 160 | input UnorderedMap<T, IntLst> map; | ||
| 161 | algorithm | ||
| 162 | 37576 | UnorderedMap.add(t, i :: UnorderedMap.getOrDefault(t, map, {}), map); | |
| 163 | end addToSliceMap; | ||
| 164 | |||
| 165 | function fromTpl | ||
| 166 | input tuple<T, IntLst> tpl; | ||
| 167 | output Slice<T> slice; | ||
| 168 | protected | ||
| 169 | T t; | ||
| 170 | IntLst lst; | ||
| 171 | algorithm | ||
| 172 | 8234 | (t, lst) := tpl; | |
| 173 | 8234 | slice := SLICE(t, lst); | |
| 174 | end fromTpl; | ||
| 175 | |||
| 176 | function fromMap | ||
| 177 | input UnorderedMap<T, IntLst> map; | ||
| 178 | output list<Slice<T>> slices = list(fromTpl(tpl) for tpl in UnorderedMap.toList(map)); | ||
| 179 | end fromMap; | ||
| 180 | |||
| 181 | function apply | ||
| 182 | input output Slice<T> slice; | ||
| 183 | input applyT func; | ||
| 184 | algorithm | ||
| 185 |
1/2✓ Branch 0 taken 1849 times.
✗ Branch 1 not taken.
|
1849 | slice.t := func(slice.t); |
| 186 | end apply; | ||
| 187 | |||
| 188 | function applyMutable | ||
| 189 | input Slice<T> slice; | ||
| 190 | input applyMutableT func; | ||
| 191 | algorithm | ||
| 192 |
1/2✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
|
276 | func(slice.t); |
| 193 | end applyMutable; | ||
| 194 | |||
| 195 | function check<T2> | ||
| 196 | input Slice<T> slice; | ||
| 197 | input checkT func; | ||
| 198 | output T2 t2 = func(slice.t); | ||
| 199 | end check; | ||
| 200 | |||
| 201 | // ############################################################ | ||
| 202 | // Partial Functions | ||
| 203 | // ############################################################ | ||
| 204 | |||
| 205 | partial function toStringT | ||
| 206 | input T t; | ||
| 207 | output String str; | ||
| 208 | end toStringT; | ||
| 209 | |||
| 210 | partial function sizeT | ||
| 211 | input T t; | ||
| 212 | output Integer s; | ||
| 213 | end sizeT; | ||
| 214 | |||
| 215 | partial function hashT | ||
| 216 | input T t; | ||
| 217 | output Integer i; | ||
| 218 | end hashT; | ||
| 219 | |||
| 220 | partial function isEqualT | ||
| 221 | input T t1; | ||
| 222 | input T t2; | ||
| 223 | output Boolean b; | ||
| 224 | end isEqualT; | ||
| 225 | |||
| 226 | partial function applyT | ||
| 227 | input output T t; | ||
| 228 | end applyT; | ||
| 229 | |||
| 230 | partial function applyMutableT | ||
| 231 | input T t; | ||
| 232 | end applyMutableT; | ||
| 233 | |||
| 234 | partial function checkT<T2> | ||
| 235 | input T t; | ||
| 236 | output T2 t2; | ||
| 237 | end checkT; | ||
| 238 | |||
| 239 | partial function filterCref | ||
| 240 | "partial function that needs to be provided. | ||
| 241 | decides if the the cref is added to the list pointer." | ||
| 242 | input output ComponentRef cref; | ||
| 243 | input UnorderedSet<ComponentRef> acc; | ||
| 244 | end filterCref; | ||
| 245 | |||
| 246 | partial function getDependentCrefIndices | ||
| 247 | input list<ComponentRef> dependencies "dependent var crefs"; | ||
| 248 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 249 | input Mapping mapping "array <-> scalar index mapping"; | ||
| 250 | input Integer eqn_arr_idx; | ||
| 251 | output array<list<Integer>> indices; | ||
| 252 | output array<array<Integer>> mode_to_var; | ||
| 253 | end getDependentCrefIndices; | ||
| 254 | |||
| 255 | // ############################################################ | ||
| 256 | // cref accumulation Functions | ||
| 257 | // use with: | ||
| 258 | // Equation.collectCrefs() | ||
| 259 | // filterExp() | ||
| 260 | // ############################################################ | ||
| 261 | |||
| 262 | function filterExp | ||
| 263 | "wrapper function that applies filter cref to | ||
| 264 | a cref expression." | ||
| 265 | input output Expression exp; | ||
| 266 | input filterCref filter; | ||
| 267 | input UnorderedSet<ComponentRef> acc; | ||
| 268 | algorithm | ||
| 269 | () := match exp | ||
| 270 | local | ||
| 271 | Expression call_exp; | ||
| 272 | Call call; | ||
| 273 | |||
| 274 |
2/2✓ Branch 0 taken 26939 times.
✓ Branch 1 taken 507 times.
|
27446 | case Expression.CREF() algorithm filter(exp.cref, acc); then (); |
| 275 | case Expression.CALL(call = call as Call.TYPED_REDUCTION(exp = call_exp)) algorithm | ||
| 276 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
|
18 | for iter in call.iters loop |
| 277 | 9 | call_exp := Expression.replaceIterator(call_exp, Util.tuple21(iter), Util.tuple22(iter)); | |
| 278 | end for; | ||
| 279 | 9 | Expression.mapShallow(call_exp, function filterExp(filter = filter, acc = acc)); | |
| 280 | then (); | ||
| 281 | |||
| 282 | else algorithm | ||
| 283 | 31958 | Expression.mapShallow(exp, function filterExp(filter = filter, acc = acc)); | |
| 284 | then (); | ||
| 285 | end match; | ||
| 286 | end filterExp; | ||
| 287 | |||
| 288 | function getContinuous | ||
| 289 | extends filterCref; | ||
| 290 | input Boolean init; | ||
| 291 | algorithm | ||
| 292 |
3/4✓ Branch 0 taken 189 times.
✗ Branch 1 not taken.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 183 times.
|
378 | if BVariable.checkCref(cref, function BVariable.isContinuous(staticAsContinuous = init), sourceInfo()) then |
| 293 | 183 | UnorderedSet.add(cref, acc); | |
| 294 | end if; | ||
| 295 | end getContinuous; | ||
| 296 | |||
| 297 | function getSliceCandidates | ||
| 298 | "Used to collect all slices of a certain variable name. | ||
| 299 | Note: the name has to be stripped of all subscripts for this to work." | ||
| 300 | extends filterCref; | ||
| 301 | input ComponentRef name "the name of the variable"; | ||
| 302 | protected | ||
| 303 | ComponentRef checkCref = ComponentRef.stripSubscriptsAll(cref); | ||
| 304 | algorithm | ||
| 305 | // check if the cref, the stripped version or the record parent are equal | ||
| 306 |
5/6✓ Branch 1 taken 23017 times.
✓ Branch 2 taken 2748 times.
✓ Branch 4 taken 21903 times.
✓ Branch 5 taken 1114 times.
✓ Branch 7 taken 21903 times.
✗ Branch 8 not taken.
|
25765 | if ComponentRef.isEqual(name, checkCref) or ComponentRef.isEqual(name, cref) or ComponentRef.isEqualRecordChild(name, checkCref) then |
| 307 | 3862 | UnorderedSet.add(cref, acc); | |
| 308 | end if; | ||
| 309 | end getSliceCandidates; | ||
| 310 | |||
| 311 | function resolveSlicedCref | ||
| 312 | "finds the cref referencing base_cref's variable inside eqn whose subscripted size | ||
| 313 | matches target_size, e.g. picking i_s[{1, 2}] (size 2) out from a co-occurring whole | ||
| 314 | reference i_s (size 3) in the same equation. Falls back to base_cref if no unique | ||
| 315 | match is found." | ||
| 316 | input ComponentRef base_cref "variable name, stripped of subscripts"; | ||
| 317 | input Equation eqn; | ||
| 318 | input Integer target_size; | ||
| 319 | output ComponentRef cref = base_cref; | ||
| 320 | protected | ||
| 321 | list<ComponentRef> candidates, filtered; | ||
| 322 | algorithm | ||
| 323 | ✗ | if target_size > 0 then | |
| 324 | ✗ | candidates := Equation.collectCrefs(eqn, function getSliceCandidates(name = base_cref)); | |
| 325 | ✗ | filtered := list(c for c guard(Type.sizeOf(ComponentRef.getSubscriptedType(c), true) == target_size) in candidates); | |
| 326 | ✗ | if List.hasOneElement(filtered) then | |
| 327 | ✗ | cref := listHead(filtered); | |
| 328 | end if; | ||
| 329 | end if; | ||
| 330 | end resolveSlicedCref; | ||
| 331 | |||
| 332 | function getDependentCref | ||
| 333 | "checks if crefs are relevant in the given context and collects them." | ||
| 334 | extends filterCref; | ||
| 335 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 336 | input Boolean pseudo; | ||
| 337 | protected | ||
| 338 | ComponentRef checkCref, childCref; | ||
| 339 | list<Pointer<Variable>> record_children; | ||
| 340 | algorithm | ||
| 341 | // if causalized in pseudo array mode, the variables will only have subscript-free variables | ||
| 342 |
1/2✓ Branch 0 taken 1781 times.
✗ Branch 1 not taken.
|
1781 | checkCref := if pseudo then ComponentRef.stripSubscriptsAll(cref) else cref; |
| 343 | 1781 | record_children := BVariable.getRecordChildren(BVariable.getVarPointer(checkCref, sourceInfo())); | |
| 344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1781 times.
|
1781 | if listEmpty(record_children) then |
| 345 | // not a record | ||
| 346 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1781 times.
|
1781 | if UnorderedMap.contains(checkCref, map) then |
| 347 | ✗ | UnorderedSet.add(cref, acc); | |
| 348 | end if; | ||
| 349 | else | ||
| 350 | // its a record, instead parse all the children | ||
| 351 | ✗ | for child in record_children loop | |
| 352 | ✗ | childCref := BVariable.getVarName(child); | |
| 353 | ✗ | if UnorderedMap.contains(childCref, map) then | |
| 354 | ✗ | UnorderedSet.add(childCref, acc); | |
| 355 | end if; | ||
| 356 | end for; | ||
| 357 | end if; | ||
| 358 | end getDependentCref; | ||
| 359 | |||
| 360 | function getDependentCrefCausalized | ||
| 361 | "checks if crefs are relevant in the given context and collects them. | ||
| 362 | previously found crefs are replaced by their dependencies! only works on causalized systems." | ||
| 363 | extends filterCref; | ||
| 364 | input UnorderedSet<ComponentRef> set "unordered set to check for array crefs for relevance"; | ||
| 365 | protected | ||
| 366 | ComponentRef checkCref, childCref; | ||
| 367 | list<Pointer<Variable>> record_children; | ||
| 368 | algorithm | ||
| 369 | // always remove subscripts here, this analysis is for sparsity pattern -> currently always scalarized! | ||
| 370 | ✗ | checkCref := ComponentRef.stripSubscriptsAll(cref); | |
| 371 | ✗ | record_children := BVariable.getRecordChildren(BVariable.getVarPointer(checkCref, sourceInfo())); | |
| 372 | ✗ | if listEmpty(record_children) then | |
| 373 | // not a record | ||
| 374 | ✗ | if UnorderedSet.contains(checkCref, set) then | |
| 375 | ✗ | UnorderedSet.add(cref, acc); | |
| 376 | end if; | ||
| 377 | else | ||
| 378 | // its a record, instead parse all the children | ||
| 379 | ✗ | for child in record_children loop | |
| 380 | ✗ | childCref := BVariable.getVarName(child); | |
| 381 | ✗ | if UnorderedSet.contains(childCref, set) then | |
| 382 | ✗ | UnorderedSet.add(childCref, acc); | |
| 383 | end if; | ||
| 384 | end for; | ||
| 385 | end if; | ||
| 386 | end getDependentCrefCausalized; | ||
| 387 | |||
| 388 | function getUnsolvableExpCrefs | ||
| 389 | "finds all unsolvable crefs in an expression." | ||
| 390 | input output Expression exp "the exp to check for unsolvable crefs"; | ||
| 391 | input UnorderedSet<ComponentRef> acc "accumulator for relevant crefs"; | ||
| 392 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 393 | input Boolean pseudo; | ||
| 394 | algorithm | ||
| 395 | // put all unsolvable logic here! | ||
| 396 | exp := match exp | ||
| 397 | ✗ | case Expression.RANGE() then Expression.mapShallow(exp, function filterExp(filter = function getDependentCref(map = map, pseudo = pseudo), acc = acc)); | |
| 398 | ✗ | case Expression.LBINARY() then Expression.mapShallow(exp, function filterExp(filter = function getDependentCref(map = map, pseudo = pseudo), acc = acc)); | |
| 399 | ✗ | case Expression.RELATION() then Expression.mapShallow(exp, function filterExp(filter = function getDependentCref(map = map, pseudo = pseudo), acc = acc)); | |
| 400 | else exp; | ||
| 401 | end match; | ||
| 402 | end getUnsolvableExpCrefs; | ||
| 403 | |||
| 404 | function getDependentCrefIndicesPseudoScalar | ||
| 405 | "Scalar equations. | ||
| 406 | Turns cref dependencies into index lists, used for adjacency." | ||
| 407 | input list<ComponentRef> dependencies "dependent var crefs"; | ||
| 408 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 409 | input Mapping mapping "array <-> scalar index mapping"; | ||
| 410 | output list<Integer> indices = {}; | ||
| 411 | protected | ||
| 412 | list<ComponentRef> scalarized_dependencies = List.flatten(list(ComponentRef.scalarizeAll(dep, true) for dep in dependencies)); | ||
| 413 | ComponentRef stripped; | ||
| 414 | Integer var_arr_idx, var_start, var_scal_idx; | ||
| 415 | list<Integer> sizes, int_subs; | ||
| 416 | algorithm | ||
| 417 | ✗ | for cref in scalarized_dependencies loop | |
| 418 | ✗ | stripped := ComponentRef.stripSubscriptsAll(cref); | |
| 419 | ✗ | var_arr_idx := UnorderedMap.getSafe(stripped, map, sourceInfo()); | |
| 420 | ✗ | (var_start, _) := mapping.var_AtS[var_arr_idx]; | |
| 421 | // the sizes of the scalarization (resized, like the mapping) | ||
| 422 | ✗ | sizes := ComponentRef.sizes(stripped, false, true); | |
| 423 | ✗ | int_subs := ComponentRef.subscriptsToInteger(cref); | |
| 424 | ✗ | var_scal_idx := locationToIndex(sizes, int_subs, var_start); | |
| 425 | indices := var_scal_idx :: indices; | ||
| 426 | end for; | ||
| 427 | // remove duplicates and sort | ||
| 428 | ✗ | if not listEmpty(indices) then | |
| 429 | ✗ | indices := List.sort(List.uniqueIntN(indices, max(i for i in indices)), intLt); | |
| 430 | end if; | ||
| 431 | end getDependentCrefIndicesPseudoScalar; | ||
| 432 | |||
| 433 | function getDependentCrefIndicesPseudoFull | ||
| 434 | "equations that will get full dependency. | ||
| 435 | Turns cref dependencies into index lists, used for adjacency." | ||
| 436 | extends getDependentCrefIndices; | ||
| 437 | protected | ||
| 438 | list<ComponentRef> scalarized_dependencies = List.flatten(list(ComponentRef.scalarizeAll(dep, true) for dep in dependencies)); | ||
| 439 | ComponentRef stripped; | ||
| 440 | Integer eqn_start, eqn_size, var_arr_idx, var_scal_idx, mode = 1; | ||
| 441 | list<Integer> scal_lst; | ||
| 442 | Integer idx; | ||
| 443 | array<Integer> mode_to_var_row; | ||
| 444 | list<Subscript> subs; | ||
| 445 | list<Dimension> dims; | ||
| 446 | Type ty; | ||
| 447 | algorithm | ||
| 448 | ✗ | (eqn_start, eqn_size) := mapping.eqn_AtS[eqn_arr_idx]; | |
| 449 | ✗ | indices := arrayCreate(eqn_size, {}); | |
| 450 | ✗ | mode_to_var := arrayCreate(eqn_size, arrayCreate(0,0)); | |
| 451 | // create unique array for each equation | ||
| 452 | ✗ | for i in 1:eqn_size loop | |
| 453 | ✗ | mode_to_var[i] := arrayCreate(listLength(scalarized_dependencies),-1); | |
| 454 | end for; | ||
| 455 | ✗ | for cref in scalarized_dependencies loop | |
| 456 | ✗ | stripped := ComponentRef.stripSubscriptsAll(cref); | |
| 457 | ✗ | var_arr_idx := UnorderedMap.getSafe(stripped, map, sourceInfo()); | |
| 458 | |||
| 459 | // build range in reverse, it will be flipped anyway | ||
| 460 | ✗ | subs := ComponentRef.subscriptsAllWithWholeFlat(cref); | |
| 461 | ✗ | ty := ComponentRef.getSubscriptedType(stripped, true); | |
| 462 | ✗ | dims := Type.arrayDims(ty); | |
| 463 | ✗ | scal_lst := Mapping.getVarScalIndices(var_arr_idx, mapping, subs, dims, true); | |
| 464 | |||
| 465 | ✗ | if intMod(eqn_size, listLength(scal_lst)) <> 0 then | |
| 466 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() | |
| 467 | + " failed because flattened indices " + intString(listLength(scal_lst)) | ||
| 468 | + " could not be repeated to fit equation size " + intString(eqn_size) + ". lst: " + List.toString(scal_lst, intString)}); | ||
| 469 | ✗ | fail(); | |
| 470 | else | ||
| 471 | // fill the equation with repeated scalar lists | ||
| 472 | ✗ | scal_lst := List.repeat(scal_lst, intDiv(eqn_size, listLength(scal_lst))); | |
| 473 | end if; | ||
| 474 | |||
| 475 | idx := 1; | ||
| 476 | ✗ | for var_scal_idx in listReverse(scal_lst) loop | |
| 477 | ✗ | mode_to_var_row := mode_to_var[idx]; | |
| 478 | ✗ | arrayUpdate(mode_to_var_row, mode, var_scal_idx); | |
| 479 | ✗ | arrayUpdate(mode_to_var, idx, mode_to_var_row); | |
| 480 | ✗ | indices[idx] := var_scal_idx :: indices[idx]; | |
| 481 | ✗ | idx := idx + 1; | |
| 482 | end for; | ||
| 483 | ✗ | mode := mode + 1; | |
| 484 | end for; | ||
| 485 | |||
| 486 | // sort | ||
| 487 | ✗ | for i in 1:arrayLength(indices) loop | |
| 488 | ✗ | indices[i] := List.sort(UnorderedSet.unique_list(indices[i], Util.id, intEq), intLt); | |
| 489 | end for; | ||
| 490 | end getDependentCrefIndicesPseudoFull; | ||
| 491 | |||
| 492 | function getDependentCrefIndicesPseudoFor | ||
| 493 | "For-Loop equations. | ||
| 494 | Turns cref dependencies into index lists, used for adjacency." | ||
| 495 | extends getDependentCrefIndices; | ||
| 496 | input Iterator iter "iterator frames"; | ||
| 497 | protected | ||
| 498 | list<ComponentRef> names; | ||
| 499 | list<Expression> ranges; | ||
| 500 | list<Option<Iterator>> maps; | ||
| 501 | list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 502 | Integer eqn_size, iter_size, body_size, mode = 1; | ||
| 503 | updateDependencies func; | ||
| 504 | algorithm | ||
| 505 | // get iterator size and frames | ||
| 506 | ✗ | iter_size := Iterator.size(iter); | |
| 507 | ✗ | (names, ranges, maps) := Iterator.getFrames(iter); | |
| 508 | ✗ | frames := List.zip3(names, ranges, maps); | |
| 509 | |||
| 510 | // get eqn size and create the adjacency matrix and causalization mode arrays | ||
| 511 | ✗ | (_, eqn_size) := mapping.eqn_AtS[eqn_arr_idx]; | |
| 512 | ✗ | indices := arrayCreate(eqn_size, {}); | |
| 513 | ✗ | mode_to_var := arrayCreate(eqn_size, arrayCreate(0,0)); | |
| 514 | |||
| 515 | // sanity check for eqn size and get size of body equation | ||
| 516 | ✗ | if mod(eqn_size, iter_size) == 0 then | |
| 517 | ✗ | body_size := intDiv(eqn_size, iter_size); | |
| 518 | else | ||
| 519 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() | |
| 520 | + " failed because the equation size " + intString(eqn_size) | ||
| 521 | + " could not be divided by the iterator size " + intString(iter_size) + " without rest."}); | ||
| 522 | ✗ | fail(); | |
| 523 | end if; | ||
| 524 | |||
| 525 | // create unique array for each equation | ||
| 526 | ✗ | for i in 1:eqn_size loop | |
| 527 | ✗ | mode_to_var[i] := arrayCreate(listLength(dependencies),-1); | |
| 528 | end for; | ||
| 529 | |||
| 530 | // create rows | ||
| 531 | ✗ | for dep in dependencies loop | |
| 532 | ✗ | func := function updateDependenciesInteger(mode = mode, mode_to_var = mode_to_var, indices = indices); | |
| 533 | // var_arr_idx not needed for this | ||
| 534 | ✗ | fillDependencyArray(dep, body_size, frames, mapping, map, func, 0, true); | |
| 535 | // increase mode index | ||
| 536 | ✗ | mode := mode + 1; | |
| 537 | end for; | ||
| 538 | |||
| 539 | // sort (kabdelhak: is this needed? try to FixMe) | ||
| 540 | ✗ | for i in 1:arrayLength(indices) loop | |
| 541 | ✗ | indices[i] := List.sort(UnorderedSet.unique_list(indices[i], Util.id, intEq), intLt); | |
| 542 | end for; | ||
| 543 | end getDependentCrefIndicesPseudoFor; | ||
| 544 | |||
| 545 | function getDependentCrefsPseudoForCausalized | ||
| 546 | "(Jacobian) For-Loop equations. | ||
| 547 | Turns cref dependencies into index lists, used for adjacency." | ||
| 548 | input ComponentRef row_cref "cref representing the current row"; | ||
| 549 | input list<ComponentRef> dependencies "dependent var crefs"; | ||
| 550 | input VariablePointers var_rep "scalarized variable representatives"; | ||
| 551 | input VariablePointers eqn_rep "scalarized equation representatives"; | ||
| 552 | input Mapping var_rep_mapping "index mapping for variable representatives"; | ||
| 553 | input Mapping eqn_rep_mapping "index mapping for equation representatives"; | ||
| 554 | input Iterator iter "iterator frames"; | ||
| 555 | input Integer eqn_size "full equation size (not considering the slice)"; | ||
| 556 | input list<Integer> slice = {} "optional slice, empty list implies full slice"; | ||
| 557 | input Boolean implicit = false "do not compute row cref indices if implicit"; | ||
| 558 | output list<tuple<ComponentRef, list<ComponentRef>>> tpl_lst "cref -> dependencies for each scalar cref"; | ||
| 559 | protected | ||
| 560 | list<ComponentRef> names; | ||
| 561 | list<Expression> ranges; | ||
| 562 | list<Option<Iterator>> maps; | ||
| 563 | list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 564 | |||
| 565 | Integer iter_size, body_size, var_arr_idx; | ||
| 566 | list<ComponentRef> row_crefs; | ||
| 567 | list<Integer> row_scal_lst; | ||
| 568 | list<list<Integer>> accum_row_lst = {}; | ||
| 569 | array<list<ComponentRef>> accum_dep_arr; | ||
| 570 | list<list<ComponentRef>> accum_dep_lst; | ||
| 571 | updateDependencies func_var, func_eqn; | ||
| 572 | ComponentRef final_dep; | ||
| 573 | algorithm | ||
| 574 | // create the array of maximum equation size and slice afterwards | ||
| 575 | ✗ | accum_dep_arr := arrayCreate(eqn_size, {}); | |
| 576 | |||
| 577 | // get iterator size and frames | ||
| 578 | ✗ | iter_size := Iterator.size(iter); | |
| 579 | ✗ | (names, ranges, maps) := Iterator.getFrames(iter); | |
| 580 | ✗ | frames := List.zip3(names, ranges, maps); | |
| 581 | |||
| 582 | // sanity check for eqn size and get size of body equation | ||
| 583 | ✗ | if mod(eqn_size, iter_size) == 0 then | |
| 584 | ✗ | body_size := intDiv(eqn_size, iter_size); | |
| 585 | else | ||
| 586 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() | |
| 587 | + " failed because the equation size " + intString(eqn_size) | ||
| 588 | + " could not be divided by the iterator size " + intString(iter_size) + " without rest."}); | ||
| 589 | ✗ | fail(); | |
| 590 | end if; | ||
| 591 | |||
| 592 | // get row cref lst | ||
| 593 | ✗ | if implicit then | |
| 594 | ✗ | row_crefs := ComponentRef.scalarizeSlice(row_cref, slice, false); | |
| 595 | else | ||
| 596 | ✗ | for cref in ComponentRef.scalarizeAll(row_cref, false) loop | |
| 597 | ✗ | row_scal_lst := getCrefInFrameIndices(cref, frames, eqn_rep_mapping, eqn_rep.map, false); | |
| 598 | accum_row_lst := row_scal_lst :: accum_row_lst; | ||
| 599 | end for; | ||
| 600 | ✗ | row_scal_lst := List.flatten(accum_row_lst); | |
| 601 | ✗ | row_scal_lst := if listEmpty(slice) or listLength(slice) > listLength(row_scal_lst) then row_scal_lst else List.getAtIndexLst(row_scal_lst, slice, true); | |
| 602 | ✗ | row_crefs := list(VariablePointers.varSlice(eqn_rep, i, eqn_rep_mapping.var_StA[i], eqn_rep_mapping, false) for i in row_scal_lst); | |
| 603 | end if; | ||
| 604 | |||
| 605 | // prepare the functions to update dependencies | ||
| 606 | ✗ | func_var := function updateDependenciesCref(accum_dep_arr = accum_dep_arr, vars = var_rep, mapping = var_rep_mapping, resize = false); | |
| 607 | ✗ | func_eqn := function updateDependenciesCref(accum_dep_arr = accum_dep_arr, vars = eqn_rep, mapping = eqn_rep_mapping, resize = false); | |
| 608 | |||
| 609 | ✗ | for dep in dependencies loop | |
| 610 | ✗ | if UnorderedMap.contains(dep, var_rep.map) then | |
| 611 | ✗ | (final_dep, var_arr_idx) := getVarArrIdx(dep, var_rep_mapping, var_rep.map); | |
| 612 | ✗ | fillDependencyArray(final_dep, body_size, frames, var_rep_mapping, var_rep.map, func_var, var_arr_idx, false); | |
| 613 | elseif UnorderedMap.contains(dep, eqn_rep.map) then | ||
| 614 | ✗ | (final_dep, var_arr_idx) := getVarArrIdx(dep, eqn_rep_mapping, eqn_rep.map); | |
| 615 | ✗ | fillDependencyArray(final_dep, body_size, frames, eqn_rep_mapping, eqn_rep.map, func_eqn, var_arr_idx, false); | |
| 616 | end if; | ||
| 617 | end for; | ||
| 618 | |||
| 619 | ✗ | accum_dep_lst := listReverse(arrayList(accum_dep_arr)); | |
| 620 | ✗ | accum_dep_lst := if listEmpty(slice) or listLength(slice) > listLength(accum_dep_lst) then accum_dep_lst else List.getAtIndexLst(accum_dep_lst, slice, true); | |
| 621 | |||
| 622 | ✗ | tpl_lst := List.zip(row_crefs, accum_dep_lst); | |
| 623 | end getDependentCrefsPseudoForCausalized; | ||
| 624 | |||
| 625 | function fillDependencyArray | ||
| 626 | "body function of getDependentCrefsPseudoFor and getDependentCrefsPseudoForCausalized | ||
| 627 | this generates all entries to jacobian or adjacency matrices for a specific dependency. | ||
| 628 | This dependency might be an array cref, part of a reduction or contain slices." | ||
| 629 | input ComponentRef dep; | ||
| 630 | input Integer body_size; | ||
| 631 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 632 | input Mapping mapping; | ||
| 633 | input UnorderedMap<ComponentRef, Integer> map; | ||
| 634 | input updateDependencies func; | ||
| 635 | input Integer var_arr_idx; | ||
| 636 | input Boolean resize; | ||
| 637 | protected | ||
| 638 | ComponentRef scal_cref; | ||
| 639 | Integer scal_length, body_repeat, element_repeat, eqn_idx; | ||
| 640 | list<Integer> scal_lst; | ||
| 641 | list<tuple<ComponentRef, list<Integer>>> scal_tpl_lst = {}; | ||
| 642 | algorithm | ||
| 643 | // get all dependencies for each scalarized cref | ||
| 644 | // Note: scalarization does not remove the iterators, therefore it can still yield | ||
| 645 | // multiple scalar indices when evaluated along the iterator frames | ||
| 646 | ✗ | for scal_cref in ComponentRef.scalarizeAll(dep, true) loop | |
| 647 | ✗ | scal_lst := getCrefInFrameIndices(scal_cref, frames, mapping, map, resize); | |
| 648 | ✗ | scal_tpl_lst := (scal_cref, scal_lst) :: scal_tpl_lst; | |
| 649 | end for; | ||
| 650 | |||
| 651 | // check wether or not the element has to be repeated to fit the body | ||
| 652 | ✗ | scal_length := listLength(scal_tpl_lst); | |
| 653 | ✗ | if mod(scal_length, body_size) == 0 then | |
| 654 | // body has to be repeated | ||
| 655 | ✗ | body_repeat := intDiv(scal_length, body_size); | |
| 656 | element_repeat := 1; | ||
| 657 | elseif mod(body_size, scal_length) == 0 then | ||
| 658 | // element has to be repeated | ||
| 659 | body_repeat := 1; | ||
| 660 | ✗ | element_repeat := intDiv(body_size, scal_length); | |
| 661 | else | ||
| 662 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() | |
| 663 | + " failed because number of flattened indices " + intString(scal_length) | ||
| 664 | + " for dependency " + ComponentRef.toString(dep) | ||
| 665 | + " could not be divided by or repeated to fit the body size " + intString(body_size) + " without rest."}); | ||
| 666 | ✗ | fail(); | |
| 667 | end if; | ||
| 668 | |||
| 669 | eqn_idx := 1; | ||
| 670 | // repeat the elements to fit the equation | ||
| 671 | ✗ | for i in 1:element_repeat loop | |
| 672 | ✗ | for tpl in listReverse(scal_tpl_lst) loop | |
| 673 | ✗ | (scal_cref, scal_lst) := tpl; | |
| 674 | |||
| 675 | // reverse the scalar index list to traverse it in the correct order | ||
| 676 | ✗ | scal_lst := listReverse(scal_lst); | |
| 677 | |||
| 678 | // check if body_repeat > 1 to set the causalization mode to -1 for unsolvable | ||
| 679 | ✗ | if body_repeat > 1 then | |
| 680 | // reset the counter to 1 if the body is supposed to be repeated | ||
| 681 | // ToDo: reductions are only tested for body equations of size 1! | ||
| 682 | eqn_idx := 1; | ||
| 683 | end if; | ||
| 684 | |||
| 685 | ✗ | for var_idx in scal_lst loop | |
| 686 | // we now know that there is a dependency of equation (eqn_idx) to variable (var_idx) | ||
| 687 | // call the function that adds this specific variable to the correct structure | ||
| 688 | ✗ | if var_idx > 0 then | |
| 689 | ✗ | eqn_idx := func(eqn_idx, var_idx, var_arr_idx); | |
| 690 | end if; | ||
| 691 | end for; | ||
| 692 | end for; | ||
| 693 | end for; | ||
| 694 | end fillDependencyArray; | ||
| 695 | |||
| 696 | partial function updateDependencies | ||
| 697 | input output Integer eqn_idx; | ||
| 698 | input Integer var_idx; | ||
| 699 | input Integer var_arr_idx; | ||
| 700 | end updateDependencies; | ||
| 701 | |||
| 702 | function updateDependenciesCref | ||
| 703 | "(jacobian) adds the variable of (var_idx) as a dependency to (eqn_idx) | ||
| 704 | jacobian depencies are stored as component references" | ||
| 705 | extends updateDependencies; | ||
| 706 | input array<list<ComponentRef>> accum_dep_arr; | ||
| 707 | input VariablePointers vars; | ||
| 708 | input Mapping mapping; | ||
| 709 | input Boolean resize; | ||
| 710 | algorithm | ||
| 711 | ✗ | arrayUpdate(accum_dep_arr, eqn_idx, VariablePointers.varSlice(vars, var_idx, var_arr_idx, mapping, resize) :: accum_dep_arr[eqn_idx]); | |
| 712 | ✗ | eqn_idx := eqn_idx + 1; | |
| 713 | end updateDependenciesCref; | ||
| 714 | |||
| 715 | function updateDependenciesInteger | ||
| 716 | "(adjacency) adds the variable of (var_idx) as a dependency to (eqn_idx) | ||
| 717 | adjacency dependencies are stored as integers | ||
| 718 | also updates the causalization modes" | ||
| 719 | extends updateDependencies; | ||
| 720 | input Integer mode; | ||
| 721 | input array<array<Integer>> mode_to_var; //mutable | ||
| 722 | input array<list<Integer>> indices; //mutable | ||
| 723 | protected | ||
| 724 | array<Integer> mode_to_var_row; | ||
| 725 | algorithm | ||
| 726 | // get the clean pointer to the scalar row to avoid double indexing (meta modelica jank) | ||
| 727 | ✗ | mode_to_var_row := mode_to_var[eqn_idx]; | |
| 728 | // set the dependency mode for this scalar equation to the scalar variable | ||
| 729 | ✗ | arrayUpdate(mode_to_var_row, mode, var_idx); | |
| 730 | // this is the adjacency matrix row. each dependency cref | ||
| 731 | // will add exactly one integer to each row belonging to this for-equation | ||
| 732 | ✗ | arrayUpdate(indices, eqn_idx, var_idx :: indices[eqn_idx]); | |
| 733 | ✗ | eqn_idx := eqn_idx + 1; | |
| 734 | end updateDependenciesInteger; | ||
| 735 | |||
| 736 | function getDependentCrefsPseudoArrayCausalized | ||
| 737 | "Array equations. | ||
| 738 | Turns cref dependencies into index lists, used for adjacency." | ||
| 739 | input ComponentRef row_cref "cref representing the current row"; | ||
| 740 | input list<ComponentRef> dependencies "dependent var crefs"; | ||
| 741 | input list<Integer> slice = {} "optional slice, empty list means all"; | ||
| 742 | output list<tuple<ComponentRef, list<ComponentRef>>> tpl_lst "cref -> dependencies for each scalar cref"; | ||
| 743 | protected | ||
| 744 | list<ComponentRef> row_cref_scal, dependencies_resizable; | ||
| 745 | Integer row_size; | ||
| 746 | list<list<ComponentRef>> dependencies_scal; | ||
| 747 | Pointer<list<ComponentRef>> full_deps = Pointer.create({}); | ||
| 748 | function fixSingleDep | ||
| 749 | "helper function to properly add a single dependency" | ||
| 750 | input Integer row_size; | ||
| 751 | input output list<ComponentRef> single_dep; | ||
| 752 | input Pointer<list<ComponentRef>> full_deps; | ||
| 753 | protected | ||
| 754 | Integer dep_size = listLength(single_dep); | ||
| 755 | algorithm | ||
| 756 | ✗ | if row_size > dep_size then | |
| 757 | // repeat the element until it fits | ||
| 758 | ✗ | if intMod(row_size, dep_size) == 0 then | |
| 759 | ✗ | single_dep := List.repeat(single_dep, intDiv(row_size, dep_size)); | |
| 760 | else | ||
| 761 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because dependencies of size " + intString(dep_size) | |
| 762 | + " could not be repeated to fit row size " + intString(row_size) + "."}); | ||
| 763 | ✗ | fail(); | |
| 764 | end if; | ||
| 765 | elseif row_size < dep_size then | ||
| 766 | // assume full dependency (not entirely correct but practical) | ||
| 767 | ✗ | Pointer.update(full_deps, listAppend(single_dep, Pointer.access(full_deps))); | |
| 768 | single_dep := {}; | ||
| 769 | end if; | ||
| 770 | end fixSingleDep; | ||
| 771 | algorithm | ||
| 772 | ✗ | row_cref_scal := ComponentRef.scalarizeSlice(row_cref, slice, false); | |
| 773 | ✗ | row_size := listLength(row_cref_scal); | |
| 774 | |||
| 775 | ✗ | dependencies_resizable := list(ComponentRef.simplifySubscripts(ComponentRef.mapExp(dep, Expression.replaceResizableParameterWithOriginal)) for dep in dependencies); | |
| 776 | ✗ | dependencies_scal := list(ComponentRef.scalarizeSlice(dep, slice, false) for dep in dependencies_resizable); | |
| 777 | |||
| 778 | ✗ | if not listEmpty(dependencies_scal) then | |
| 779 | // repeat lists that are too short to fit the equation size and collect full dependencies | ||
| 780 | ✗ | dependencies_scal := list(fixSingleDep(row_size, d, full_deps) for d in dependencies_scal); | |
| 781 | ✗ | dependencies_scal := list(d for d guard(not listEmpty(d)) in dependencies_scal); | |
| 782 | // transpose it such that each list now represents one row | ||
| 783 | ✗ | if listEmpty(dependencies_scal) then | |
| 784 | ✗ | dependencies_scal := List.fill(Pointer.access(full_deps), row_size); | |
| 785 | else | ||
| 786 | ✗ | dependencies_scal := list(listAppend(Pointer.access(full_deps), d) for d in List.transposeList(dependencies_scal)); | |
| 787 | end if; | ||
| 788 | ✗ | tpl_lst := List.zip(row_cref_scal, dependencies_scal); | |
| 789 | else | ||
| 790 | ✗ | tpl_lst := list((cref, {}) for cref in row_cref_scal); | |
| 791 | end if; | ||
| 792 | end getDependentCrefsPseudoArrayCausalized; | ||
| 793 | |||
| 794 | function locationToIndex | ||
| 795 | "reverse function to indexToLocation() | ||
| 796 | maps a frame location to a scalar index starting from first index (one based!)" | ||
| 797 | input list<Integer> sizes; | ||
| 798 | input list<Integer> values; | ||
| 799 | input output Integer index; | ||
| 800 | protected | ||
| 801 | Integer factor = 1, val, siz; | ||
| 802 | list<Integer> val_trav = values, siz_trav = sizes; | ||
| 803 | algorithm | ||
| 804 |
3/4✓ Branch 0 taken 10419 times.
✓ Branch 1 taken 4893 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10419 times.
|
15312 | while not (listEmpty(val_trav) or listEmpty(siz_trav)) loop |
| 805 | 10419 | val :: val_trav := val_trav; | |
| 806 | 10419 | siz :: siz_trav := siz_trav; | |
| 807 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10419 times.
|
10419 | if val > siz then |
| 808 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because value of " + intString(val) | |
| 809 | + " is too large for size " + intString(siz) + "."}); | ||
| 810 | ✗ | fail(); | |
| 811 | end if; | ||
| 812 | 10419 | index := index + (val - 1) * factor; | |
| 813 | 10419 | factor := factor * siz; | |
| 814 | end while; | ||
| 815 | end locationToIndex; | ||
| 816 | |||
| 817 | function indexToLocation | ||
| 818 | "reverse function to locationToIndex() | ||
| 819 | maps a scalar index to its frame location (zero based!)" | ||
| 820 | input Integer index; | ||
| 821 | input list<Integer> sizes; | ||
| 822 | output list<Integer> vals = {}; | ||
| 823 | protected | ||
| 824 | Integer iterator = index; | ||
| 825 | Integer divisor = product(s for s in sizes); | ||
| 826 | algorithm | ||
| 827 |
2/2✓ Branch 0 taken 2975 times.
✓ Branch 1 taken 7095 times.
|
10070 | for size in sizes loop |
| 828 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2975 times.
|
2975 | divisor := intDiv(divisor, size); |
| 829 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2975 times.
|
2975 | vals := intDiv(iterator, divisor) :: vals; |
| 830 | iterator := mod(iterator, divisor); | ||
| 831 | end for; | ||
| 832 | end indexToLocation; | ||
| 833 | |||
| 834 | function transposeLocations | ||
| 835 | "transpose the location indices. | ||
| 836 | Before: Each inner list of indices represents a scalar equations | ||
| 837 | location inside all of the dimensions | ||
| 838 | After: Each inner array of indices represents the location of all | ||
| 839 | scalar equations for just one of the dimensions. | ||
| 840 | (still in order from Sorting)" | ||
| 841 | input list<list<Integer>> locations; | ||
| 842 | input Integer out_size; | ||
| 843 | output list<array<Integer>> locations_transposed; | ||
| 844 | protected | ||
| 845 | array<list<Integer>> lT_tmp = arrayCreate(out_size, {}); | ||
| 846 | array<array<Integer>> lT_tmp2 = arrayCreate(out_size, arrayCreate(0,0)); | ||
| 847 | Integer idx; | ||
| 848 | algorithm | ||
| 849 | ✗ | for location in locations loop | |
| 850 | idx := 1; | ||
| 851 | ✗ | for i in location loop | |
| 852 | ✗ | lT_tmp[idx] := i :: lT_tmp[idx]; | |
| 853 | ✗ | idx := idx + 1; | |
| 854 | end for; | ||
| 855 | end for; | ||
| 856 | ✗ | for j in 1:arrayLength(lT_tmp) loop | |
| 857 | ✗ | lT_tmp2[j] := listArray(listReverse(lT_tmp[j])); | |
| 858 | end for; | ||
| 859 | ✗ | locations_transposed := listReverse(arrayList(lT_tmp2)); | |
| 860 | end transposeLocations; | ||
| 861 | |||
| 862 | function orderTransposedFrameLocations | ||
| 863 | "order the frame locations by ascending inertia. | ||
| 864 | (the longer the chain of equal values at the start, the higher the inertia) | ||
| 865 | This is done to perform necessary reordering of nested for-loops" | ||
| 866 | input output list<FrameLocation> frame_locations_transposed; | ||
| 867 | output UnorderedMap<ComponentRef, Expression> replacements = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 868 | output FrameOrderingStatus status; | ||
| 869 | protected | ||
| 870 | list<tuple<Integer, FrameLocation>> frame_inertia_lst; | ||
| 871 | algorithm | ||
| 872 | // get inertia for each frame | ||
| 873 | ✗ | frame_inertia_lst := list((frameLocationInertia(frame), frame) for frame in frame_locations_transposed); | |
| 874 | // sort by inertia (ascending) | ||
| 875 | ✗ | frame_inertia_lst := List.sort(frame_inertia_lst, Util.compareTupleIntGt); | |
| 876 | // resolve equal inertia (diagonal slices) | ||
| 877 | ✗ | (frame_inertia_lst, status) := resolveEqualInertia(frame_inertia_lst, replacements); | |
| 878 | ✗ | frame_locations_transposed := list(Util.tuple22(frame_inertia) for frame_inertia in frame_inertia_lst); | |
| 879 | end orderTransposedFrameLocations; | ||
| 880 | |||
| 881 | protected function frameLocationInertia | ||
| 882 | "the longer the chain of equal values at the start, the higher the inertia" | ||
| 883 | input FrameLocation frameLocation; | ||
| 884 | output Integer inertia = 1; | ||
| 885 | protected | ||
| 886 | array<Integer> dim; | ||
| 887 | algorithm | ||
| 888 | ✗ | dim := Util.tuple21(frameLocation); | |
| 889 | ✗ | while inertia < arrayLength(dim) and dim[inertia] == dim[inertia+1] loop | |
| 890 | inertia := inertia + 1; | ||
| 891 | end while; | ||
| 892 | end frameLocationInertia; | ||
| 893 | |||
| 894 | protected function resolveEqualInertia | ||
| 895 | "Squashing all equal inertia frames (nested loops) into one. | ||
| 896 | Equal inertia for frames shows that they 'fire' at the same time. | ||
| 897 | These frames have to change in one step, therefore they should be merged to | ||
| 898 | a single one." | ||
| 899 | input list<tuple<Integer, FrameLocation>> frame_inertia_lst; | ||
| 900 | input UnorderedMap<ComponentRef, Expression> replacements; | ||
| 901 | output list<tuple<Integer, FrameLocation>> resolved = {}; | ||
| 902 | output FrameOrderingStatus status = NBEquation.FrameOrderingStatus.UNCHANGED; | ||
| 903 | protected | ||
| 904 | tuple<Integer, FrameLocation> tpl1, tpl2; | ||
| 905 | list<tuple<Integer, FrameLocation>> rest; | ||
| 906 | algorithm | ||
| 907 | ✗ | tpl1 :: rest := frame_inertia_lst; | |
| 908 | ✗ | while not listEmpty(rest) loop | |
| 909 | ✗ | tpl2 :: rest := rest; | |
| 910 | tpl1 := match (tpl1, tpl2) | ||
| 911 | local | ||
| 912 | Integer inertia1, inertia2, m, b; | ||
| 913 | array<Integer> loc1, loc2; | ||
| 914 | ComponentRef name1, name2; | ||
| 915 | Operator addOp, mulOp; | ||
| 916 | Expression linMap; | ||
| 917 | |||
| 918 | // equal inertia, combine the frames | ||
| 919 | case ((inertia1, (loc1, (name1, _, _))), (inertia2, (loc2, (name2, _, _)))) guard(inertia1 == inertia2) algorithm | ||
| 920 | ✗ | addOp := Operator.fromClassification((NFOperator.MathClassification.ADDITION, NFOperator.SizeClassification.SCALAR), Type.INTEGER()); | |
| 921 | ✗ | mulOp := Operator.fromClassification((NFOperator.MathClassification.MULTIPLICATION, NFOperator.SizeClassification.SCALAR), Type.INTEGER()); | |
| 922 | ✗ | if arrayLength(loc1) <> arrayLength(loc2) then | |
| 923 | status := NBEquation.FrameOrderingStatus.FAILURE; | ||
| 924 | ✗ | return; | |
| 925 | elseif arrayLength(loc1) == 1 then | ||
| 926 | ✗ | b := loc2[1] - loc1[1]; | |
| 927 | ✗ | linMap := Expression.fromCref(name1); | |
| 928 | ✗ | if b <> 0 then | |
| 929 | ✗ | linMap := Expression.MULTARY({Expression.INTEGER(b), linMap}, {}, addOp); | |
| 930 | end if; | ||
| 931 | ✗ | UnorderedMap.add(name2, linMap, replacements); | |
| 932 | status := NBEquation.FrameOrderingStatus.CHANGED; | ||
| 933 | else | ||
| 934 | // compute linear map from frame1 to frame2 (y = m*x + b) | ||
| 935 | // ToDo: integer to real conversion might be wrong? | ||
| 936 | ✗ | m := realInt((loc2[1]-loc2[1+inertia2])/(loc1[1]-loc1[1+inertia1])); | |
| 937 | ✗ | b := loc2[1]-m*loc1[1]; | |
| 938 | // check if linear map holds | ||
| 939 | ✗ | for i in 2:arrayLength(loc1) loop | |
| 940 | ✗ | if loc2[i] <> m*loc1[i] + b then | |
| 941 | status := NBEquation.FrameOrderingStatus.FAILURE; | ||
| 942 | ✗ | return; | |
| 943 | end if; | ||
| 944 | end for; | ||
| 945 | ✗ | linMap := Expression.fromCref(name1); | |
| 946 | ✗ | if m <> 1 then | |
| 947 | ✗ | linMap := Expression.MULTARY({Expression.INTEGER(m), linMap}, {}, mulOp); | |
| 948 | end if; | ||
| 949 | ✗ | if b <> 0 then | |
| 950 | ✗ | linMap := Expression.MULTARY({Expression.INTEGER(b), linMap}, {}, addOp); | |
| 951 | end if; | ||
| 952 | ✗ | UnorderedMap.add(name2, linMap, replacements); | |
| 953 | status := NBEquation.FrameOrderingStatus.CHANGED; | ||
| 954 | end if; | ||
| 955 | then tpl1; | ||
| 956 | |||
| 957 | // different inertia | ||
| 958 | else algorithm | ||
| 959 | resolved := tpl1 :: resolved; | ||
| 960 | then tpl2; | ||
| 961 | end match; | ||
| 962 | end while; | ||
| 963 | ✗ | resolved := listReverse(tpl1 :: resolved); | |
| 964 | end resolveEqualInertia; | ||
| 965 | |||
| 966 | public function recollectRangesHeuristic | ||
| 967 | "consecutively builds up the new frames from frame locations. | ||
| 968 | Assumes that slicing along the dimensions is possible. | ||
| 969 | Basic Idea: | ||
| 970 | 1. iterate over each frame location | ||
| 971 | 2. take first (start) and second (stop) element of frame dim to start the search for a pattern (step = stop - start) | ||
| 972 | 3. shift the stop location further until the step changes and safe the start-step-stop pattern | ||
| 973 | 3.1 iterate over the rest of the dim and check if the pattern holds for all of it | ||
| 974 | 3.2 if it not holds search a missing diagonal for this dimension (reconstruct diagonal) | ||
| 975 | 4. increase the shift for the length of the previous pattern and go to next frame location (shifting happens inherently in step 3)" | ||
| 976 | input list<FrameLocation> frame_locations_transposed; | ||
| 977 | output list<Frame> frames = {}; | ||
| 978 | output Option<UnorderedMap<ComponentRef, Expression>> removed_diagonal = NONE(); | ||
| 979 | output RecollectStatus status; | ||
| 980 | protected | ||
| 981 | array<Integer> dim; | ||
| 982 | Frame frame; | ||
| 983 | Integer check_shift, pre_shift, shift = 1; | ||
| 984 | Integer start, step, stop, max_size, new_step, new_stop, check_stop; | ||
| 985 | Boolean fail_; | ||
| 986 | list<Integer> starts = {}, stops = {}, steps = {}, shifts = {}; | ||
| 987 | list<Boolean> failed = {}; | ||
| 988 | Integer min_dim, max_dim; | ||
| 989 | list<FrameLocation> diagonal; | ||
| 990 | UnorderedMap<ComponentRef, Expression> replacements; | ||
| 991 | FrameOrderingStatus fos; | ||
| 992 | algorithm | ||
| 993 | ✗ | for tpl in frame_locations_transposed loop | |
| 994 | // 1. iterate over each frame location | ||
| 995 | fail_ := false; | ||
| 996 | ✗ | (dim, frame) := tpl; | |
| 997 | pre_shift := shift; | ||
| 998 | max_size := arrayLength(dim); | ||
| 999 | ✗ | if max_size == 1 then | |
| 1000 | // if there is only one frame, it is a single equation at that exact point | ||
| 1001 | ✗ | frames := applyNewFrameRange(frame, (dim[1], 1, dim[1])) :: frames; | |
| 1002 | starts := dim[1] :: starts; | ||
| 1003 | steps := 0 :: steps; | ||
| 1004 | stops := dim[1] :: stops; | ||
| 1005 | shifts := shift :: shifts; | ||
| 1006 | else | ||
| 1007 | // 2. take first (start) and second (stop) element of frame dim to start the search for a pattern (step = stop - start) | ||
| 1008 | ✗ | start := dim[1]; | |
| 1009 | ✗ | stop := dim[1 + shift]; | |
| 1010 | ✗ | step := stop - start; | |
| 1011 | ✗ | if step == 0 then | |
| 1012 | // if the step size is zero, this range only has a single entry | ||
| 1013 | // this should not happen? | ||
| 1014 | ✗ | frames := applyNewFrameRange(frame, (start, 1, stop)) :: frames; | |
| 1015 | starts := start :: starts; | ||
| 1016 | steps := step :: steps; | ||
| 1017 | stops := stop :: stops; | ||
| 1018 | shifts := shift :: shifts; | ||
| 1019 | else | ||
| 1020 | // 3. shift the stop location further until the step changes and safe the start-step-stop pattern | ||
| 1021 | new_step := step; | ||
| 1022 | new_stop := stop; | ||
| 1023 | ✗ | while (new_step == step) and (shift + pre_shift < max_size) loop | |
| 1024 | stop := new_stop; | ||
| 1025 | shift := shift + pre_shift; | ||
| 1026 | ✗ | new_stop := dim[1 + shift]; | |
| 1027 | ✗ | new_step := new_stop - stop; | |
| 1028 | end while; | ||
| 1029 | ✗ | if new_step == step then | |
| 1030 | // if new_step and step are still equal we hit the end (max_size) | ||
| 1031 | stop := new_stop; | ||
| 1032 | ✗ | shift := shift + pre_shift; //not necessary but more correct | |
| 1033 | else | ||
| 1034 | // 3.1 iterate over the rest of the dim and check if the pattern holds for all of it | ||
| 1035 | check_shift := shift; | ||
| 1036 | ✗ | while (check_shift + pre_shift < max_size) loop | |
| 1037 | new_step := step; | ||
| 1038 | ✗ | while (new_step == step) and (check_shift + pre_shift < max_size) loop | |
| 1039 | check_stop := new_stop; | ||
| 1040 | check_shift := check_shift + pre_shift; | ||
| 1041 | ✗ | new_stop := dim[1 + check_shift]; | |
| 1042 | ✗ | new_step := new_stop - check_stop; | |
| 1043 | end while; | ||
| 1044 | // has to be the same amount of steps after the step size changes | ||
| 1045 | ✗ | if (check_shift + pre_shift == max_size) then | |
| 1046 | check_shift := check_shift + pre_shift; | ||
| 1047 | end if; | ||
| 1048 | ✗ | if not intMod(check_shift, shift) == 0 then | |
| 1049 | fail_ := true; | ||
| 1050 | break; | ||
| 1051 | end if; | ||
| 1052 | end while; | ||
| 1053 | end if; | ||
| 1054 | // use max/min dim instead of start and stop because the start or end | ||
| 1055 | // could be missing (missing diagonals) | ||
| 1056 | ✗ | min_dim := min(d for d in dim); | |
| 1057 | ✗ | max_dim := max(d for d in dim); | |
| 1058 | ✗ | if fail_ then | |
| 1059 | ✗ | if step > 0 then | |
| 1060 | ✗ | frames := applyNewFrameRange(frame, (min_dim, step, max_dim)) :: frames; | |
| 1061 | else | ||
| 1062 | ✗ | frames := applyNewFrameRange(frame, (max_dim, step, min_dim)) :: frames; | |
| 1063 | end if; | ||
| 1064 | else | ||
| 1065 | ✗ | frames := applyNewFrameRange(frame, (start, step, stop)) :: frames; | |
| 1066 | end if; | ||
| 1067 | steps := step :: steps; | ||
| 1068 | ✗ | starts := if step > 0 then min_dim :: starts else max_dim :: starts; | |
| 1069 | ✗ | stops := if step > 0 then max_dim :: stops else min_dim :: stops; | |
| 1070 | shifts := shift :: shifts; | ||
| 1071 | ✗ | failed := fail_ :: failed; | |
| 1072 | end if; | ||
| 1073 | end if; | ||
| 1074 | end for; | ||
| 1075 | |||
| 1076 | // 3.2 if it not holds search a missing diagonal for this dimension (reconstruct diagonal) | ||
| 1077 | // if any dimension was not consistent, try to find a missing diagonal | ||
| 1078 | // it is stored in an unordered map as linear map for the indices | ||
| 1079 | ✗ | if List.fold(failed, boolOr, false) then | |
| 1080 | ✗ | diagonal := reconstructDiagonal(frame_locations_transposed, listReverse(starts), listReverse(steps), listReverse(stops), listReverse(shifts), listReverse(failed)); | |
| 1081 | ✗ | (diagonal, replacements, fos) := orderTransposedFrameLocations(diagonal); | |
| 1082 | ✗ | if fos == NBEquation.FrameOrderingStatus.CHANGED then | |
| 1083 | ✗ | removed_diagonal := SOME(replacements); | |
| 1084 | status := NBEquation.RecollectStatus.SUCCESS; | ||
| 1085 | else | ||
| 1086 | // no equal inertia to resolve or unable to resolve | ||
| 1087 | status := NBEquation.RecollectStatus.FAILURE; | ||
| 1088 | end if; | ||
| 1089 | else | ||
| 1090 | status := NBEquation.RecollectStatus.SUCCESS; | ||
| 1091 | end if; | ||
| 1092 | end recollectRangesHeuristic; | ||
| 1093 | |||
| 1094 | function reconstructDiagonal | ||
| 1095 | "reconstructs a supposed missing diagonal if it exists. | ||
| 1096 | ToDo1: create multiple diagonals if missing indices are found in one go without reset" | ||
| 1097 | input list<FrameLocation> frame_locations_transposed; | ||
| 1098 | input list<Integer> starts; | ||
| 1099 | input list<Integer> steps; | ||
| 1100 | input list<Integer> stops; | ||
| 1101 | input list<Integer> shifts; | ||
| 1102 | input list<Boolean> failed; | ||
| 1103 | output list<FrameLocation> diagonal = {}; | ||
| 1104 | protected | ||
| 1105 | Integer start, step, stop, pos, shift = 1; | ||
| 1106 | Boolean fail_; | ||
| 1107 | list<Integer> start_rest = starts, step_rest = steps, stop_rest = stops, shift_rest = shifts; | ||
| 1108 | list<Boolean> fail_rest = failed; | ||
| 1109 | array<Integer> dim; | ||
| 1110 | list<Integer> missing_dims; | ||
| 1111 | Frame frame; | ||
| 1112 | algorithm | ||
| 1113 | // ToDo: all lists have to be of equal length! | ||
| 1114 | // default first shift to 1 | ||
| 1115 | ✗ | for tpl in frame_locations_transposed loop | |
| 1116 | // get dims and frame from tpl | ||
| 1117 | ✗ | (dim, frame) := tpl; | |
| 1118 | // take out start, step, stop, fail | ||
| 1119 | ✗ | start :: start_rest := start_rest; | |
| 1120 | ✗ | step :: step_rest := step_rest; | |
| 1121 | ✗ | stop :: stop_rest := stop_rest; | |
| 1122 | ✗ | fail_ :: fail_rest := fail_rest; | |
| 1123 | // initialize missing dims and pos | ||
| 1124 | missing_dims := {}; | ||
| 1125 | pos := start; | ||
| 1126 | ✗ | if fail_ then | |
| 1127 | ✗ | for i in 1:shift:arrayLength(dim) loop | |
| 1128 | ✗ | while dim[i] <> pos loop | |
| 1129 | // ToDo1 | ||
| 1130 | missing_dims := pos :: missing_dims; | ||
| 1131 | ✗ | pos := pos + step; | |
| 1132 | ✗ | if (sign(step)*pos > sign(step)*stop) then | |
| 1133 | break; | ||
| 1134 | end if; | ||
| 1135 | end while; | ||
| 1136 | ✗ | if (sign(step)*(pos+step) > sign(step)*stop) then | |
| 1137 | pos := start; | ||
| 1138 | else | ||
| 1139 | pos := pos + step; | ||
| 1140 | end if; | ||
| 1141 | end for; | ||
| 1142 | ✗ | while sign(step)*pos <= sign(step)*stop loop | |
| 1143 | missing_dims := pos :: missing_dims; | ||
| 1144 | ✗ | pos := pos + step; | |
| 1145 | end while; | ||
| 1146 | else | ||
| 1147 | ✗ | for i in 1:shift:arrayLength(dim) loop | |
| 1148 | ✗ | missing_dims := dim[i] :: missing_dims; | |
| 1149 | end for; | ||
| 1150 | end if; | ||
| 1151 | ✗ | diagonal := (listArray(listReverse(missing_dims)), frame) :: diagonal; | |
| 1152 | // take out shift from shifts | ||
| 1153 | ✗ | shift :: shift_rest := shift_rest; | |
| 1154 | end for; | ||
| 1155 | ✗ | diagonal := listReverse(diagonal); | |
| 1156 | end reconstructDiagonal; | ||
| 1157 | |||
| 1158 | function naiveSeparation | ||
| 1159 | input list<Integer> indices "assumed to be sorted"; | ||
| 1160 | output list<list<Integer>> index_clusters = {}; | ||
| 1161 | protected | ||
| 1162 | Integer i; | ||
| 1163 | list<Integer> rest, current = {}; | ||
| 1164 | algorithm | ||
| 1165 | ✗ | if not listEmpty(indices) then | |
| 1166 | ✗ | i :: rest := listReverse(indices); | |
| 1167 | current := {i}; | ||
| 1168 | ✗ | for i2 in rest loop | |
| 1169 | ✗ | if i-i2 == 1 then | |
| 1170 | current := i2 :: current; | ||
| 1171 | else | ||
| 1172 | index_clusters := current :: index_clusters; | ||
| 1173 | current := {i2}; | ||
| 1174 | end if; | ||
| 1175 | i := i2; | ||
| 1176 | end for; | ||
| 1177 | index_clusters := current :: index_clusters; | ||
| 1178 | end if; | ||
| 1179 | end naiveSeparation; | ||
| 1180 | |||
| 1181 | // #### KAB ### new adjacency util | ||
| 1182 | function upgradeRowFull | ||
| 1183 | "Scalar equations. | ||
| 1184 | Turns cref dependencies into index lists, used for adjacency." | ||
| 1185 | input list<ComponentRef> dependencies "dependent var crefs"; | ||
| 1186 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 1187 | input Mapping mapping "array <-> scalar index mapping"; | ||
| 1188 | output list<Integer> indices = {}; | ||
| 1189 | protected | ||
| 1190 | list<ComponentRef> scalarized_dependencies = List.flatten(list(ComponentRef.scalarizeAll(dep, true) for dep in dependencies)); | ||
| 1191 | ComponentRef replaced, stripped; | ||
| 1192 | Integer var_arr_idx, var_start, var_scal_idx; | ||
| 1193 | algorithm | ||
| 1194 |
2/2✓ Branch 0 taken 233 times.
✓ Branch 1 taken 747 times.
|
980 | for cref in scalarized_dependencies loop |
| 1195 | 233 | (replaced, stripped) := getReplacedAndStripped(cref); | |
| 1196 | 233 | var_arr_idx := UnorderedMap.getSafe(stripped, map, sourceInfo()); | |
| 1197 | 233 | (var_start, _) := mapping.var_AtS[var_arr_idx]; | |
| 1198 | 233 | var_scal_idx := indexFromReplacedStripped(replaced, stripped, var_start, resize = true); | |
| 1199 | indices := var_scal_idx :: indices; | ||
| 1200 | end for; | ||
| 1201 | end upgradeRowFull; | ||
| 1202 | |||
| 1203 | function upgradeRow | ||
| 1204 | "For-Loop equations. | ||
| 1205 | Turns cref dependencies into index lists, used for adjacency." | ||
| 1206 | input ComponentRef eqn_name; | ||
| 1207 | input Integer eqn_arr_idx; | ||
| 1208 | input Iterator iter "iterator frames"; | ||
| 1209 | input Type ty; | ||
| 1210 | input list<ComponentRef> dependencies "dependent var crefs"; | ||
| 1211 | input UnorderedMap<ComponentRef, Dependency> dep "dependency map"; | ||
| 1212 | input UnorderedSet<ComponentRef> rep "repetition set"; | ||
| 1213 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 1214 | input UnorderedMap<ComponentRef, Integer> fullmap "unordered map to check for general relevance"; | ||
| 1215 | input IntMatrix.Builder m; | ||
| 1216 | input Mapping mapping "array <-> scalar index mapping"; | ||
| 1217 | input ModeTable modes; | ||
| 1218 | algorithm | ||
| 1219 |
2/2✓ Branch 0 taken 24044 times.
✓ Branch 1 taken 23441 times.
|
47485 | for cref in dependencies loop |
| 1220 | 24044 | resolveDependency(cref, eqn_name, eqn_arr_idx, iter, ty, dep, rep, map, fullmap, m, mapping, modes); | |
| 1221 | end for; | ||
| 1222 | end upgradeRow; | ||
| 1223 | |||
| 1224 | function getSingleIndex | ||
| 1225 | input ComponentRef cref; | ||
| 1226 | output Integer index; | ||
| 1227 | protected | ||
| 1228 | ComponentRef replaced, stripped; | ||
| 1229 | algorithm | ||
| 1230 | ✗ | (replaced, stripped) := getReplacedAndStripped(cref); | |
| 1231 | ✗ | index := indexFromReplacedStripped(replaced, stripped, 0); | |
| 1232 | end getSingleIndex; | ||
| 1233 | |||
| 1234 | // ############################################################ | ||
| 1235 | // Protected Functions | ||
| 1236 | // ############################################################ | ||
| 1237 | |||
| 1238 | protected | ||
| 1239 | function getReplacedAndStripped | ||
| 1240 | input ComponentRef cref; | ||
| 1241 | output ComponentRef replaced; | ||
| 1242 | output ComponentRef stripped; | ||
| 1243 | algorithm | ||
| 1244 | // remove all resizable parameters from cref | ||
| 1245 | 233 | replaced := ComponentRef.mapExp(cref, Expression.replaceResizableParameter); | |
| 1246 | 233 | replaced := ComponentRef.simplifySubscripts(replaced); | |
| 1247 | |||
| 1248 | // remove all subscripts from cref | ||
| 1249 | 233 | stripped := ComponentRef.stripSubscriptsAll(replaced); | |
| 1250 | end getReplacedAndStripped; | ||
| 1251 | |||
| 1252 | function indexFromReplacedStripped | ||
| 1253 | input ComponentRef replaced; | ||
| 1254 | input ComponentRef stripped; | ||
| 1255 | input Integer var_start; | ||
| 1256 | input Boolean resize = false "the sizes of resizable dimensions as resized, like scalarizeAll(cref, true)"; | ||
| 1257 | output Integer index; | ||
| 1258 | protected | ||
| 1259 | list<Integer> sizes, int_subs; | ||
| 1260 | algorithm | ||
| 1261 | // get the sizes and subscripts as integers and compute the final scalar index | ||
| 1262 | 233 | sizes := ComponentRef.sizes(stripped, false, resize); | |
| 1263 | 233 | int_subs := ComponentRef.subscriptsToInteger(replaced); | |
| 1264 | 233 | index := locationToIndex(sizes, int_subs, var_start); | |
| 1265 | end indexFromReplacedStripped; | ||
| 1266 | |||
| 1267 | function resolveSkipsLst | ||
| 1268 | input Integer index; | ||
| 1269 | input Type ty; | ||
| 1270 | input list<list<Integer>> skips; | ||
| 1271 | input ComponentRef cref; | ||
| 1272 | input UnorderedMap<ComponentRef, Integer> fullmap "unordered map to check for general relevance"; | ||
| 1273 | output list<tuple<Integer, Type>> skip_lst = {}; | ||
| 1274 | protected | ||
| 1275 | list<list<Integer>> combinations = List.combination(skips); | ||
| 1276 | Integer sub_idx; | ||
| 1277 | Type sub_ty; | ||
| 1278 | algorithm | ||
| 1279 |
2/2✓ Branch 0 taken 611 times.
✓ Branch 1 taken 21965 times.
|
22576 | if listEmpty(combinations) then |
| 1280 | 21965 | skip_lst := {(index, ty)}; | |
| 1281 | else | ||
| 1282 |
2/2✓ Branch 0 taken 926 times.
✓ Branch 1 taken 611 times.
|
1537 | for com in combinations loop |
| 1283 | 926 | (sub_idx, sub_ty) := resolveSkips(index, ty, com, cref, fullmap); | |
| 1284 | 926 | skip_lst := (sub_idx, sub_ty) :: skip_lst; | |
| 1285 | end for; | ||
| 1286 | end if; | ||
| 1287 | end resolveSkipsLst; | ||
| 1288 | |||
| 1289 | function resolveSkips | ||
| 1290 | input output Integer index; | ||
| 1291 | input output Type ty; | ||
| 1292 | input list<Integer> skips; | ||
| 1293 | input ComponentRef cref; | ||
| 1294 | input UnorderedMap<ComponentRef, Integer> fullmap "unordered map to check for general relevance"; | ||
| 1295 | algorithm | ||
| 1296 | (index, ty) := match (ty, skips) | ||
| 1297 | local | ||
| 1298 | Integer skip; | ||
| 1299 | list<Integer> rest, tail; | ||
| 1300 | list<Dimension> rest_dim, tail_dim; | ||
| 1301 | Type sub_ty; | ||
| 1302 | list<Type> rest_ty; | ||
| 1303 | Pointer<Variable> parent; | ||
| 1304 | list<ComponentRef> crefs; | ||
| 1305 | ComponentRef field; | ||
| 1306 | list<list<Subscript>> subs; | ||
| 1307 | |||
| 1308 | // 0 skips are full dependencies | ||
| 1309 | case (Type.TUPLE(), 0::_) then (index, ty); | ||
| 1310 | |||
| 1311 | // skip to a tuple element | ||
| 1312 | case (Type.TUPLE(types = rest_ty), skip::rest) guard(skip <= listLength(rest_ty)) algorithm | ||
| 1313 | // skip to the desired sub type and shift the starting index accordingly | ||
| 1314 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | for i in 1:skip-1 loop |
| 1315 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | sub_ty :: rest_ty := rest_ty; |
| 1316 | 2 | index := index + Type.sizeOf(sub_ty); | |
| 1317 | end for; | ||
| 1318 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | sub_ty :: rest_ty := rest_ty; |
| 1319 | // see if there is nested skips | ||
| 1320 | 927 | then resolveSkips(index, sub_ty, rest, cref, fullmap); | |
| 1321 | |||
| 1322 | // skip to a record element | ||
| 1323 | case (Type.COMPLEX(complexTy = ComplexType.RECORD()), skip::rest) algorithm | ||
| 1324 | // get the children and skip to correct one | ||
| 1325 | field := match BVariable.getParent(BVariable.getVarPointer(cref, sourceInfo())) | ||
| 1326 | case SOME(parent) algorithm | ||
| 1327 | 314 | subs := ComponentRef.subscriptsAll(cref); | |
| 1328 | // the skip counts all fields, but only the relevant ones (e.g. not removed aliases) have an index | ||
| 1329 |
4/4✓ Branch 1 taken 850 times.
✓ Branch 2 taken 314 times.
✓ Branch 3 taken 850 times.
✓ Branch 4 taken 314 times.
|
1164 | crefs := list(BVariable.getVarName(child) for child in BVariable.getRecordChildren(parent)); |
| 1330 |
1/2✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
|
314 | if skip <= listLength(crefs) then |
| 1331 |
2/2✓ Branch 0 taken 180 times.
✓ Branch 1 taken 134 times.
|
576 | for i in 1:skip-1 loop |
| 1332 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 262 times.
|
262 | field :: crefs := crefs; |
| 1333 |
2/2✓ Branch 1 taken 250 times.
✓ Branch 2 taken 12 times.
|
262 | if UnorderedMap.contains(field, fullmap) then |
| 1334 | 250 | field := ComponentRef.setSubscriptsList(subs, field); | |
| 1335 | 250 | index := index + Type.sizeOf(ComponentRef.getSubscriptedType(field)); | |
| 1336 | end if; | ||
| 1337 | end for; | ||
| 1338 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 314 times.
|
314 | field :: crefs := crefs; |
| 1339 | 314 | field := ComponentRef.setSubscriptsList(subs, field); | |
| 1340 | else | ||
| 1341 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because skip of " + intString(skip) | |
| 1342 | + " is too large for record elements " + List.toString(crefs, ComponentRef.toString) + "."}); | ||
| 1343 | ✗ | fail(); | |
| 1344 | end if; | ||
| 1345 | then field; | ||
| 1346 | else algorithm | ||
| 1347 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because skip of " + intString(skip) | |
| 1348 | + " for type " + Type.toString(ty) + " is requested, but the cref is not part of a record: " + ComponentRef.toString(cref) + "."}); | ||
| 1349 | ✗ | then fail(); | |
| 1350 | end match; | ||
| 1351 | // see if there is nested skips | ||
| 1352 | 314 | then resolveSkips(index, ComponentRef.getSubscriptedType(field), rest, cref, fullmap); | |
| 1353 | |||
| 1354 | // size one arrays do not have a skip associated | ||
| 1355 | case (Type.ARRAY(), rest) guard(Dimension.sizesProduct(ty.dimensions, true) == 1) algorithm | ||
| 1356 | 1 | then resolveSkips(index, ty.elementType, rest, cref, fullmap); | |
| 1357 | |||
| 1358 | // skip to an array element with more or equal skips to dimensions | ||
| 1359 | case (Type.ARRAY(), rest) guard List.compareLength(rest, ty.dimensions) >= 0 algorithm | ||
| 1360 | 608 | (rest, tail) := List.split(rest, listLength(ty.dimensions)); | |
| 1361 | // locationToIndex expects the innermost dimension first | ||
| 1362 |
4/4✓ Branch 0 taken 608 times.
✓ Branch 1 taken 608 times.
✓ Branch 2 taken 608 times.
✓ Branch 3 taken 608 times.
|
1216 | index := locationToIndex(listReverse(list(Dimension.size(dim, true) for dim in ty.dimensions)), listReverse(rest), index); |
| 1363 | 608 | then resolveSkips(index, ty.elementType, tail, cref, fullmap); | |
| 1364 | |||
| 1365 | // skip to an array with less skips then dimensions | ||
| 1366 | case (Type.ARRAY(), rest) algorithm | ||
| 1367 | 83 | (rest_dim, tail_dim) := List.split(ty.dimensions, listLength(rest)); | |
| 1368 | // offset by the skipped position times the size of the remaining dimensions (may be zero) | ||
| 1369 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 83 times.
|
83 | index := index + (locationToIndex(listReverse(list(Dimension.size(dim, true) for dim in rest_dim)), listReverse(rest), 1) - 1) |
| 1370 | * Dimension.sizesProduct(tail_dim, true); | ||
| 1371 | 83 | ty.dimensions := tail_dim; | |
| 1372 | then (index, ty); | ||
| 1373 | |||
| 1374 | // skip for tuple or array, but the skip is too large | ||
| 1375 | case (_, skip::_) guard(Type.isTuple(ty) or Type.isArray(ty)) algorithm | ||
| 1376 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because skip of " + intString(skip) | |
| 1377 | + " for type " + Type.toString(ty) + " is too large."}); | ||
| 1378 | ✗ | then fail(); | |
| 1379 | |||
| 1380 | // there is no skip but there is a tuple (no-skip array is fine) | ||
| 1381 | case (Type.TUPLE(), {}) algorithm | ||
| 1382 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because there is no skip for type " | |
| 1383 | + Type.toString(ty)}); | ||
| 1384 | ✗ | then fail(); | |
| 1385 | |||
| 1386 | // invalid skip | ||
| 1387 | // skipping to the first element of any type that is not array, tuple or complex is technically allowed but does not do anything | ||
| 1388 | case (_, skip::_) guard(skip <> 1) algorithm | ||
| 1389 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because skip of " + intString(skip) | |
| 1390 | + " for type " + Type.toString(ty) + " is invalid."}); | ||
| 1391 | ✗ | then fail(); | |
| 1392 | |||
| 1393 | else (index, ty); | ||
| 1394 | end match; | ||
| 1395 | end resolveSkips; | ||
| 1396 | |||
| 1397 | // intermediate types and functions for resolveDependency() | ||
| 1398 | type Key = list<Integer>; | ||
| 1399 | type Val1 = list<ComponentRef>; | ||
| 1400 | type Val2 = list<Integer>; | ||
| 1401 | |||
| 1402 | function keyString | ||
| 1403 | input Key key; | ||
| 1404 | output String str = List.toString(key, intString); | ||
| 1405 | end keyString; | ||
| 1406 | |||
| 1407 | function keyHash | ||
| 1408 | input Key key; | ||
| 1409 | output Integer hash = Util.HASH_SEED; | ||
| 1410 | algorithm | ||
| 1411 |
2/2✓ Branch 0 taken 272 times.
✓ Branch 1 taken 136 times.
|
408 | for k in key loop |
| 1412 | 272 | hash := stringHashDjb2Continue(intString(k), hash); | |
| 1413 | end for; | ||
| 1414 | end keyHash; | ||
| 1415 | |||
| 1416 | function keyEqual | ||
| 1417 | input Key key1; | ||
| 1418 | input Key key2; | ||
| 1419 | output Boolean b = List.isEqualOnTrue(key1, key2, intEq); | ||
| 1420 | end keyEqual; | ||
| 1421 | |||
| 1422 | function val1String | ||
| 1423 | input list<ComponentRef> val; | ||
| 1424 | output String str = List.toString(val, ComponentRef.toString); | ||
| 1425 | end val1String; | ||
| 1426 | |||
| 1427 | function resolveDependency | ||
| 1428 | "resolves the dependency of a component reference in an equation. | ||
| 1429 | I. Resolve skip dimensions (Tuples, Records, Array Constructors) | ||
| 1430 | II. Resolve regular vs. reduced dimensions" | ||
| 1431 | input ComponentRef original_cref; | ||
| 1432 | input ComponentRef eqn_name; | ||
| 1433 | input Integer eqn_arr_idx; | ||
| 1434 | input Iterator iter; | ||
| 1435 | input Type ty; | ||
| 1436 | input UnorderedMap<ComponentRef, Dependency> dep "dependency map"; | ||
| 1437 | input UnorderedSet<ComponentRef> rep "repetition set"; | ||
| 1438 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 1439 | input UnorderedMap<ComponentRef, Integer> fullmap "unordered map to check for general relevance"; | ||
| 1440 | input IntMatrix.Builder m; | ||
| 1441 | input Mapping mapping "array <-> scalar index mapping"; | ||
| 1442 | input ModeTable modes; | ||
| 1443 | protected | ||
| 1444 | Dependency d; | ||
| 1445 | list<tuple<Integer, Type>> skip_lst; | ||
| 1446 | Type skip_ty; | ||
| 1447 | Integer skip_idx, start, size, body_size, iter_size; | ||
| 1448 | list<ComponentRef> names; | ||
| 1449 | list<Expression> ranges; | ||
| 1450 | list<Option<Iterator>> maps; | ||
| 1451 | list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 1452 | list<Boolean> regulars; | ||
| 1453 | ComponentRef cref; | ||
| 1454 | algorithm | ||
| 1455 | try | ||
| 1456 | // remove resizable parameters for index lookup | ||
| 1457 | 24044 | cref := ComponentRef.mapExp(original_cref, Expression.replaceResizableParameter); | |
| 1458 | 24044 | cref := ComponentRef.simplifySubscripts(cref); | |
| 1459 | |||
| 1460 | // I. resolve the skips | ||
| 1461 | 24044 | d := UnorderedMap.getSafe(original_cref, dep, sourceInfo()); | |
| 1462 | 24044 | (start, _) := mapping.eqn_AtS[eqn_arr_idx]; | |
| 1463 |
2/2✓ Branch 1 taken 22576 times.
✓ Branch 2 taken 1468 times.
|
24044 | if not UnorderedSet.contains(cref, rep) then |
| 1464 | 22576 | skip_lst := resolveSkipsLst(start, ty, arrayList(d.skips), cref, fullmap); | |
| 1465 | else | ||
| 1466 | 1468 | skip_lst := {(start, ty)}; | |
| 1467 | end if; | ||
| 1468 | |||
| 1469 |
2/2✓ Branch 0 taken 24359 times.
✓ Branch 1 taken 24044 times.
|
48403 | for tpl in skip_lst loop |
| 1470 | 24359 | (skip_idx, skip_ty) := tpl; | |
| 1471 | // get equation and iterator sizes and frames | ||
| 1472 | 24359 | body_size := Type.sizeOf(skip_ty, true); | |
| 1473 | 24359 | iter_size := Iterator.size(iter, true); | |
| 1474 | 24359 | size := body_size * iter_size; | |
| 1475 | 24359 | (names, ranges, maps) := Iterator.getFrames(iter); | |
| 1476 | 24359 | frames := List.zip3(names, ranges, maps); | |
| 1477 | |||
| 1478 | // II. check for regular vs. reduced dimensions | ||
| 1479 | 24359 | regulars := Dependency.toBoolean(d); | |
| 1480 |
2/2✓ Branch 1 taken 24038 times.
✓ Branch 2 taken 321 times.
|
24359 | if List.all(regulars, Util.id) then |
| 1481 | // II.1 all regular - single dependency per row. | ||
| 1482 | // The rows of a for-equation are ordered by iteration, then by the elements of its body. If | ||
| 1483 | // the dependency is only an element of the body (e.g. one output of a tuple) its rows are not | ||
| 1484 | // contiguous but a whole body apart. | ||
| 1485 | 24038 | resolveAllRegular(cref, original_cref, eqn_name, skip_idx, size, iter_size, frames, rep, map, m, mapping, modes, Type.sizeOf(ty, true)); | |
| 1486 | elseif List.any(regulars, Util.id) then | ||
| 1487 | // II.2 mixed regularity - find all necessary configurations and add them to a map with a proper key | ||
| 1488 | 12 | resolveMixed(cref, original_cref, eqn_name, skip_idx, ty, frames, iter_size, regulars, map, m, mapping, modes); | |
| 1489 | else | ||
| 1490 | // II.3 all reduced - full dependency per row. scalarize and add to all rows of the equation | ||
| 1491 | 309 | resolveAllReduced(cref, original_cref, eqn_name, skip_idx, size, iter_size, frames, rep, map, m, mapping, modes); | |
| 1492 | end if; | ||
| 1493 | |||
| 1494 | end for; | ||
| 1495 | else | ||
| 1496 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for: " + ComponentRef.toString(original_cref) + "."}); | |
| 1497 | ✗ | fail(); | |
| 1498 | end try; | ||
| 1499 | end resolveDependency; | ||
| 1500 | |||
| 1501 | function resolveAllRegular | ||
| 1502 | "II.1 all regular - single dependency per row." | ||
| 1503 | input ComponentRef cref; | ||
| 1504 | input ComponentRef original_cref; | ||
| 1505 | input ComponentRef eqn_name; | ||
| 1506 | input Integer skip_idx, size, iter_size; | ||
| 1507 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 1508 | input UnorderedSet<ComponentRef> rep "repetition set"; | ||
| 1509 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 1510 | input IntMatrix.Builder m; | ||
| 1511 | input Mapping mapping "array <-> scalar index mapping"; | ||
| 1512 | input ModeTable modes; | ||
| 1513 | input Integer stride = 0 "rows of a whole equation body (0: same as the dependency)"; | ||
| 1514 | protected | ||
| 1515 | Integer mode; | ||
| 1516 | list<ComponentRef> scalarized; | ||
| 1517 | list<Val2> scal_indices = {}; | ||
| 1518 | Val2 idx_lst; | ||
| 1519 | Integer scal_size = 0, shift, body_size = if iter_size > 0 then intDiv(size, iter_size) else size; | ||
| 1520 | algorithm | ||
| 1521 | 24038 | mode := Modes.add(modes, Mode.create(eqn_name, {original_cref}, false)); | |
| 1522 | 24038 | scalarized := listReverse(ComponentRef.scalarizeAll(cref, true)); | |
| 1523 |
2/2✓ Branch 0 taken 28653 times.
✓ Branch 1 taken 24038 times.
|
52691 | for scal in scalarized loop |
| 1524 | 28653 | idx_lst := getCrefInFrameIndices(scal, frames, mapping, map, true); | |
| 1525 | scal_indices := idx_lst :: scal_indices; | ||
| 1526 | 28653 | scal_size := scal_size + listLength(idx_lst); | |
| 1527 | end for; | ||
| 1528 | 24038 | scal_indices := listReverse(scal_indices); | |
| 1529 | // either the scalarized list has to be equal in length to the equation or it can be repeated enough times to fit | ||
| 1530 |
7/8✓ Branch 0 taken 24037 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 24011 times.
✓ Branch 5 taken 19 times.
✓ Branch 6 taken 7 times.
✓ Branch 7 taken 19 times.
✗ Branch 8 not taken.
|
24057 | if scal_size > 0 and (size == scal_size or (UnorderedSet.contains(cref, rep) and intMod(size, scal_size) == 0)) then |
| 1531 | shift := 0; | ||
| 1532 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 24030 times.
✓ Branch 3 taken 24030 times.
✗ Branch 4 not taken.
|
48118 | for i in 1:size/scal_size loop |
| 1533 |
2/2✓ Branch 0 taken 28704 times.
✓ Branch 1 taken 24088 times.
|
52792 | for indices in scal_indices loop |
| 1534 |
2/2✓ Branch 0 taken 45958 times.
✓ Branch 1 taken 28704 times.
|
74662 | for scal_idx in indices loop |
| 1535 |
2/2✓ Branch 0 taken 1338 times.
✓ Branch 1 taken 44620 times.
|
45958 | if stride > body_size and body_size > 0 then |
| 1536 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1338 times.
|
1338 | addMatrixEntry(m, skip_idx + intDiv(shift, body_size) * stride + intMod(shift, body_size), scal_idx, mode); |
| 1537 | else | ||
| 1538 | 44620 | addMatrixEntry(m, skip_idx + shift, scal_idx, mode); | |
| 1539 | end if; | ||
| 1540 | 45958 | shift := shift + 1; | |
| 1541 | end for; | ||
| 1542 | end for; | ||
| 1543 | end for; | ||
| 1544 | elseif scal_size > 0 and scal_size < size then | ||
| 1545 | // partial out-of-bounds: some frame values produce invalid subscripts (e.g. $i1-1 at $i1=1). | ||
| 1546 | // evaluate each frame combination individually and assign deps to the correct equation row only. | ||
| 1547 | 3 | resolveAllRegularPartial(cref, original_cref, eqn_name, skip_idx, size, iter_size, frames, map, m, mapping, modes); | |
| 1548 | elseif scal_size > size then | ||
| 1549 | // undetected full dependency caused by non-evaluable subscripts, this can happen by inlining functions | ||
| 1550 | // II.3 all reduced - full dependency per row. scalarize and add to all rows of the equation | ||
| 1551 | 4 | resolveAllReduced(cref, original_cref, eqn_name, skip_idx, size, iter_size, frames, rep, map, m, mapping, modes); | |
| 1552 | end if; | ||
| 1553 | // scal_size == 0: all frame values are out-of-bounds, no real dependency — do nothing | ||
| 1554 | end resolveAllRegular; | ||
| 1555 | |||
| 1556 | function resolveMixed | ||
| 1557 | "II.2 mixed regularity - find all necessary configurations and add them to a map with a proper key" | ||
| 1558 | input ComponentRef cref; | ||
| 1559 | input ComponentRef original_cref; | ||
| 1560 | input ComponentRef eqn_name; | ||
| 1561 | input Integer skip_idx; | ||
| 1562 | input Type ty; | ||
| 1563 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 1564 | input Integer iter_size; | ||
| 1565 | input list<Boolean> regulars; | ||
| 1566 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 1567 | input IntMatrix.Builder m; | ||
| 1568 | input Mapping mapping "array <-> scalar index mapping"; | ||
| 1569 | input ModeTable modes; | ||
| 1570 | protected | ||
| 1571 | ComponentRef stripped; | ||
| 1572 | list<Subscript> subs; | ||
| 1573 | list<Dimension> dims, eq_dims; | ||
| 1574 | array<Integer> key; | ||
| 1575 | UnorderedMap<Key, Val1> map1; | ||
| 1576 | array<UnorderedMap<Key, Val2>> frame_maps; | ||
| 1577 | list<array<Integer>> frame_indices; | ||
| 1578 | list<Integer> all_indices; | ||
| 1579 | Integer size_comp, frame_count = max(iter_size, 1), mode; | ||
| 1580 | Boolean per_frame; | ||
| 1581 | Pointer<Integer> eqn_idx_ptr; | ||
| 1582 | list<Boolean> eq_reg, scalars; | ||
| 1583 | list<tuple<Dimension, Boolean>> lst; | ||
| 1584 | list<tuple<Subscript, Dimension, Boolean>> var_lst; | ||
| 1585 | Boolean aligned; | ||
| 1586 | algorithm | ||
| 1587 | // 1. get the cref subscripts and dimensions as well as the equation dimensions (they have to match in length) | ||
| 1588 | 12 | subs := ComponentRef.subscriptsAllWithWholeFlat(cref); | |
| 1589 | 12 | dims := Type.arrayDims(ComponentRef.getSubscriptedType(cref)); | |
| 1590 | 12 | eq_dims := Type.arrayDims(ty); | |
| 1591 | 12 | (var_lst, scalars, aligned) := zipSubscripts(subs, dims, regulars); | |
| 1592 | |||
| 1593 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if aligned then |
| 1594 | // 2. create a map that maps a configuration key to the corresponding scalar crefs | ||
| 1595 | 12 | stripped := ComponentRef.stripSubscriptsAll(cref); | |
| 1596 | 12 | key := arrayCreate(listLength(subs), 0); | |
| 1597 | 12 | map1 := UnorderedMap.new<Val1>(keyHash, keyEqual); | |
| 1598 | 12 | resolveReductions(var_lst, map1, key, stripped); | |
| 1599 | |||
| 1600 | // 3. create maps that map a configuration key to the final variable indices, one map per | ||
| 1601 | // frame since each frame (iteration of a for-equation) has its own rows | ||
| 1602 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
|
24 | frame_maps := listArray(list(UnorderedMap.new<Val2>(keyHash, keyEqual) for i in 1:frame_count)); |
| 1603 |
2/2✓ Branch 1 taken 34 times.
✓ Branch 2 taken 12 times.
|
46 | for k in UnorderedMap.keyList(map1) loop |
| 1604 |
4/4✓ Branch 1 taken 98 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 98 times.
✓ Branch 4 taken 34 times.
|
132 | frame_indices := list(listArray(getCrefInFrameIndices(scal, frames, mapping, map, true)) |
| 1605 | for scal in UnorderedMap.getSafe(k, map1, sourceInfo())); | ||
| 1606 |
5/6✓ Branch 0 taken 98 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 34 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 98 times.
|
230 | per_frame := List.all(list(arrayLength(a) == frame_count for a in frame_indices), Util.id); |
| 1607 | |||
| 1608 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | if per_frame then |
| 1609 | 34 | for i in 1:frame_count loop | |
| 1610 |
4/4✓ Branch 0 taken 98 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 34 times.
|
132 | UnorderedMap.add(k, list(a[i] for a in frame_indices), frame_maps[i]); |
| 1611 | end for; | ||
| 1612 | else | ||
| 1613 | // indices that cannot be attributed to a frame (e.g. some frames are out of bounds) belong to all of them | ||
| 1614 | ✗ | all_indices := List.flatten(list(arrayList(a) for a in frame_indices)); | |
| 1615 | ✗ | for i in 1:frame_count loop | |
| 1616 | ✗ | UnorderedMap.add(k, all_indices, frame_maps[i]); | |
| 1617 | end for; | ||
| 1618 | end if; | ||
| 1619 | end for; | ||
| 1620 | |||
| 1621 | // 4. check if equation and variable are of same length, if not: fixup the lists to be of equal length | ||
| 1622 | 12 | size_comp := List.compareLength(eq_dims, regulars); | |
| 1623 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if size_comp > 0 then |
| 1624 | // bigger equation than variable | ||
| 1625 | ✗ | eq_reg := listAppend(regulars, List.fill(false, listLength(eq_dims) - listLength(regulars))); | |
| 1626 | ✗ | lst := List.zip(eq_dims, eq_reg); | |
| 1627 | elseif size_comp < 0 then | ||
| 1628 | // bigger variable than equation | ||
| 1629 | 12 | lst := resolveMixedDimensions(eq_dims, regulars); | |
| 1630 | else | ||
| 1631 | ✗ | lst := List.zip(eq_dims, regulars); | |
| 1632 | end if; | ||
| 1633 | 12 | lst := insertScalarDimensions(lst, scalars); | |
| 1634 | |||
| 1635 | // 5. iterate over all equation dimensions and use the map to get the correct dependencies, | ||
| 1636 | // the rows of the frames follow each other | ||
| 1637 | 12 | mode := Modes.add(modes, Mode.create(eqn_name, {original_cref}, false)); | |
| 1638 | 12 | eqn_idx_ptr := Pointer.create(skip_idx); | |
| 1639 | 24 | for i in 1:frame_count loop | |
| 1640 | 12 | key := arrayCreate(listLength(subs), 0); | |
| 1641 | 12 | resolveEquationDimensions(lst, frame_maps[i], key, m, mode, eqn_idx_ptr); | |
| 1642 | end for; | ||
| 1643 | else | ||
| 1644 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because subscripts, dimensions and dependencies were not of equal length.\n" | |
| 1645 | + "variable subscripts(" + intString(listLength(subs)) + "): " + List.toString(subs, Subscript.toString) + "\n" | ||
| 1646 | + "variable dimensions(" + intString(listLength(dims)) + "): " + List.toString(dims, Dimension.toString) + "\n" | ||
| 1647 | + "equation dimensions(" + intString(listLength(eq_dims)) + "): " + List.toString(eq_dims, Dimension.toString) + "\n" | ||
| 1648 | + "variable dependencies(" + intString(listLength(regulars)) + "): " + List.toString(regulars, boolString) + "\n"}); | ||
| 1649 | ✗ | fail(); | |
| 1650 | end if; | ||
| 1651 | end resolveMixed; | ||
| 1652 | |||
| 1653 | function zipSubscripts | ||
| 1654 | "Zips the subscripts of a cref with the dimensions and dependencies of its | ||
| 1655 | subscripted type. A scalar subscript (e.g. a[1].b[:]) has neither and gets | ||
| 1656 | a reduced dimension of size one, so that the key positions of the variable | ||
| 1657 | and the equation stay aligned (see insertScalarDimensions)." | ||
| 1658 | input list<Subscript> subs; | ||
| 1659 | input list<Dimension> dims; | ||
| 1660 | input list<Boolean> regulars; | ||
| 1661 | output list<tuple<Subscript, Dimension, Boolean>> lst = {}; | ||
| 1662 | output list<Boolean> scalars = {}; | ||
| 1663 | output Boolean aligned = true; | ||
| 1664 | protected | ||
| 1665 | list<Dimension> rest_dims = dims; | ||
| 1666 | list<Boolean> rest_regs = regulars; | ||
| 1667 | Dimension dim; | ||
| 1668 | Boolean reg; | ||
| 1669 | algorithm | ||
| 1670 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
|
36 | for sub in subs loop |
| 1671 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
|
24 | if Subscript.isScalar(sub) then |
| 1672 | ✗ | lst := (sub, Dimension.fromInteger(1), false) :: lst; | |
| 1673 | scalars := true :: scalars; | ||
| 1674 | elseif listEmpty(rest_dims) or listEmpty(rest_regs) then | ||
| 1675 | aligned := false; | ||
| 1676 | ✗ | return; | |
| 1677 | else | ||
| 1678 | 24 | dim :: rest_dims := rest_dims; | |
| 1679 | 24 | reg :: rest_regs := rest_regs; | |
| 1680 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
|
36 | lst := (sub, dim, reg) :: lst; |
| 1681 | scalars := false :: scalars; | ||
| 1682 | end if; | ||
| 1683 | end for; | ||
| 1684 | |||
| 1685 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | aligned := listEmpty(rest_dims) and listEmpty(rest_regs); |
| 1686 | 12 | lst := listReverse(lst); | |
| 1687 | 12 | scalars := listReverse(scalars); | |
| 1688 | end zipSubscripts; | ||
| 1689 | |||
| 1690 | function insertScalarDimensions | ||
| 1691 | "Inserts a reduced dimension of size one into the equation dimensions for | ||
| 1692 | each scalar subscript of the variable." | ||
| 1693 | input list<tuple<Dimension, Boolean>> lst; | ||
| 1694 | input list<Boolean> scalars; | ||
| 1695 | output list<tuple<Dimension, Boolean>> outLst = {}; | ||
| 1696 | protected | ||
| 1697 | list<tuple<Dimension, Boolean>> rest = lst; | ||
| 1698 | tuple<Dimension, Boolean> t; | ||
| 1699 | algorithm | ||
| 1700 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
|
36 | for scalar in scalars loop |
| 1701 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if scalar then |
| 1702 | ✗ | outLst := (Dimension.fromInteger(1), false) :: outLst; | |
| 1703 | elseif not listEmpty(rest) then | ||
| 1704 | 24 | t :: rest := rest; | |
| 1705 | outLst := t :: outLst; | ||
| 1706 | end if; | ||
| 1707 | end for; | ||
| 1708 | |||
| 1709 | 12 | outLst := List.append_reverse(outLst, rest); | |
| 1710 | end insertScalarDimensions; | ||
| 1711 | |||
| 1712 | function resolveMixedDimensions | ||
| 1713 | "fills the list with dimensions of size one at the proper place even if they are skipped. | ||
| 1714 | allows a function that resolves all configurations of variable and equation sizes. | ||
| 1715 | prepares for resolveEquationDimensions() if the variable is bigger than the equation" | ||
| 1716 | input list<Dimension> eq_dims; | ||
| 1717 | input list<Boolean> regulars; | ||
| 1718 | input output list<tuple<Dimension, Boolean>> lst = {}; | ||
| 1719 | algorithm | ||
| 1720 | lst := match (eq_dims, regulars) | ||
| 1721 | local | ||
| 1722 | Dimension dim; | ||
| 1723 | list<Dimension> rest_dim; | ||
| 1724 | list<Boolean> rest_reg; | ||
| 1725 | // dummy dimension that will be skipped | ||
| 1726 | 12 | case (_, false :: rest_reg) then (Dimension.fromExp(Expression.INTEGER(1), Variability.CONSTANT), false) :: resolveMixedDimensions(eq_dims, rest_reg); | |
| 1727 | // correct dimension that will be kept | ||
| 1728 | 12 | case (dim :: rest_dim, true :: rest_reg) then (dim, true) :: resolveMixedDimensions(rest_dim, rest_reg); | |
| 1729 | // excess unfitting is ignored | ||
| 1730 | else {}; | ||
| 1731 | end match; | ||
| 1732 | end resolveMixedDimensions; | ||
| 1733 | |||
| 1734 | function resolveAllReduced | ||
| 1735 | "II.3 all reduced - full dependency per row. scalarize and add to all rows of the equation" | ||
| 1736 | input ComponentRef cref; | ||
| 1737 | input ComponentRef original_cref; | ||
| 1738 | input ComponentRef eqn_name; | ||
| 1739 | input Integer skip_idx, size, iter_size; | ||
| 1740 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 1741 | input UnorderedSet<ComponentRef> rep "repetition set"; | ||
| 1742 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 1743 | input IntMatrix.Builder m; | ||
| 1744 | input Mapping mapping "array <-> scalar index mapping"; | ||
| 1745 | input ModeTable modes; | ||
| 1746 | protected | ||
| 1747 | Boolean repeated; | ||
| 1748 | list<ComponentRef> scalarized; | ||
| 1749 | list<Val2> scal_indices = {}; | ||
| 1750 | Integer shift; | ||
| 1751 | Integer mode; | ||
| 1752 | algorithm | ||
| 1753 | 313 | repeated := UnorderedSet.contains(cref, rep); | |
| 1754 | 313 | scalarized := listReverse(ComponentRef.scalarizeAll(cref, true)); | |
| 1755 |
2/2✓ Branch 0 taken 3571 times.
✓ Branch 1 taken 313 times.
|
3884 | for scal in scalarized loop |
| 1756 | 3571 | scal_indices := getCrefInFrameIndices(scal, frames, mapping, map, true) :: scal_indices; | |
| 1757 | end for; | ||
| 1758 | 313 | scal_indices := listReverse(scal_indices); | |
| 1759 | |||
| 1760 | // if its repeated, use the same cref always; otherwise use local cref | ||
| 1761 | 313 | mode := Modes.add(modes, Mode.create(eqn_name, {original_cref}, not repeated)); | |
| 1762 | |||
| 1763 |
3/6✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 313 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 313 times.
|
980 | for i in skip_idx:iter_size:skip_idx+size-iter_size loop |
| 1764 | shift := 0; | ||
| 1765 |
2/2✓ Branch 0 taken 5397 times.
✓ Branch 1 taken 667 times.
|
6064 | for indices in scal_indices loop |
| 1766 |
3/4✓ Branch 0 taken 5841 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5841 times.
✓ Branch 3 taken 5397 times.
|
11238 | for scal_idx in indices loop |
| 1767 |
2/2✓ Branch 0 taken 5401 times.
✓ Branch 1 taken 440 times.
|
5841 | if intMod(shift, iter_size) == 0 then shift := 0; end if; |
| 1768 | 5841 | addMatrixEntry(m, i + shift, scal_idx, mode); | |
| 1769 | 5841 | shift := shift + 1; | |
| 1770 | end for; | ||
| 1771 | end for; | ||
| 1772 | end for; | ||
| 1773 | end resolveAllReduced; | ||
| 1774 | |||
| 1775 | function resolveAllRegularPartial | ||
| 1776 | "II.1 partial out-of-bounds variant: some frame values produce invalid (out-of-bounds) subscripts. | ||
| 1777 | Evaluates each frame combination individually and assigns each valid scalar index to the | ||
| 1778 | equation row that corresponds to that frame value only. Rows whose frame value maps to an | ||
| 1779 | out-of-bounds subscript receive no dependency entry." | ||
| 1780 | input ComponentRef cref; | ||
| 1781 | input ComponentRef original_cref; | ||
| 1782 | input ComponentRef eqn_name; | ||
| 1783 | input Integer skip_idx, size, iter_size; | ||
| 1784 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 1785 | input UnorderedMap<ComponentRef, Integer> map; | ||
| 1786 | input IntMatrix.Builder m; | ||
| 1787 | input Mapping mapping; | ||
| 1788 | input ModeTable modes; | ||
| 1789 | protected | ||
| 1790 | Integer mode; | ||
| 1791 | ComponentRef final_cref; | ||
| 1792 | Integer var_arr_idx, var_start; | ||
| 1793 | list<Integer> sizes; | ||
| 1794 | list<Expression> subs; | ||
| 1795 | Integer body_size; | ||
| 1796 | Pointer<Integer> row; | ||
| 1797 | UnorderedMap<ComponentRef, Expression> replacements; | ||
| 1798 | algorithm | ||
| 1799 | 3 | mode := Modes.add(modes, Mode.create(eqn_name, {original_cref}, false)); | |
| 1800 | 3 | (final_cref, var_arr_idx) := getVarArrIdx(cref, mapping, map); | |
| 1801 | 3 | (var_start, _) := mapping.var_AtS[var_arr_idx]; | |
| 1802 | 3 | sizes := ComponentRef.sizes(final_cref, false, true); | |
| 1803 | 3 | subs := ComponentRef.subscriptsToExpression(cref, true); | |
| 1804 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | body_size := intDiv(size, iter_size); |
| 1805 | 3 | row := Pointer.create(skip_idx); | |
| 1806 | 3 | replacements := UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | |
| 1807 | 3 | resolveFrames(frames, sizes, subs, var_start, replacements, true, m, mode, body_size, row); | |
| 1808 | end resolveAllRegularPartial; | ||
| 1809 | |||
| 1810 | function resolveFrames | ||
| 1811 | "Recursively iterates over all frame combinations (one per equation row) and assigns | ||
| 1812 | each valid scalar index to the corresponding equation row. Advances the row counter | ||
| 1813 | for every frame combination regardless of whether the subscript is valid." | ||
| 1814 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 1815 | input list<Integer> sizes; | ||
| 1816 | input list<Expression> subs; | ||
| 1817 | input Integer var_start; | ||
| 1818 | input UnorderedMap<ComponentRef, Expression> replacements; | ||
| 1819 | input Boolean resize; | ||
| 1820 | input IntMatrix.Builder m; | ||
| 1821 | input Integer mode "index into the mode table"; | ||
| 1822 | input Integer body_size; | ||
| 1823 | input Pointer<Integer> row; | ||
| 1824 | algorithm | ||
| 1825 | () := match frames | ||
| 1826 | local | ||
| 1827 | ComponentRef iterator; | ||
| 1828 | Expression range; | ||
| 1829 | Option<Iterator> fmap; | ||
| 1830 | list<tuple<ComponentRef, Expression, Option<Iterator>>> rest; | ||
| 1831 | Integer start, step, stop, sub_idx, r; | ||
| 1832 | list<list<Integer>> values; | ||
| 1833 | list<Expression> iterator_exps; | ||
| 1834 | list<Integer> iterator_lst; | ||
| 1835 | |||
| 1836 | // leaf: all frame iterators bound — evaluate subscript and assign to current row | ||
| 1837 | case {} algorithm | ||
| 1838 | 23 | r := Pointer.access(row); | |
| 1839 | 23 | values := resolveDimensionsSubscripts(sizes, subs, replacements, resize); | |
| 1840 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 23 times.
|
43 | for v in listReverse(values) loop |
| 1841 | 20 | addMatrixEntry(m, r, locationToIndex(sizes, v, var_start), mode); | |
| 1842 | end for; | ||
| 1843 | 23 | Pointer.update(row, r + body_size); | |
| 1844 | then (); | ||
| 1845 | |||
| 1846 | // recurse over iterator range | ||
| 1847 | case (iterator, range, fmap) :: rest algorithm | ||
| 1848 | iterator_lst := match range | ||
| 1849 | case Expression.RANGE() algorithm | ||
| 1850 | 3 | (start, step, stop) := Expression.getIntegerRange(range, resize); | |
| 1851 | 3 | then List.intRange3(start, step, stop); | |
| 1852 | case Expression.ARRAY() algorithm | ||
| 1853 | ✗ | iterator_exps := list(Expression.map(e, function Replacements.applySimpleExp(replacements = replacements)) for e in range.elements); | |
| 1854 | ✗ | iterator_lst := list(Expression.integerValue(SimplifyExp.simplifyDump(e, true, getInstanceName())) for e in iterator_exps); | |
| 1855 | then iterator_lst; | ||
| 1856 | else algorithm | ||
| 1857 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to parse iterator range: " | |
| 1858 | + ComponentRef.toString(iterator) + " in " + Expression.toString(range)}); | ||
| 1859 | ✗ | then fail(); | |
| 1860 | end match; | ||
| 1861 | |||
| 1862 | sub_idx := 1; | ||
| 1863 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 3 times.
|
26 | for index in iterator_lst loop |
| 1864 | 23 | UnorderedMap.add(iterator, Expression.INTEGER(index), replacements); | |
| 1865 | 23 | Iterator.createMappedLocationReplacement(fmap, sub_idx, replacements); | |
| 1866 | 23 | resolveFrames(rest, sizes, subs, var_start, replacements, resize, m, mode, body_size, row); | |
| 1867 | 23 | sub_idx := sub_idx + 1; | |
| 1868 | end for; | ||
| 1869 | then (); | ||
| 1870 | |||
| 1871 | else algorithm | ||
| 1872 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for an unknown reason."}); | |
| 1873 | ✗ | then fail(); | |
| 1874 | end match; | ||
| 1875 | end resolveFrames; | ||
| 1876 | |||
| 1877 | function resolveEquationDimensions | ||
| 1878 | "a component reference in a list of equation dimensions. The second argument to the tuple | ||
| 1879 | is TRUE if its a regular occurence of the cref and FALSE if its a reduced occurence. | ||
| 1880 | The key is created from the dimensions and the additional boolean to look up the cref occurence in the map." | ||
| 1881 | input list<tuple<Dimension, Boolean>> lst "equation dimension and cref regularity tuple list"; | ||
| 1882 | input UnorderedMap<Key, Val2> map "map to look up occurence"; | ||
| 1883 | input Array<Integer> key "mutable key"; | ||
| 1884 | input IntMatrix.Builder m "adjacency matrix builder"; | ||
| 1885 | input Integer mode "index into the mode table"; | ||
| 1886 | input Pointer<Integer> eqn_idx_ptr "mutable equation index"; | ||
| 1887 | input Integer index = 1 "dimension index for the key"; | ||
| 1888 | algorithm | ||
| 1889 | () := match lst | ||
| 1890 | local | ||
| 1891 | Dimension dim; | ||
| 1892 | list<tuple<Dimension, Boolean>> rest; | ||
| 1893 | Integer eqn_idx; | ||
| 1894 | list<Integer> scal_lst; | ||
| 1895 | |||
| 1896 | case {} algorithm | ||
| 1897 | // no further dimensions. resolve with current key config and bump equation index | ||
| 1898 | 34 | eqn_idx := Pointer.access(eqn_idx_ptr); | |
| 1899 | 34 | scal_lst := UnorderedMap.getSafe(arrayList(key), map, sourceInfo()); | |
| 1900 |
2/2✓ Branch 0 taken 98 times.
✓ Branch 1 taken 34 times.
|
132 | for scal_idx in scal_lst loop |
| 1901 | 98 | addMatrixEntry(m, eqn_idx, scal_idx, mode); | |
| 1902 | end for; | ||
| 1903 | 34 | Pointer.update(eqn_idx_ptr, eqn_idx + 1); | |
| 1904 | then (); | ||
| 1905 | |||
| 1906 | case (dim, false)::rest algorithm | ||
| 1907 | // reduced dimension, keep key index at 0 and go deeper with next dimension | ||
| 1908 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
68 | for i in 1:Dimension.size(dim, true) loop |
| 1909 | 34 | resolveEquationDimensions(rest, map, key, m, mode, eqn_idx_ptr, index+1); | |
| 1910 | end for; | ||
| 1911 | then (); | ||
| 1912 | |||
| 1913 | case (dim, true)::rest algorithm | ||
| 1914 | // regular dimension, update key index to corresponding dimension index | ||
| 1915 | // and go deeper with next dimension | ||
| 1916 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
46 | for i in 1:Dimension.size(dim, true) loop |
| 1917 | 34 | arrayUpdate(key, index, i); | |
| 1918 | 34 | resolveEquationDimensions(rest, map, key, m, mode, eqn_idx_ptr, index+1); | |
| 1919 | end for; | ||
| 1920 | then (); | ||
| 1921 | end match; | ||
| 1922 | end resolveEquationDimensions; | ||
| 1923 | |||
| 1924 | function addMatrixEntry | ||
| 1925 | input IntMatrix.Builder m "adjacency matrix builder"; | ||
| 1926 | input Integer eqn_idx; | ||
| 1927 | input Integer var_idx; | ||
| 1928 | input Integer mode "index into the mode table"; | ||
| 1929 | algorithm | ||
| 1930 | // only add the variable if its a viable index. due to unresolved if-expressions in for-loops some branches can access variables | ||
| 1931 | // that seem out of scope but are in fact valid because the if-condition ensures it. | ||
| 1932 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51917 times.
|
51917 | if var_idx > 0 then |
| 1933 | 51917 | IntMatrix.builderAddAux(m, eqn_idx, var_idx, mode); | |
| 1934 | end if; | ||
| 1935 | end addMatrixEntry; | ||
| 1936 | |||
| 1937 | function resolveReductions | ||
| 1938 | input list<tuple<Subscript, Dimension, Boolean>> lst; | ||
| 1939 | input UnorderedMap<Key, Val1> map; | ||
| 1940 | input Array<Integer> key; | ||
| 1941 | input ComponentRef stripped; | ||
| 1942 | input list<Subscript> acc = {}; | ||
| 1943 | input Integer index = 1; | ||
| 1944 | algorithm | ||
| 1945 | () := match lst | ||
| 1946 | local | ||
| 1947 | list<tuple<Subscript, Dimension, Boolean>> rest; | ||
| 1948 | Subscript sub; | ||
| 1949 | Dimension dim; | ||
| 1950 | ComponentRef cref; | ||
| 1951 | Val1 val; | ||
| 1952 | Integer sub_idx; | ||
| 1953 | |||
| 1954 | case {} algorithm | ||
| 1955 | 34 | cref := ComponentRef.mergeSubscripts(listReverse(acc), stripped, true); | |
| 1956 | 34 | val := ComponentRef.scalarizeAll(cref, true); | |
| 1957 | 34 | UnorderedMap.add(arrayList(key), val, map); | |
| 1958 | then (); | ||
| 1959 | |||
| 1960 | case (sub, _, false)::rest algorithm | ||
| 1961 | 34 | resolveReductions(rest, map, key, stripped, sub::acc, index+1); | |
| 1962 | then (); | ||
| 1963 | |||
| 1964 | case (sub, dim, true)::rest algorithm | ||
| 1965 | sub_idx := 1; | ||
| 1966 |
2/2✓ Branch 2 taken 34 times.
✓ Branch 3 taken 12 times.
|
46 | for s in Subscript.scalarize(sub, dim, true) loop |
| 1967 | 34 | arrayUpdate(key, index, sub_idx); | |
| 1968 | 34 | resolveReductions(rest, map, key, stripped, s::acc, index+1); | |
| 1969 | 34 | sub_idx := sub_idx + 1; | |
| 1970 | end for; | ||
| 1971 | then (); | ||
| 1972 | |||
| 1973 | end match; | ||
| 1974 | end resolveReductions; | ||
| 1975 | |||
| 1976 | function combineFrames2Indices | ||
| 1977 | "Iterates over all elements in nested iterators represented by frames. | ||
| 1978 | Converts each of the now integer subscript lists (in combination with | ||
| 1979 | subscript sizes) to a single scalar index of the subscripted cref." | ||
| 1980 | input Integer first "index of first variable. start counting from here"; | ||
| 1981 | input list<Integer> sizes "list of variables sizes"; | ||
| 1982 | input list<Expression> subs "list of cref subscripts"; | ||
| 1983 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames "list of frame tuples containing iterator name and range"; | ||
| 1984 | input UnorderedMap<ComponentRef, Expression> replacements "replacement rules iterator cref -> integer (may have to be simplified)"; | ||
| 1985 | input Boolean resize; | ||
| 1986 | input output list<Integer> indices = {} "list of scalarized indices"; | ||
| 1987 | algorithm | ||
| 1988 | indices := match frames | ||
| 1989 | local | ||
| 1990 | list<tuple<ComponentRef, Expression, Option<Iterator>>> rest; | ||
| 1991 | ComponentRef iterator; | ||
| 1992 | Expression range; | ||
| 1993 | Option<Iterator> map; | ||
| 1994 | Integer start, step, stop; | ||
| 1995 | list<list<Integer>> values; | ||
| 1996 | list<Expression> iterator_exps; | ||
| 1997 | list<Integer> iterator_lst; | ||
| 1998 | Integer sub_idx; | ||
| 1999 | |||
| 2000 | // only occurs for non-for-loop equations (no frames to replace) | ||
| 2001 | case {} algorithm | ||
| 2002 | 8 | values := resolveDimensionsSubscripts(sizes, subs, replacements, resize); | |
| 2003 |
4/4✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 8 times.
|
24 | then list(locationToIndex(sizes, v, first) for v in values); |
| 2004 | |||
| 2005 | // extract numeric information about the range | ||
| 2006 | case (iterator, range, map) :: rest algorithm | ||
| 2007 | iterator_lst := match range | ||
| 2008 | case Expression.RANGE() algorithm | ||
| 2009 | 810 | (start, step, stop) := Expression.getIntegerRange(range, resize); | |
| 2010 | 810 | then List.intRange3(start,step, stop); | |
| 2011 | case Expression.ARRAY() algorithm | ||
| 2012 |
4/4✓ Branch 0 taken 36 times.
✓ Branch 1 taken 12 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 12 times.
|
96 | iterator_exps := list(Expression.map(e, function Replacements.applySimpleExp(replacements = replacements)) for e in range.elements); |
| 2013 |
4/4✓ Branch 0 taken 36 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 12 times.
|
48 | iterator_lst := list(Expression.integerValue(SimplifyExp.simplifyDump(e, true, getInstanceName())) for e in iterator_exps); |
| 2014 | then iterator_lst; | ||
| 2015 | else algorithm | ||
| 2016 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because iterator binding could not be parsed: " | |
| 2017 | + ComponentRef.toString(iterator) + " in " + Expression.toString(range)}); | ||
| 2018 | ✗ | then fail(); | |
| 2019 | end match; | ||
| 2020 | |||
| 2021 | // traverse every index in the range (and possible sub iterators) | ||
| 2022 | sub_idx := 1; | ||
| 2023 |
2/2✓ Branch 0 taken 4122 times.
✓ Branch 1 taken 822 times.
|
4944 | for index in iterator_lst loop |
| 2024 | // create main iterator replacement | ||
| 2025 | 4122 | UnorderedMap.add(iterator, Expression.INTEGER(index), replacements); | |
| 2026 | // create local sub replacements if existent | ||
| 2027 | 4122 | Iterator.createMappedLocationReplacement(map, sub_idx, replacements); | |
| 2028 | |||
| 2029 |
2/2✓ Branch 0 taken 3936 times.
✓ Branch 1 taken 186 times.
|
4122 | if listEmpty(rest) then |
| 2030 | // bottom line, resolve current configuration and create index for it | ||
| 2031 | 3936 | values := resolveDimensionsSubscripts(sizes, subs, replacements, resize); | |
| 2032 |
2/2✓ Branch 1 taken 3933 times.
✓ Branch 2 taken 3936 times.
|
7869 | for v in listReverse(values) loop |
| 2033 | 3933 | indices := locationToIndex(sizes, v, first) :: indices; | |
| 2034 | end for; | ||
| 2035 | else | ||
| 2036 | // not last frame, go deeper | ||
| 2037 | 186 | indices := combineFrames2Indices(first, sizes, subs, rest, replacements, resize, indices); | |
| 2038 | end if; | ||
| 2039 | 4122 | sub_idx := sub_idx + 1; | |
| 2040 | end for; | ||
| 2041 | then indices; | ||
| 2042 | |||
| 2043 | case (iterator, range, _) :: _ algorithm | ||
| 2044 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because uniontype records are wrong: " | |
| 2045 | + ComponentRef.toString(iterator) + " in " + Expression.toString(range)}); | ||
| 2046 | ✗ | then fail(); | |
| 2047 | |||
| 2048 | else algorithm | ||
| 2049 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for an unknown reason."}); | |
| 2050 | ✗ | then fail(); | |
| 2051 | |||
| 2052 | end match; | ||
| 2053 | end combineFrames2Indices; | ||
| 2054 | |||
| 2055 | function combineFramesIndices | ||
| 2056 | "Turns the subscripts of a cref into scalar indices over all frame values. | ||
| 2057 | Tries the arithmetic evaluation first and falls back to the general | ||
| 2058 | expression machinery." | ||
| 2059 | input Integer first; | ||
| 2060 | input list<Integer> sizes; | ||
| 2061 | input list<Expression> subs; | ||
| 2062 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 2063 | input Boolean resize; | ||
| 2064 | output list<Integer> indices; | ||
| 2065 | protected | ||
| 2066 | Boolean ok; | ||
| 2067 | algorithm | ||
| 2068 | 32583 | (ok, indices) := combineFramesArithmetic(first, sizes, subs, frames); | |
| 2069 |
2/2✓ Branch 0 taken 31939 times.
✓ Branch 1 taken 644 times.
|
32583 | if not ok then |
| 2070 | 644 | indices := listReverse(combineFrames2Indices(first, sizes, subs, frames, | |
| 2071 | UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual), resize)); | ||
| 2072 | end if; | ||
| 2073 | end combineFramesIndices; | ||
| 2074 | |||
| 2075 | function combineFramesArithmetic | ||
| 2076 | "Fast path for combineFrames2Indices: every frame has to be a literal | ||
| 2077 | integer range without a mapped location and every subscript has to be | ||
| 2078 | integer arithmetic over the frame iterators. ok is false if it is not, | ||
| 2079 | the general path has to be used then." | ||
| 2080 | input Integer first; | ||
| 2081 | input list<Integer> sizes; | ||
| 2082 | input list<Expression> subs; | ||
| 2083 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames; | ||
| 2084 | output Boolean ok = true; | ||
| 2085 | output list<Integer> indices = {}; | ||
| 2086 | protected | ||
| 2087 | Integer n = listLength(frames); | ||
| 2088 | Integer sz = if n > 0 then n else 1; | ||
| 2089 | array<ComponentRef> names = arrayCreate(sz, ComponentRef.EMPTY()); | ||
| 2090 | array<Integer> values = arrayCreate(sz, 0); | ||
| 2091 | array<Integer> starts = arrayCreate(sz, 0); | ||
| 2092 | array<Integer> steps = arrayCreate(sz, 0); | ||
| 2093 | array<Integer> stops = arrayCreate(sz, 0); | ||
| 2094 | Integer i = 1; | ||
| 2095 | ComponentRef name; | ||
| 2096 | Expression range; | ||
| 2097 | Option<Iterator> map; | ||
| 2098 | algorithm | ||
| 2099 | // an unsubscripted cref yields no combination at all, same as List.combination({}) | ||
| 2100 |
1/2✓ Branch 0 taken 32583 times.
✗ Branch 1 not taken.
|
32583 | if listEmpty(subs) then |
| 2101 | ✗ | return; | |
| 2102 | end if; | ||
| 2103 | |||
| 2104 |
2/2✓ Branch 0 taken 3082 times.
✓ Branch 1 taken 32081 times.
|
35163 | for frame in frames loop |
| 2105 | 3082 | (name, range, map) := frame; | |
| 2106 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 3082 times.
✓ Branch 2 taken 3082 times.
✗ Branch 3 not taken.
|
3082 | if isSome(map) then |
| 2107 | ok := false; | ||
| 2108 | ✗ | return; | |
| 2109 | end if; | ||
| 2110 | 3082 | arrayUpdate(names, i, name); | |
| 2111 | () := match range | ||
| 2112 | local | ||
| 2113 | Integer rstart, rstep, rstop; | ||
| 2114 | case Expression.RANGE(start = Expression.INTEGER(value = rstart), stop = Expression.INTEGER(value = rstop)) | ||
| 2115 | algorithm | ||
| 2116 | rstep := match range.step | ||
| 2117 |
1/2✓ Branch 0 taken 2572 times.
✗ Branch 1 not taken.
|
2572 | case NONE() then if rstart > rstop then -1 else 1; |
| 2118 | case SOME(Expression.INTEGER(value = rstep)) then rstep; | ||
| 2119 | else 0; | ||
| 2120 | end match; | ||
| 2121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if rstep == 0 then |
| 2122 | ok := false; | ||
| 2123 | else | ||
| 2124 | 2580 | arrayUpdate(starts, i, rstart); | |
| 2125 | 2580 | arrayUpdate(steps, i, rstep); | |
| 2126 | 2580 | arrayUpdate(stops, i, rstop); | |
| 2127 | end if; | ||
| 2128 | then (); | ||
| 2129 | else algorithm | ||
| 2130 | ok := false; | ||
| 2131 | then (); | ||
| 2132 | end match; | ||
| 2133 | if not ok then | ||
| 2134 | 502 | return; | |
| 2135 | end if; | ||
| 2136 | 2580 | i := i + 1; | |
| 2137 | end for; | ||
| 2138 | |||
| 2139 | 32081 | (ok, indices) := combineFramesArithmeticWork(first, sizes, subs, names, values, starts, steps, stops, 1, n, ok, indices); | |
| 2140 |
2/2✓ Branch 0 taken 142 times.
✓ Branch 1 taken 31939 times.
|
32081 | if ok then |
| 2141 | 31939 | indices := listReverse(indices); | |
| 2142 | end if; | ||
| 2143 | end combineFramesArithmetic; | ||
| 2144 | |||
| 2145 | function combineFramesArithmeticWork | ||
| 2146 | input Integer first; | ||
| 2147 | input list<Integer> sizes; | ||
| 2148 | input list<Expression> subs; | ||
| 2149 | input array<ComponentRef> names; | ||
| 2150 | input array<Integer> values; | ||
| 2151 | input array<Integer> starts; | ||
| 2152 | input array<Integer> steps; | ||
| 2153 | input array<Integer> stops; | ||
| 2154 | input Integer level; | ||
| 2155 | input Integer nframes; | ||
| 2156 | input output Boolean ok; | ||
| 2157 | input output list<Integer> indices; | ||
| 2158 | protected | ||
| 2159 | Integer v, step, stop, index; | ||
| 2160 | Boolean inBounds; | ||
| 2161 | algorithm | ||
| 2162 |
2/2✓ Branch 0 taken 46372 times.
✓ Branch 1 taken 3367 times.
|
49739 | if level > nframes then |
| 2163 | 46372 | (ok, inBounds, index) := evalFrameIndex(subs, sizes, names, values, nframes, first); | |
| 2164 |
3/4✓ Branch 0 taken 46230 times.
✓ Branch 1 taken 142 times.
✓ Branch 2 taken 46230 times.
✗ Branch 3 not taken.
|
46372 | if ok and inBounds then |
| 2165 | 46230 | indices := index :: indices; | |
| 2166 | end if; | ||
| 2167 | else | ||
| 2168 | 3367 | step := steps[level]; | |
| 2169 | 3367 | stop := stops[level]; | |
| 2170 | 3367 | v := starts[level]; | |
| 2171 |
4/4✓ Branch 0 taken 3240 times.
✓ Branch 1 taken 17646 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 3228 times.
|
20886 | while (step > 0 and v <= stop) or (step < 0 and v >= stop) loop |
| 2172 | 17658 | arrayUpdate(values, level, v); | |
| 2173 | 17658 | (ok, indices) := combineFramesArithmeticWork(first, sizes, subs, names, values, starts, steps, stops, level + 1, nframes, ok, indices); | |
| 2174 |
2/2✓ Branch 0 taken 139 times.
✓ Branch 1 taken 17519 times.
|
17658 | if not ok then |
| 2175 | 139 | return; | |
| 2176 | end if; | ||
| 2177 | 17519 | v := v + step; | |
| 2178 | end while; | ||
| 2179 | end if; | ||
| 2180 | end combineFramesArithmeticWork; | ||
| 2181 | |||
| 2182 | function evalFrameIndex | ||
| 2183 | "Evaluates all subscripts at the current frame values and folds them into the | ||
| 2184 | scalar index, like locationToIndex() does for the general path. inBounds is | ||
| 2185 | false if one of them is outside its dimension, which is no dependency at all." | ||
| 2186 | input list<Expression> subs; | ||
| 2187 | input list<Integer> sizes; | ||
| 2188 | input array<ComponentRef> names; | ||
| 2189 | input array<Integer> values; | ||
| 2190 | input Integer nframes; | ||
| 2191 | input Integer first; | ||
| 2192 | output Boolean ok = true; | ||
| 2193 | output Boolean inBounds = true; | ||
| 2194 | output Integer index = first; | ||
| 2195 | protected | ||
| 2196 | list<Integer> rest_sizes = sizes; | ||
| 2197 | Integer size, value, factor = 1; | ||
| 2198 | algorithm | ||
| 2199 |
2/2✓ Branch 0 taken 130896 times.
✓ Branch 1 taken 46230 times.
|
177126 | for sub in subs loop |
| 2200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 130896 times.
|
130896 | if listEmpty(rest_sizes) then |
| 2201 | ok := false; | ||
| 2202 | ✗ | return; | |
| 2203 | end if; | ||
| 2204 | 130896 | size :: rest_sizes := rest_sizes; | |
| 2205 | 130896 | (ok, value) := evalFrameExp(sub, names, values, nframes); | |
| 2206 |
2/2✓ Branch 0 taken 142 times.
✓ Branch 1 taken 130754 times.
|
130896 | if not ok then |
| 2207 | 142 | return; | |
| 2208 | end if; | ||
| 2209 |
2/4✓ Branch 0 taken 130754 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 130754 times.
|
130754 | if value < 1 or value > size then |
| 2210 | inBounds := false; | ||
| 2211 | ✗ | return; | |
| 2212 | end if; | ||
| 2213 | 130754 | index := index + (value - 1) * factor; | |
| 2214 | 130754 | factor := factor * size; | |
| 2215 | end for; | ||
| 2216 | end evalFrameIndex; | ||
| 2217 | |||
| 2218 | function evalFrameExp | ||
| 2219 | "Evaluates an integer expression at the current frame values. ok is false | ||
| 2220 | for anything but integer literals, frame iterators and integer +, - and *." | ||
| 2221 | input Expression exp; | ||
| 2222 | input array<ComponentRef> names; | ||
| 2223 | input array<Integer> values; | ||
| 2224 | input Integer nframes; | ||
| 2225 | output Boolean ok; | ||
| 2226 | output Integer value; | ||
| 2227 | algorithm | ||
| 2228 | (ok, value) := match exp | ||
| 2229 | local | ||
| 2230 | Integer v1, v2; | ||
| 2231 | Boolean ok1, ok2; | ||
| 2232 | |||
| 2233 | 111663 | case Expression.INTEGER() then (true, exp.value); | |
| 2234 | |||
| 2235 | case Expression.CREF() algorithm | ||
| 2236 | ok := false; | ||
| 2237 | 19099 | value := 0; | |
| 2238 |
2/2✓ Branch 0 taken 19091 times.
✓ Branch 1 taken 8 times.
|
26355 | for i in 1:nframes loop |
| 2239 |
2/2✓ Branch 2 taken 19091 times.
✓ Branch 3 taken 7256 times.
|
26347 | if ComponentRef.isEqual(exp.cref, names[i]) then |
| 2240 | 19091 | value := values[i]; | |
| 2241 | ok := true; | ||
| 2242 | 19091 | break; | |
| 2243 | end if; | ||
| 2244 | end for; | ||
| 2245 | 19099 | then (ok, value); | |
| 2246 | |||
| 2247 | case Expression.BINARY() guard(Type.isInteger(Operator.typeOf(exp.operator))) algorithm | ||
| 2248 | ✗ | (ok1, v1) := evalFrameExp(exp.exp1, names, values, nframes); | |
| 2249 | ✗ | (ok2, v2) := evalFrameExp(exp.exp2, names, values, nframes); | |
| 2250 | ✗ | value := 0; | |
| 2251 | ✗ | if ok1 and ok2 then | |
| 2252 | (ok, value) := match exp.operator.op | ||
| 2253 | ✗ | case NFOperator.Op.ADD then (true, v1 + v2); | |
| 2254 | ✗ | case NFOperator.Op.SUB then (true, v1 - v2); | |
| 2255 | ✗ | case NFOperator.Op.MUL then (true, v1 * v2); | |
| 2256 | else (false, 0); | ||
| 2257 | end match; | ||
| 2258 | else | ||
| 2259 | ok := false; | ||
| 2260 | end if; | ||
| 2261 | ✗ | then (ok, value); | |
| 2262 | |||
| 2263 | case Expression.UNARY() guard(Type.isInteger(Operator.typeOf(exp.operator)) | ||
| 2264 | and exp.operator.op == NFOperator.Op.UMINUS) algorithm | ||
| 2265 | ✗ | (ok, value) := evalFrameExp(exp.exp, names, values, nframes); | |
| 2266 | ✗ | value := -value; | |
| 2267 | then (ok, value); | ||
| 2268 | |||
| 2269 | else (false, 0); | ||
| 2270 | end match; | ||
| 2271 | end evalFrameExp; | ||
| 2272 | |||
| 2273 | function getCrefInFrameIndices | ||
| 2274 | input ComponentRef cref "cref to get indices from"; | ||
| 2275 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames "iterator frames at which to evaluate cref"; | ||
| 2276 | input Mapping mapping "index mapping (only variable mapping needed)"; | ||
| 2277 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 2278 | input Boolean resize; | ||
| 2279 | output list<Integer> scal_lst "scalar indices of cref"; | ||
| 2280 | protected | ||
| 2281 | ComponentRef final_cref; | ||
| 2282 | Integer var_arr_idx, var_start; | ||
| 2283 | algorithm | ||
| 2284 | 32322 | (final_cref, var_arr_idx) := getVarArrIdx(cref, mapping, map); | |
| 2285 | 32322 | (var_start, _) := mapping.var_AtS[var_arr_idx]; | |
| 2286 | |||
| 2287 | // add local indices to start index | ||
| 2288 | 32322 | scal_lst := getCrefInFrameIndicesLocal(cref, final_cref, frames, var_start, resize); | |
| 2289 | end getCrefInFrameIndices; | ||
| 2290 | |||
| 2291 | function getVarArrIdx | ||
| 2292 | input output ComponentRef cref "cref to get indices from"; | ||
| 2293 | input Mapping mapping "index mapping (only variable mapping needed)"; | ||
| 2294 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 2295 | output Integer var_arr_idx; | ||
| 2296 | algorithm | ||
| 2297 | // try to get array index, if it fails, strip the subscripts | ||
| 2298 | (var_arr_idx, cref) := match UnorderedMap.get(cref, map) | ||
| 2299 | case SOME(var_arr_idx) then (var_arr_idx, cref); | ||
| 2300 | else algorithm | ||
| 2301 | 155 | cref := ComponentRef.stripSubscriptsAll(cref); | |
| 2302 | 155 | then (UnorderedMap.getSafe(cref, map, sourceInfo()), cref); | |
| 2303 | end match; | ||
| 2304 | end getVarArrIdx; | ||
| 2305 | |||
| 2306 | public | ||
| 2307 | function getCrefInFrameIndicesLocal | ||
| 2308 | input ComponentRef subscripted_cref; | ||
| 2309 | input ComponentRef stripped_cref; | ||
| 2310 | input list<tuple<ComponentRef, Expression, Option<Iterator>>> frames "iterator frames at which to evaluate cref"; | ||
| 2311 | input Integer var_start; | ||
| 2312 | input Boolean resize; | ||
| 2313 | output list<Integer> scal_lst; | ||
| 2314 | protected | ||
| 2315 | list<Integer> sizes; | ||
| 2316 | list<Expression> subs; | ||
| 2317 | Type ty; | ||
| 2318 | Integer complex_size; | ||
| 2319 | algorithm | ||
| 2320 | // prepare the sizes of the full cref, the subscripts and the type to check if its complex | ||
| 2321 | 32354 | sizes := ComponentRef.sizes(stripped_cref, false, resize); | |
| 2322 | 32354 | subs := ComponentRef.subscriptsToExpression(subscripted_cref, true); | |
| 2323 | 32354 | ty := Type.arrayElementType(ComponentRef.getComponentType(subscripted_cref)); | |
| 2324 | |||
| 2325 | // check if it needs special record handling | ||
| 2326 | scal_lst := match Type.complexSize(ty) | ||
| 2327 | case SOME(complex_size) algorithm | ||
| 2328 | scal_lst := {}; | ||
| 2329 |
1/2✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
|
329 | for i in complex_size:-1:1 loop |
| 2330 | 558 | scal_lst := listAppend(combineFramesIndices(var_start, complex_size :: sizes, Expression.INTEGER(i) :: subs, frames, resize), scal_lst); | |
| 2331 | end for; | ||
| 2332 | then scal_lst; | ||
| 2333 | 32304 | else combineFramesIndices(var_start, sizes, subs, frames, resize); | |
| 2334 | end match; | ||
| 2335 | end getCrefInFrameIndicesLocal; | ||
| 2336 | |||
| 2337 | protected | ||
| 2338 | function resolveDimensionsSubscripts | ||
| 2339 | "uses the replacement module to replace all iterator crefs in the subscript with the current position. | ||
| 2340 | Returns the current positions for each subscript." | ||
| 2341 | input list<Integer> sizes "dimension sizes"; | ||
| 2342 | input list<Expression> subs "subscript expressions"; | ||
| 2343 | input UnorderedMap<ComponentRef, Expression> replacements "replacement map for iterator crefs"; | ||
| 2344 | input Boolean resize; | ||
| 2345 | output list<list<Integer>> values; | ||
| 2346 | protected | ||
| 2347 | list<Expression> replaced; | ||
| 2348 | algorithm | ||
| 2349 | // get all possible subscript combinations | ||
| 2350 |
4/4✓ Branch 0 taken 9357 times.
✓ Branch 1 taken 3967 times.
✓ Branch 2 taken 9357 times.
✓ Branch 3 taken 3967 times.
|
13324 | replaced := list(Expression.map(sub, function Replacements.applySimpleExp(replacements = replacements)) for sub in subs); |
| 2351 |
7/8✓ Branch 0 taken 9357 times.
✓ Branch 1 taken 3967 times.
✓ Branch 2 taken 9357 times.
✓ Branch 3 taken 3967 times.
✓ Branch 4 taken 9357 times.
✓ Branch 5 taken 3967 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3967 times.
|
13324 | values := list(resolveDimensionsSubscript(exp, size, resize) threaded for exp in replaced, size in sizes); |
| 2352 | 3967 | values := List.combination(values); | |
| 2353 | end resolveDimensionsSubscripts; | ||
| 2354 | |||
| 2355 | function resolveDimensionsSubscript | ||
| 2356 | input Expression replaced; | ||
| 2357 | input Integer size; | ||
| 2358 | input Boolean resize; | ||
| 2359 | output list<Integer> res; | ||
| 2360 | protected | ||
| 2361 | Expression rep; | ||
| 2362 | algorithm | ||
| 2363 | 9357 | rep := SimplifyExp.simplifyDump(replaced, true, getInstanceName()); | |
| 2364 | res := match rep | ||
| 2365 | local | ||
| 2366 | Integer start, step, stop; | ||
| 2367 | |||
| 2368 | // just a single element; filter out-of-bounds values (Modelica arrays are 1-indexed) | ||
| 2369 |
3/4✓ Branch 0 taken 9343 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 9343 times.
✗ Branch 3 not taken.
|
9349 | case Expression.INTEGER() then if rep.value >= 1 and rep.value <= size then {rep.value} else {}; |
| 2370 | ✗ | case Expression.ENUM_LITERAL() then {rep.index}; | |
| 2371 | |||
| 2372 | // build list from range | ||
| 2373 | case Expression.RANGE() algorithm | ||
| 2374 | ✗ | (start, step, stop) := Expression.getIntegerRange(rep, resize); | |
| 2375 | ✗ | then List.intRange3(start,step, stop); | |
| 2376 | |||
| 2377 | // resolve individual array elements | ||
| 2378 | case Expression.ARRAY() | ||
| 2379 | ✗ | then List.flatten(list(resolveDimensionsSubscript(e, size, resize) for e in rep.elements)); | |
| 2380 | |||
| 2381 | // assume full dependency if it cannot be evaluated | ||
| 2382 | 8 | else List.intRange(size); | |
| 2383 | end match; | ||
| 2384 | end resolveDimensionsSubscript; | ||
| 2385 | |||
| 2386 | function applyNewFrameRange | ||
| 2387 | "applies new start, step and stop to a frame" | ||
| 2388 | input output Frame frame; | ||
| 2389 | input tuple<Integer, Integer, Integer> range; | ||
| 2390 | algorithm | ||
| 2391 | frame := match frame | ||
| 2392 | local | ||
| 2393 | ComponentRef name; | ||
| 2394 | Expression exp; | ||
| 2395 | Option<Iterator> map; | ||
| 2396 | |||
| 2397 | ✗ | case (name, exp as Expression.RANGE(), map) then (name, Expression.sliceRange(exp, range), map); | |
| 2398 | |||
| 2399 | case (_, exp, _) algorithm | ||
| 2400 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() | |
| 2401 | + " failed because frame expression was not Expression.RANGE(): " + Expression.toString(exp)}); | ||
| 2402 | ✗ | then fail(); | |
| 2403 | end match; | ||
| 2404 | end applyNewFrameRange; | ||
| 2405 | |||
| 2406 | annotation(__OpenModelica_Interface="nbackend"); | ||
| 2407 | end NBSlice; | ||
| 2408 |