OMCompiler/Compiler/NBackEnd/Util/NBAdjacency.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 | encapsulated package NBAdjacency | ||
| 36 | "file: NBAdjacency.mo | ||
| 37 | package: NBAdjacency | ||
| 38 | description: This file contains the functions which will create adjacency matrices. | ||
| 39 | " | ||
| 40 | public | ||
| 41 | // self import | ||
| 42 | import Adjacency = NBAdjacency; | ||
| 43 | |||
| 44 | protected | ||
| 45 | // OF imports | ||
| 46 | import Absyn.Path; | ||
| 47 | |||
| 48 | // Old Simcode imports | ||
| 49 | import OldSimCode = SimCode; | ||
| 50 | |||
| 51 | // NF imports | ||
| 52 | import Call = NFCall; | ||
| 53 | import ComponentRef = NFComponentRef; | ||
| 54 | import Dimension = NFDimension; | ||
| 55 | import Expression = NFExpression; | ||
| 56 | import NFFunction.Function; | ||
| 57 | import SimplifyExp = NFSimplifyExp; | ||
| 58 | import Statement = NFStatement; | ||
| 59 | import Subscript = NFSubscript; | ||
| 60 | import Type = NFType; | ||
| 61 | import Operator = NFOperator; | ||
| 62 | import NFOperator.Op; | ||
| 63 | import Variable = NFVariable; | ||
| 64 | |||
| 65 | // NB imports | ||
| 66 | import Differentiate = NBDifferentiate; | ||
| 67 | import NBDifferentiate.{DifferentiationArguments, DifferentiationType}; | ||
| 68 | import BEquation = NBEquation; | ||
| 69 | import NBEquation.{Equation, EquationAttributes, EquationPointers, Iterator, IfEquationBody, WhenEquationBody, WhenStatement}; | ||
| 70 | import Solve = NBSolve; | ||
| 71 | import BVariable = NBVariable; | ||
| 72 | import NBVariable.{VariablePointers, VarData}; | ||
| 73 | import StrongComponent = NBStrongComponent; | ||
| 74 | import Partition = NBPartition; | ||
| 75 | |||
| 76 | // Util import | ||
| 77 | import Array; | ||
| 78 | import BackendUtil = NBBackendUtil; | ||
| 79 | import BuiltinSystem = System; | ||
| 80 | import Slice = NBSlice; | ||
| 81 | import StringUtil; | ||
| 82 | import Vector; | ||
| 83 | |||
| 84 | public | ||
| 85 | type MatrixStrictness = enumeration(LINEAR, MATCHING, SORTING, FULL); | ||
| 86 | |||
| 87 | function strictnessString | ||
| 88 | input MatrixStrictness s; | ||
| 89 | output String str; | ||
| 90 | algorithm | ||
| 91 | str := match s | ||
| 92 | case MatrixStrictness.LINEAR then "linear"; | ||
| 93 | case MatrixStrictness.MATCHING then "matching"; | ||
| 94 | case MatrixStrictness.SORTING then "sorting"; | ||
| 95 | case MatrixStrictness.FULL then "full"; | ||
| 96 | else "unknown"; | ||
| 97 | end match; | ||
| 98 | end strictnessString; | ||
| 99 | |||
| 100 | uniontype Mapping | ||
| 101 | record MAPPING | ||
| 102 | array<Integer> eqn_StA "eqn: scal_idx -> arr_idx"; | ||
| 103 | array<Integer> var_StA "var: scal_idx -> arr_idx"; | ||
| 104 | array<tuple<Integer,Integer>> eqn_AtS "eqn: arr_idx -> start_idx/length"; | ||
| 105 | array<tuple<Integer,Integer>> var_AtS "var: arr_idx -> start_idx/length"; | ||
| 106 | end MAPPING; | ||
| 107 | |||
| 108 | function toString | ||
| 109 | input Mapping mapping; | ||
| 110 | output String str; | ||
| 111 | protected | ||
| 112 | Integer start, size; | ||
| 113 | algorithm | ||
| 114 | ✗ | str := StringUtil.headline_4("Equation Index Mapping (ARR) -> START | SIZE"); | |
| 115 | ✗ | for i in 1:arrayLength(mapping.eqn_AtS) loop | |
| 116 | ✗ | (start, size) := mapping.eqn_AtS[i]; | |
| 117 | ✗ | str := str + "(" + intString(i) + ")\t" + intString(start) + " | " + intString(size) + "\n"; | |
| 118 | end for; | ||
| 119 | ✗ | str := str + StringUtil.headline_4("Variable Index Mapping (ARR) -> START | SIZE"); | |
| 120 | ✗ | for i in 1:arrayLength(mapping.var_AtS) loop | |
| 121 | ✗ | (start, size) := mapping.var_AtS[i]; | |
| 122 | ✗ | str := str + "(" + intString(i) + ")\t" + intString(start) + " | " + intString(size) + "\n"; | |
| 123 | end for; | ||
| 124 | end toString; | ||
| 125 | |||
| 126 | function empty | ||
| 127 | output Mapping mapping = MAPPING(arrayCreate(0, 0), arrayCreate(0, 0),arrayCreate(0, (0,0)),arrayCreate(0, (0,0))); | ||
| 128 | end empty; | ||
| 129 | |||
| 130 | function create | ||
| 131 | input EquationPointers eqns; | ||
| 132 | input VariablePointers vars; | ||
| 133 | output Mapping mapping; | ||
| 134 | protected | ||
| 135 | list<Pointer<Equation>> eqn_lst = EquationPointers.toList(eqns); | ||
| 136 | list<Pointer<Variable>> var_lst = VariablePointers.toList(vars); | ||
| 137 | array<Integer> eqn_StA, var_StA; | ||
| 138 | array<tuple<Integer,Integer>> eqn_AtS, var_AtS; | ||
| 139 | Integer eqn_scalar_size, var_scalar_size; | ||
| 140 | Integer eqn_idx_scal = 1, eqn_idx_arr = 1, var_idx_scal = 1, var_idx_arr = 1; | ||
| 141 | algorithm | ||
| 142 | // prepare the mappings | ||
| 143 |
4/4✓ Branch 0 taken 15038 times.
✓ Branch 1 taken 2000 times.
✓ Branch 2 taken 15038 times.
✓ Branch 3 taken 2000 times.
|
17038 | eqn_scalar_size := sum(Equation.size(eqn, true) for eqn in eqn_lst); |
| 144 |
4/4✓ Branch 0 taken 11905 times.
✓ Branch 1 taken 2000 times.
✓ Branch 2 taken 11905 times.
✓ Branch 3 taken 2000 times.
|
13905 | var_scalar_size := sum(BVariable.size(var, true) for var in var_lst); |
| 145 | 2000 | eqn_StA := arrayCreate(eqn_scalar_size, -1); | |
| 146 | 2000 | var_StA := arrayCreate(var_scalar_size, -1); | |
| 147 | 2000 | eqn_AtS := arrayCreate(EquationPointers.size(eqns), (-1, -1)); | |
| 148 | 2000 | var_AtS := arrayCreate(VariablePointers.size(vars), (-1, -1)); | |
| 149 | |||
| 150 | // fill the arrays | ||
| 151 | 2000 | (eqn_StA, var_StA, eqn_AtS, var_AtS) := fill_(eqn_StA, var_StA, eqn_AtS, var_AtS, eqn_lst, var_lst, eqn_idx_scal, eqn_idx_arr, var_idx_scal, var_idx_arr); | |
| 152 | |||
| 153 | // compile mapping | ||
| 154 | 2000 | mapping := MAPPING(eqn_StA, var_StA, eqn_AtS, var_AtS); | |
| 155 | end create; | ||
| 156 | |||
| 157 | function expand | ||
| 158 | input output Mapping mapping; | ||
| 159 | input list<Pointer<Equation>> eqn_lst; | ||
| 160 | input list<Pointer<Variable>> var_lst; | ||
| 161 | protected | ||
| 162 | array<Integer> eqn_StA, var_StA; | ||
| 163 | array<tuple<Integer,Integer>> eqn_AtS, var_AtS; | ||
| 164 | Integer eqn_scalar_size, var_scalar_size; | ||
| 165 | Integer neqn_scal = sum(Equation.size(eqn, true) for eqn in eqn_lst); | ||
| 166 | Integer nvar_scal = sum(BVariable.size(var, true) for var in var_lst); | ||
| 167 | Integer neqn_arr = listLength(eqn_lst); | ||
| 168 | Integer nvar_arr = listLength(var_lst); | ||
| 169 | Integer eqn_idx_scal = arrayLength(mapping.eqn_StA) + 1, eqn_idx_arr = arrayLength(mapping.eqn_AtS) + 1; | ||
| 170 | Integer var_idx_scal = arrayLength(mapping.var_StA) + 1, var_idx_arr = arrayLength(mapping.var_AtS) + 1; | ||
| 171 | algorithm | ||
| 172 | |||
| 173 | // copy all data | ||
| 174 | 28 | eqn_StA := Array.expandToSize(eqn_idx_scal - 1 + neqn_scal, mapping.eqn_StA, -1); | |
| 175 | 28 | var_StA := Array.expandToSize(var_idx_scal - 1 + nvar_scal, mapping.var_StA, -1); | |
| 176 | 28 | eqn_AtS := Array.expandToSize(eqn_idx_arr - 1 + neqn_arr, mapping.eqn_AtS, (-1, -1)); | |
| 177 | 28 | var_AtS := Array.expandToSize(var_idx_arr - 1 + nvar_arr, mapping.var_AtS, (-1, -1)); | |
| 178 | |||
| 179 | // fill the new sections | ||
| 180 | 28 | (eqn_StA, var_StA, eqn_AtS, var_AtS) := fill_(eqn_StA, var_StA, eqn_AtS, var_AtS, eqn_lst, var_lst, eqn_idx_scal, eqn_idx_arr, var_idx_scal, var_idx_arr); | |
| 181 | |||
| 182 | // compile mapping | ||
| 183 | 28 | mapping := MAPPING(eqn_StA, var_StA, eqn_AtS, var_AtS); | |
| 184 | end expand; | ||
| 185 | |||
| 186 | function getEqnScalIndices | ||
| 187 | input Integer arr_idx; | ||
| 188 | input Mapping mapping; | ||
| 189 | input Boolean reverse = false; | ||
| 190 | output list<Integer> scal_indices; | ||
| 191 | protected | ||
| 192 | Integer start, length; | ||
| 193 | algorithm | ||
| 194 | ✗ | (start, length) := mapping.eqn_AtS[arr_idx]; | |
| 195 | ✗ | scal_indices := if reverse then | |
| 196 | List.intRange2(start + length - 1, start) else | ||
| 197 | List.intRange2(start, start + length - 1); | ||
| 198 | end getEqnScalIndices; | ||
| 199 | |||
| 200 | function getVarScalIndices | ||
| 201 | input Integer arr_idx; | ||
| 202 | input Mapping mapping; | ||
| 203 | input list<Subscript> subs; | ||
| 204 | input list<Dimension> dims; | ||
| 205 | input Boolean reverse = false; | ||
| 206 | output list<Integer> scal_indices; | ||
| 207 | protected | ||
| 208 | Integer start, length; | ||
| 209 | function subscriptedIndices | ||
| 210 | input Integer start; | ||
| 211 | input Integer length; | ||
| 212 | input list<Integer> slice; | ||
| 213 | output list<Integer> scal_indices; | ||
| 214 | algorithm | ||
| 215 | ✗ | scal_indices := List.intRange2(start, start + length - 1); | |
| 216 | ✗ | if not listEmpty(slice) then | |
| 217 | ✗ | scal_indices := List.keepPositions(scal_indices, slice); | |
| 218 | end if; | ||
| 219 | end subscriptedIndices; | ||
| 220 | algorithm | ||
| 221 | ✗ | (start, length) := mapping.var_AtS[arr_idx]; | |
| 222 | |||
| 223 | scal_indices := match subs | ||
| 224 | local | ||
| 225 | Subscript sub; | ||
| 226 | list<list<Subscript>> subs_lst; | ||
| 227 | list<Integer> slice = {}, dim_sizes, values; | ||
| 228 | |||
| 229 | // no subscripts -> create full index list | ||
| 230 | ✗ | case {} then subscriptedIndices(start, length, {}); | |
| 231 | |||
| 232 | // all subscripts are whole -> create full index list | ||
| 233 | ✗ | case _ guard(List.all(subs, Subscript.isWhole)) then subscriptedIndices(start, length, {}); | |
| 234 | |||
| 235 | // only one subscript -> apply simple rule | ||
| 236 | case {sub} algorithm | ||
| 237 | ✗ | slice := Subscript.toIndexList(sub, length); | |
| 238 | ✗ | then subscriptedIndices(start, length, slice); | |
| 239 | |||
| 240 | // multiple subscripts -> apply location to index mapping rules | ||
| 241 | case _ algorithm | ||
| 242 | ✗ | subs_lst := Subscript.scalarizeList(subs, dims, true); | |
| 243 | ✗ | subs_lst := List.combination(subs_lst); | |
| 244 | ✗ | dim_sizes := list(Dimension.size(dim) for dim in dims); | |
| 245 | ✗ | for sub_lst in listReverse(subs_lst) loop | |
| 246 | ✗ | values := list(Subscript.toInteger(s) for s in sub_lst); | |
| 247 | ✗ | slice := Slice.locationToIndex(dim_sizes, values, start) :: slice; | |
| 248 | end for; | ||
| 249 | then slice; | ||
| 250 | |||
| 251 | else fail(); | ||
| 252 | end match; | ||
| 253 | |||
| 254 | ✗ | if reverse then | |
| 255 | ✗ | scal_indices := listReverse(scal_indices); | |
| 256 | end if; | ||
| 257 | end getVarScalIndices; | ||
| 258 | |||
| 259 | protected | ||
| 260 | function fill_ | ||
| 261 | input output array<Integer> eqn_StA; | ||
| 262 | input output array<Integer> var_StA; | ||
| 263 | input output array<tuple<Integer,Integer>> eqn_AtS; | ||
| 264 | input output array<tuple<Integer,Integer>> var_AtS; | ||
| 265 | input list<Pointer<Equation>> eqn_lst; | ||
| 266 | input list<Pointer<Variable>> var_lst; | ||
| 267 | input Integer eqn_idx_scal_start; | ||
| 268 | input Integer eqn_idx_arr_start; | ||
| 269 | input Integer var_idx_scal_start; | ||
| 270 | input Integer var_idx_arr_start; | ||
| 271 | protected | ||
| 272 | Integer size; | ||
| 273 | Integer eqn_idx_scal = eqn_idx_scal_start; | ||
| 274 | Integer eqn_idx_arr = eqn_idx_arr_start; | ||
| 275 | Integer var_idx_scal = var_idx_scal_start; | ||
| 276 | Integer var_idx_arr= var_idx_arr_start; | ||
| 277 | algorithm | ||
| 278 | // fill equation mapping | ||
| 279 |
2/2✓ Branch 0 taken 15092 times.
✓ Branch 1 taken 2028 times.
|
17120 | for eqn_ptr in eqn_lst loop |
| 280 | 15092 | size := Equation.size(eqn_ptr, true); | |
| 281 | 15092 | eqn_AtS[eqn_idx_arr] := (eqn_idx_scal, size); | |
| 282 |
2/2✓ Branch 0 taken 14771 times.
✓ Branch 1 taken 321 times.
|
44329 | for i in eqn_idx_scal:eqn_idx_scal+size-1 loop |
| 283 | 29237 | eqn_StA[i] := eqn_idx_arr; | |
| 284 | end for; | ||
| 285 | eqn_idx_scal := eqn_idx_scal + size; | ||
| 286 | 15092 | eqn_idx_arr := eqn_idx_arr + 1; | |
| 287 | end for; | ||
| 288 | // fill variable mapping | ||
| 289 |
2/2✓ Branch 0 taken 11905 times.
✓ Branch 1 taken 2028 times.
|
13933 | for var_ptr in var_lst loop |
| 290 | 11905 | size := BVariable.size(var_ptr, true); | |
| 291 | 11905 | var_AtS[var_idx_arr] := (var_idx_scal, size); | |
| 292 |
2/2✓ Branch 0 taken 11904 times.
✓ Branch 1 taken 1 time.
|
41925 | for i in var_idx_scal:var_idx_scal+size-1 loop |
| 293 | 30020 | var_StA[i] := var_idx_arr; | |
| 294 | end for; | ||
| 295 | var_idx_scal := var_idx_scal + size; | ||
| 296 | 11905 | var_idx_arr := var_idx_arr + 1; | |
| 297 | end for; | ||
| 298 | end fill_; | ||
| 299 | end Mapping; | ||
| 300 | |||
| 301 | uniontype Mode | ||
| 302 | record MODE | ||
| 303 | "most of the time this will only have one cref. if there are multiple crefs | ||
| 304 | representing the same variable its a multi mode and the equation needs to | ||
| 305 | be split when solved for it" | ||
| 306 | ComponentRef eqn_name "the equation name"; | ||
| 307 | list<ComponentRef> crefs "the cref(s) to solve for"; | ||
| 308 | Boolean scalarize "true if the equation needs to be scalarized to find the cref to solve for"; | ||
| 309 | end MODE; | ||
| 310 | |||
| 311 | function toString | ||
| 312 | input Mode mode; | ||
| 313 | output String str = "[eqn: " + ComponentRef.toString(mode.eqn_name) + ", crefs: " + List.toString(mode.crefs, ComponentRef.toString) + ", scal: " + boolString(mode.scalarize) + "]"; | ||
| 314 | end toString; | ||
| 315 | |||
| 316 | function hash | ||
| 317 | input Mode mode; | ||
| 318 | output Integer hash = ComponentRef.hash(mode.eqn_name); | ||
| 319 | end hash; | ||
| 320 | |||
| 321 | function isEqual | ||
| 322 | input Mode mode1; | ||
| 323 | input Mode mode2; | ||
| 324 | output Boolean b = ComponentRef.isEqual(mode1.eqn_name, mode2.eqn_name) and mode1.scalarize == mode2.scalarize | ||
| 325 | and List.isEqualOnTrue(mode1.crefs, mode2.crefs, ComponentRef.isEqual); | ||
| 326 | end isEqual; | ||
| 327 | |||
| 328 | function create | ||
| 329 | input ComponentRef eqn_name; | ||
| 330 | input list<ComponentRef> crefs; | ||
| 331 | input Boolean scalarize; | ||
| 332 | output Mode mode = MODE(eqn_name, list(ComponentRef.simplifySubscripts(cref) for cref in crefs), scalarize); | ||
| 333 | end create; | ||
| 334 | |||
| 335 | function merge | ||
| 336 | input Mode mode1; | ||
| 337 | input Mode mode2; | ||
| 338 | output Mode oMode = MODE(mode1.eqn_name, listAppend(mode1.crefs, mode2.crefs), mode1.scalarize or mode2.scalarize); | ||
| 339 | end merge; | ||
| 340 | |||
| 341 | end Mode; | ||
| 342 | |||
| 343 | type ModeTable = Vector<Mode> | ||
| 344 | "the distinct causalization modes. a matrix entry refers to one by its index | ||
| 345 | in here (0 for none), kept in the matrix payload instead of in a map keyed | ||
| 346 | on the (equation, variable) pair."; | ||
| 347 | |||
| 348 | package Modes | ||
| 349 | function new | ||
| 350 | output ModeTable modes = Vector.new<Mode>(0); | ||
| 351 | end new; | ||
| 352 | |||
| 353 | function add | ||
| 354 | input ModeTable modes; | ||
| 355 | input Mode mode; | ||
| 356 | output Integer id; | ||
| 357 | algorithm | ||
| 358 | 24366 | Vector.push(modes, mode); | |
| 359 | 24366 | id := Vector.size(modes); | |
| 360 | end add; | ||
| 361 | |||
| 362 | function get | ||
| 363 | "the mode of the (eqn, var) entry. duplicate entries are merged the way | ||
| 364 | UnorderedMap.addMerge did, newest first, which is the row order." | ||
| 365 | input ModeTable modes; | ||
| 366 | input IntMatrix m; | ||
| 367 | input array<Integer> data; | ||
| 368 | input array<Integer> ids; | ||
| 369 | input Integer eqn; | ||
| 370 | input Integer var; | ||
| 371 | output Option<Mode> res = NONE(); | ||
| 372 | protected | ||
| 373 | Integer first = m.start[eqn]; | ||
| 374 | Mode mode; | ||
| 375 | algorithm | ||
| 376 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 18231 times.
|
60330 | for k in first:first + m.len[eqn] - 1 loop |
| 377 |
4/4✓ Branch 1 taken 18231 times.
✓ Branch 2 taken 23868 times.
✓ Branch 4 taken 18110 times.
✓ Branch 5 taken 121 times.
|
42099 | if data[k] == var and ids[k] > 0 then |
| 378 | 18110 | mode := Vector.getNoBounds(modes, ids[k]); | |
| 379 | res := match res | ||
| 380 | local Mode acc; | ||
| 381 | ✗ | case SOME(acc) then SOME(Mode.merge(acc, mode)); | |
| 382 | else SOME(mode); | ||
| 383 | end match; | ||
| 384 | end if; | ||
| 385 | end for; | ||
| 386 | end get; | ||
| 387 | end Modes; | ||
| 388 | |||
| 389 | uniontype IntMatrix | ||
| 390 | "Adjacency rows stored flat: every row is a slice of one append-only integer | ||
| 391 | buffer. Nothing in here is a pointer, so the collector does not have to walk | ||
| 392 | the nonzeros. aux carries one extra integer per entry (the causalization | ||
| 393 | mode id of the normal matrix), and is empty where it is not used." | ||
| 394 | |||
| 395 | record INT_MATRIX | ||
| 396 | array<Integer> start "row -> 1-based index of its first entry in data"; | ||
| 397 | array<Integer> len "row -> number of entries"; | ||
| 398 | Vector<Integer> data "entry buffer, only appended to"; | ||
| 399 | Vector<Integer> aux "payload parallel to data, empty if unused"; | ||
| 400 | end INT_MATRIX; | ||
| 401 | |||
| 402 | uniontype Builder | ||
| 403 | "The matrix is filled by collecting (row, entry) pairs in any order; | ||
| 404 | fromBuilder() then groups them by row in one counting sort." | ||
| 405 | record BUILDER | ||
| 406 | Vector<Integer> pairs; | ||
| 407 | Vector<Integer> aux; | ||
| 408 | Boolean hasAux; | ||
| 409 | end BUILDER; | ||
| 410 | end Builder; | ||
| 411 | |||
| 412 | function new | ||
| 413 | input Integer rows; | ||
| 414 | output IntMatrix m = INT_MATRIX(arrayCreate(rows, 1), arrayCreate(rows, 0), Vector.new<Integer>(0), Vector.new<Integer>(0)); | ||
| 415 | end new; | ||
| 416 | |||
| 417 | function rows | ||
| 418 | input IntMatrix m; | ||
| 419 | output Integer n = arrayLength(m.start); | ||
| 420 | end rows; | ||
| 421 | |||
| 422 | function nonZeroCount | ||
| 423 | input IntMatrix m; | ||
| 424 | output Integer count = sum(l for l in m.len); | ||
| 425 | end nonZeroCount; | ||
| 426 | |||
| 427 | function entries | ||
| 428 | "the raw entry buffer, indexed by start[row] .. start[row]+len[row]-1. | ||
| 429 | invalidated by anything that adds entries" | ||
| 430 | input IntMatrix m; | ||
| 431 | output array<Integer> data = Vector.rawArray(m.data); | ||
| 432 | end entries; | ||
| 433 | |||
| 434 | function payload | ||
| 435 | input IntMatrix m; | ||
| 436 | output array<Integer> aux = Vector.rawArray(m.aux); | ||
| 437 | end payload; | ||
| 438 | |||
| 439 | function toList | ||
| 440 | input IntMatrix m; | ||
| 441 | input Integer row; | ||
| 442 | output list<Integer> lst = {}; | ||
| 443 | protected | ||
| 444 | array<Integer> data = Vector.rawArray(m.data); | ||
| 445 | Integer first = m.start[row]; | ||
| 446 | algorithm | ||
| 447 | ✗ | for k in first + m.len[row] - 1:-1:first loop | |
| 448 | ✗ | lst := data[k] :: lst; | |
| 449 | end for; | ||
| 450 | end toList; | ||
| 451 | |||
| 452 | function setRow | ||
| 453 | "replaces a row by appending its new entries to the buffer. the payload, | ||
| 454 | if any, is not maintained" | ||
| 455 | input IntMatrix m; | ||
| 456 | input Integer row; | ||
| 457 | input list<Integer> values; | ||
| 458 | algorithm | ||
| 459 | ✗ | arrayUpdate(m.start, row, Vector.size(m.data) + 1); | |
| 460 | ✗ | arrayUpdate(m.len, row, listLength(values)); | |
| 461 | ✗ | for v in values loop | |
| 462 | ✗ | Vector.push(m.data, v); | |
| 463 | end for; | ||
| 464 | end setRow; | ||
| 465 | |||
| 466 | function setRowFromArray | ||
| 467 | "setRow with the first n entries of values" | ||
| 468 | input IntMatrix m; | ||
| 469 | input Integer row; | ||
| 470 | input array<Integer> values; | ||
| 471 | input Integer n; | ||
| 472 | algorithm | ||
| 473 | 2578 | arrayUpdate(m.start, row, Vector.size(m.data) + 1); | |
| 474 | 2578 | arrayUpdate(m.len, row, n); | |
| 475 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2578 times.
|
24379 | for i in 1:n loop |
| 476 | 21801 | Vector.push(m.data, values[i]); | |
| 477 | end for; | ||
| 478 | end setRowFromArray; | ||
| 479 | |||
| 480 | function reserveData | ||
| 481 | "makes room for extra more entries so that adding them does not grow the buffer" | ||
| 482 | input IntMatrix m; | ||
| 483 | input Integer extra; | ||
| 484 | input Boolean withAux = false; | ||
| 485 | algorithm | ||
| 486 | 1634 | Vector.reserve(m.data, Vector.size(m.data) + extra); | |
| 487 |
2/2✓ Branch 0 taken 1622 times.
✓ Branch 1 taken 12 times.
|
1634 | if withAux then |
| 488 | 12 | Vector.reserve(m.aux, Vector.size(m.aux) + extra); | |
| 489 | end if; | ||
| 490 | end reserveData; | ||
| 491 | |||
| 492 | function clearRow | ||
| 493 | input IntMatrix m; | ||
| 494 | input Integer row; | ||
| 495 | algorithm | ||
| 496 | 23098 | arrayUpdate(m.len, row, 0); | |
| 497 | end clearRow; | ||
| 498 | |||
| 499 | function copyRow | ||
| 500 | "appends row src of `from` (whose buffer must be given) as row dst of m" | ||
| 501 | input IntMatrix from; | ||
| 502 | input Integer src; | ||
| 503 | input array<Integer> from_data; | ||
| 504 | input array<Integer> from_aux; | ||
| 505 | input IntMatrix m; | ||
| 506 | input Integer dst; | ||
| 507 | protected | ||
| 508 | Integer first = from.start[src], n = from.len[src]; | ||
| 509 | Boolean aux = arrayLength(from_aux) > 0; | ||
| 510 | algorithm | ||
| 511 | 1304 | arrayUpdate(m.start, dst, Vector.size(m.data) + 1); | |
| 512 | 1304 | arrayUpdate(m.len, dst, n); | |
| 513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1304 times.
|
4843 | for k in first:first + n - 1 loop |
| 514 | 3539 | Vector.push(m.data, from_data[k]); | |
| 515 |
1/2✓ Branch 0 taken 3539 times.
✗ Branch 1 not taken.
|
3539 | if aux then |
| 516 | 3539 | Vector.push(m.aux, from_aux[k]); | |
| 517 | end if; | ||
| 518 | end for; | ||
| 519 | end copyRow; | ||
| 520 | |||
| 521 | function expandRows | ||
| 522 | input output IntMatrix m; | ||
| 523 | input Integer shift; | ||
| 524 | algorithm | ||
| 525 |
2/2✓ Branch 0 taken 1244 times.
✓ Branch 1 taken 378 times.
|
1622 | if shift > 0 then |
| 526 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 378 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 378 times.
|
1134 | m := INT_MATRIX(Array.expandToSize(arrayLength(m.start) + shift, m.start, 1), |
| 527 | Array.expandToSize(arrayLength(m.len) + shift, m.len, 0), m.data, m.aux); | ||
| 528 | end if; | ||
| 529 | end expandRows; | ||
| 530 | |||
| 531 | function transpose | ||
| 532 | "transposes the matrix, dropping any payload. a negative entry -v means | ||
| 533 | that row occurs negated in column v. each result row comes out descending, | ||
| 534 | matching what List.sort(.., intLt) produced before. | ||
| 535 | slack reserves buffer space for rows that are merged in afterwards." | ||
| 536 | input IntMatrix m; | ||
| 537 | input Integer size "number of rows of the result (does not have to be square!)"; | ||
| 538 | input Integer slack = 0; | ||
| 539 | output IntMatrix mT; | ||
| 540 | protected | ||
| 541 | array<Integer> data = Vector.rawArray(m.data); | ||
| 542 | array<Integer> start, len, out; | ||
| 543 | Integer n = arrayLength(m.start), nnz = 0, idx, pos, first; | ||
| 544 | Boolean negated = false; | ||
| 545 | algorithm | ||
| 546 | 5467 | start := arrayCreate(size, 1); | |
| 547 | 5467 | len := arrayCreate(size, 0); | |
| 548 | |||
| 549 |
1/2✓ Branch 0 taken 5467 times.
✗ Branch 1 not taken.
|
85271 | for r in 1:n loop |
| 550 | 79804 | first := m.start[r]; | |
| 551 |
2/2✓ Branch 1 taken 59880 times.
✓ Branch 2 taken 19924 times.
|
228315 | for k in first:first + m.len[r] - 1 loop |
| 552 | 148511 | idx := intAbs(data[k]); | |
| 553 |
1/2✓ Branch 0 taken 148511 times.
✗ Branch 1 not taken.
|
148511 | if idx > 0 and idx <= size then |
| 554 | 148511 | arrayUpdate(len, idx, len[idx] + 1); | |
| 555 | 148511 | nnz := nnz + 1; | |
| 556 |
2/4✓ Branch 0 taken 148511 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 148511 times.
|
148511 | negated := negated or data[k] < 0; |
| 557 | else | ||
| 558 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for variable index " + intString(data[k]) + ". | |
| 559 | The variables have to be dense (without empty spaces) for this to work!"}); | ||
| 560 | end if; | ||
| 561 | end for; | ||
| 562 | end for; | ||
| 563 | |||
| 564 | pos := 1; | ||
| 565 |
1/2✓ Branch 0 taken 5467 times.
✗ Branch 1 not taken.
|
5467 | for c in 1:size loop |
| 566 | 80154 | arrayUpdate(start, c, pos); | |
| 567 | 80154 | pos := pos + len[c]; | |
| 568 | end for; | ||
| 569 | |||
| 570 | 5467 | out := arrayCreate(nnz + slack, 0); | |
| 571 | |||
| 572 | // scatter, using start as the cursor and winding it back afterwards. | ||
| 573 | // positive entries first, rows descending | ||
| 574 |
1/2✓ Branch 0 taken 5467 times.
✗ Branch 1 not taken.
|
85271 | for r in n:-1:1 loop |
| 575 | 79804 | first := m.start[r]; | |
| 576 |
2/2✓ Branch 1 taken 59880 times.
✓ Branch 2 taken 19924 times.
|
228315 | for k in first:first + m.len[r] - 1 loop |
| 577 | 148511 | idx := data[k]; | |
| 578 |
1/2✓ Branch 0 taken 148511 times.
✗ Branch 1 not taken.
|
148511 | if idx > 0 and idx <= size then |
| 579 | 148511 | arrayUpdate(out, start[idx], r); | |
| 580 | 148511 | arrayUpdate(start, idx, start[idx] + 1); | |
| 581 | end if; | ||
| 582 | end for; | ||
| 583 | end for; | ||
| 584 | |||
| 585 | // then the negated ones, rows ascending so that -row descends | ||
| 586 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5467 times.
|
5467 | if negated then |
| 587 | ✗ | for r in 1:n loop | |
| 588 | ✗ | first := m.start[r]; | |
| 589 | ✗ | for k in first:first + m.len[r] - 1 loop | |
| 590 | ✗ | idx := data[k]; | |
| 591 | ✗ | if idx < 0 and -idx <= size then | |
| 592 | ✗ | arrayUpdate(out, start[-idx], -r); | |
| 593 | ✗ | arrayUpdate(start, -idx, start[-idx] + 1); | |
| 594 | end if; | ||
| 595 | end for; | ||
| 596 | end for; | ||
| 597 | end if; | ||
| 598 | |||
| 599 |
1/2✓ Branch 0 taken 5467 times.
✗ Branch 1 not taken.
|
85621 | for c in 1:size loop |
| 600 | 80154 | arrayUpdate(start, c, start[c] - len[c]); | |
| 601 | end for; | ||
| 602 | |||
| 603 | 5467 | mT := INT_MATRIX(start, len, Vector.fromArrayNoCopy(out, nnz), Vector.new<Integer>(0)); | |
| 604 | end transpose; | ||
| 605 | |||
| 606 | function newBuilder | ||
| 607 | input Integer capacity = 0; | ||
| 608 | input Boolean withAux = false; | ||
| 609 | output Builder b = Builder.BUILDER(Vector.new<Integer>(2 * capacity), | ||
| 610 | Vector.new<Integer>(if withAux then capacity else 0), withAux); | ||
| 611 | end newBuilder; | ||
| 612 | |||
| 613 | function builderAdd | ||
| 614 | input Builder b; | ||
| 615 | input Integer row; | ||
| 616 | input Integer value; | ||
| 617 | algorithm | ||
| 618 | 9628 | Vector.push(b.pairs, row); | |
| 619 | 9628 | Vector.push(b.pairs, value); | |
| 620 | end builderAdd; | ||
| 621 | |||
| 622 | function builderAddAux | ||
| 623 | input Builder b; | ||
| 624 | input Integer row; | ||
| 625 | input Integer value; | ||
| 626 | input Integer aux; | ||
| 627 | algorithm | ||
| 628 | 51950 | Vector.push(b.pairs, row); | |
| 629 | 51950 | Vector.push(b.pairs, value); | |
| 630 | 51950 | Vector.push(b.aux, aux); | |
| 631 | end builderAddAux; | ||
| 632 | |||
| 633 | function builderAddList | ||
| 634 | "adds a whole row front, keeping the order of the list" | ||
| 635 | input Builder b; | ||
| 636 | input Integer row; | ||
| 637 | input list<Integer> values; | ||
| 638 | input Integer aux = 0; | ||
| 639 | algorithm | ||
| 640 |
2/2✓ Branch 2 taken 639 times.
✓ Branch 3 taken 318 times.
|
957 | for v in listReverse(values) loop |
| 641 | 639 | Vector.push(b.pairs, row); | |
| 642 | 639 | Vector.push(b.pairs, v); | |
| 643 |
1/2✓ Branch 0 taken 639 times.
✗ Branch 1 not taken.
|
639 | if b.hasAux then |
| 644 | 639 | Vector.push(b.aux, aux); | |
| 645 | end if; | ||
| 646 | end for; | ||
| 647 | end builderAddList; | ||
| 648 | |||
| 649 | function toBuilder | ||
| 650 | "seeds a builder with the entries of an existing matrix, oldest first, so that | ||
| 651 | fromBuilder puts them back in the same order" | ||
| 652 | input IntMatrix m; | ||
| 653 | input Integer capacity = 0; | ||
| 654 | input Boolean withAux = false; | ||
| 655 | output Builder b; | ||
| 656 | protected | ||
| 657 | array<Integer> data = Vector.rawArray(m.data); | ||
| 658 | array<Integer> aux = Vector.rawArray(m.aux); | ||
| 659 | Integer nnz = nonZeroCount(m), first; | ||
| 660 | algorithm | ||
| 661 | 3833 | b := newBuilder(intMax(nnz, capacity), withAux); | |
| 662 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 3833 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3833 times.
|
66461 | for r in 1:arrayLength(m.start) loop |
| 663 | 58795 | first := m.start[r]; | |
| 664 |
2/2✓ Branch 1 taken 26969 times.
✓ Branch 2 taken 31826 times.
|
118388 | for k in first + m.len[r] - 1:-1:first loop |
| 665 | 59593 | Vector.push(b.pairs, r); | |
| 666 | 59593 | Vector.push(b.pairs, data[k]); | |
| 667 |
1/2✓ Branch 0 taken 59593 times.
✗ Branch 1 not taken.
|
59593 | if withAux then |
| 668 | 59593 | Vector.push(b.aux, aux[k]); | |
| 669 | end if; | ||
| 670 | end for; | ||
| 671 | end for; | ||
| 672 | end toBuilder; | ||
| 673 | |||
| 674 | function fromBuilder | ||
| 675 | "groups the collected pairs by row. entries were prepended to their row | ||
| 676 | before, so the pairs are distributed back to front." | ||
| 677 | input Builder b; | ||
| 678 | input Integer rows; | ||
| 679 | output IntMatrix m; | ||
| 680 | protected | ||
| 681 | array<Integer> raw = Vector.rawArray(b.pairs); | ||
| 682 | array<Integer> raux = Vector.rawArray(b.aux); | ||
| 683 | array<Integer> start, len, out, aout; | ||
| 684 | Integer n = intDiv(Vector.size(b.pairs), 2), r, pos = 1, p; | ||
| 685 | algorithm | ||
| 686 | 4908 | start := arrayCreate(rows, 1); | |
| 687 | 4908 | len := arrayCreate(rows, 0); | |
| 688 | |||
| 689 |
2/2✓ Branch 0 taken 4811 times.
✓ Branch 1 taken 97 times.
|
126718 | for i in 1:n loop |
| 690 | 121810 | r := raw[2*i - 1]; | |
| 691 | 121810 | arrayUpdate(len, r, len[r] + 1); | |
| 692 | end for; | ||
| 693 | |||
| 694 |
2/2✓ Branch 0 taken 4907 times.
✓ Branch 1 taken 1 time.
|
4908 | for i in 1:rows loop |
| 695 | 68854 | arrayUpdate(start, i, pos); | |
| 696 | 68854 | pos := pos + len[i]; | |
| 697 | end for; | ||
| 698 | |||
| 699 | 4908 | out := arrayCreate(n, 0); | |
| 700 |
2/2✓ Branch 0 taken 1063 times.
✓ Branch 1 taken 3845 times.
|
5971 | aout := arrayCreate(if b.hasAux then n else 0, 0); |
| 701 | |||
| 702 | // scatter, using start as the cursor and winding it back afterwards | ||
| 703 |
2/2✓ Branch 0 taken 4811 times.
✓ Branch 1 taken 97 times.
|
126718 | for i in n:-1:1 loop |
| 704 | 121810 | r := raw[2*i - 1]; | |
| 705 | 121810 | p := start[r]; | |
| 706 | 121810 | arrayUpdate(out, p, raw[2*i]); | |
| 707 |
2/2✓ Branch 0 taken 112182 times.
✓ Branch 1 taken 9628 times.
|
121810 | if b.hasAux then |
| 708 | 112182 | arrayUpdate(aout, p, raux[i]); | |
| 709 | end if; | ||
| 710 | 121810 | arrayUpdate(start, r, p + 1); | |
| 711 | end for; | ||
| 712 | |||
| 713 |
2/2✓ Branch 0 taken 4907 times.
✓ Branch 1 taken 1 time.
|
73762 | for i in 1:rows loop |
| 714 | 68854 | arrayUpdate(start, i, start[i] - len[i]); | |
| 715 | end for; | ||
| 716 | |||
| 717 | 4908 | m := INT_MATRIX(start, len, Vector.fromArrayNoCopy(out, n), Vector.fromArrayNoCopy(aout, arrayLength(aout))); | |
| 718 | end fromBuilder; | ||
| 719 | |||
| 720 | function toString | ||
| 721 | input IntMatrix m; | ||
| 722 | output String str = ""; | ||
| 723 | protected | ||
| 724 | Integer skip = stringLength(intString(arrayLength(m.start))) + 1; | ||
| 725 | String tmp; | ||
| 726 | algorithm | ||
| 727 | ✗ | for row in 1:arrayLength(m.start) loop | |
| 728 | ✗ | tmp := intString(row); | |
| 729 | ✗ | str := str + "\t(" + tmp + ")" + StringUtil.repeat(" ", skip - stringLength(tmp)) + List.toString(toList(m, row), intString) + "\n"; | |
| 730 | end for; | ||
| 731 | end toString; | ||
| 732 | end IntMatrix; | ||
| 733 | |||
| 734 | uniontype Matrix | ||
| 735 | "used to store adjacency information for the bipartite graph representing the system of equations and variables | ||
| 736 | you have to create it in this specific order: EMPTY->FULL->FINAL(LINEAR)->FINAL->(MATCHING)->FINAL(SORTING) | ||
| 737 | and store the FULL for further use." | ||
| 738 | |||
| 739 | record EMPTY "placeholder for empty matrices, just stores intended strictness" | ||
| 740 | MatrixStrictness st; | ||
| 741 | end EMPTY; | ||
| 742 | |||
| 743 | record FULL "contains all information needed. create specific final matrices from this" | ||
| 744 | array<ComponentRef> equation_names; | ||
| 745 | array<UnorderedSet<ComponentRef>> occurrences; | ||
| 746 | array<UnorderedMap<ComponentRef, Dependency>> dependencies; | ||
| 747 | array<UnorderedMap<ComponentRef, Solvability>> solvabilities; | ||
| 748 | array<UnorderedSet<ComponentRef>> repetitions; | ||
| 749 | Mapping mapping; | ||
| 750 | end FULL; | ||
| 751 | |||
| 752 | record FINAL "specific final matrix, defined by its strictness" | ||
| 753 | IntMatrix m "eqn -> vars"; | ||
| 754 | IntMatrix mT "var -> eqns"; | ||
| 755 | Mapping mapping "index mapping scalar <-> array"; | ||
| 756 | ModeTable modes "array reconstruction information"; | ||
| 757 | MatrixStrictness st "strictness with which it was created"; | ||
| 758 | end FINAL; | ||
| 759 | |||
| 760 | record SPARSITY "contains sparsity information to create sparsity patterns for jacobians" | ||
| 761 | array<ComponentRef> equation_names; | ||
| 762 | array<Iterator> equation_iterators; | ||
| 763 | array<UnorderedMap<ComponentRef, Dependency>> dependencies; | ||
| 764 | array<UnorderedSet<ComponentRef>> repetitions; | ||
| 765 | array<list<ComponentRef>> solved_crefs; | ||
| 766 | end SPARSITY; | ||
| 767 | |||
| 768 | function createFull | ||
| 769 | input VariablePointers vars; | ||
| 770 | input EquationPointers eqns; | ||
| 771 | input Partition.Kind kind = NBPartition.Kind.ODE; | ||
| 772 | output Matrix adj; | ||
| 773 | protected | ||
| 774 | Integer index, size = EquationPointers.size(eqns); | ||
| 775 | array<ComponentRef> equation_names; | ||
| 776 | array<UnorderedSet<ComponentRef>> occurrences; | ||
| 777 | array<UnorderedMap<ComponentRef, Dependency>> dependencies; | ||
| 778 | array<UnorderedMap<ComponentRef, Solvability>> solvabilities; | ||
| 779 | array<UnorderedSet<ComponentRef>> repetitions; | ||
| 780 | UnorderedSet<ComponentRef> occ_set, rep_set; | ||
| 781 | UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 782 | UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 783 | Mapping mapping; | ||
| 784 | algorithm | ||
| 785 | // only create matrix if there are any variables or equations | ||
| 786 |
3/4✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1904 times.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
|
1905 | if ExpandableArray.getNumberOfElements(vars.varArr) > 0 or ExpandableArray.getNumberOfElements(eqns.eqArr) > 0 then |
| 787 | // create empty arrays for the structures | ||
| 788 | 1905 | equation_names := arrayCreate(size, ComponentRef.EMPTY()); | |
| 789 | 1905 | occurrences := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 790 | 1905 | dependencies := arrayCreate(size, UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual)); | |
| 791 | 1905 | solvabilities := arrayCreate(size, UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual)); | |
| 792 | 1905 | repetitions := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 793 | // loop over each equation and create the corresponding maps and sets | ||
| 794 |
2/2✓ Branch 1 taken 14432 times.
✓ Branch 2 taken 1905 times.
|
16337 | for eqn_ptr in EquationPointers.toList(eqns) loop |
| 795 | 14432 | index := UnorderedMap.getSafe(Equation.getEqnName(eqn_ptr), eqns.map, sourceInfo()); | |
| 796 | 14432 | dep_map := UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual); | |
| 797 | 14432 | sol_map := UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual); | |
| 798 | 14432 | rep_set := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 799 | 14432 | occ_set := collectDependenciesEquation(Pointer.access(eqn_ptr), kind, vars.map, dep_map, sol_map, rep_set); | |
| 800 | 14432 | addInitialStartOccurrences(occ_set, dep_map, sol_map, rep_set, kind); | |
| 801 | 14432 | equation_names[index] := Equation.getEqnName(eqn_ptr); | |
| 802 | 14432 | occurrences[index] := occ_set; | |
| 803 | 14432 | dependencies[index] := dep_map; | |
| 804 | 14432 | solvabilities[index] := sol_map; | |
| 805 | 14432 | repetitions[index] := rep_set; | |
| 806 | end for; | ||
| 807 | // create the index mapping and the matrix | ||
| 808 | 1905 | mapping := Mapping.create(eqns, vars); | |
| 809 | 1905 | adj := FULL(equation_names, occurrences, dependencies, solvabilities, repetitions, mapping); | |
| 810 | else | ||
| 811 | adj := EMPTY(MatrixStrictness.FULL); | ||
| 812 | end if; | ||
| 813 |
1/2✓ Branch 1 taken 1905 times.
✗ Branch 2 not taken.
|
1905 | if Flags.isSet(Flags.BLT_MATRIX_DUMP) then |
| 814 | ✗ | print(StringUtil.headline_1("Creating Adjacency Matrices") + "\n"); | |
| 815 | ✗ | print(EquationPointers.toString(eqns) + "\n"); | |
| 816 | ✗ | print(VariablePointers.toString(vars) + "\n"); | |
| 817 | ✗ | print(toString(adj, "Full") + "\n"); | |
| 818 | ✗ | print(solvabilityString(adj, "Full") + "\n"); | |
| 819 | ✗ | print(dependencyString(adj, "Full") + "\n"); | |
| 820 | end if; | ||
| 821 | end createFull; | ||
| 822 | |||
| 823 | function subFull | ||
| 824 | "creates the full matrix of a subset of equations and variables from an | ||
| 825 | existing one, sharing its per-equation maps. eqn_indices are the indices | ||
| 826 | of eqns in full, in the order of eqns." | ||
| 827 | input Matrix full; | ||
| 828 | input list<Integer> eqn_indices; | ||
| 829 | input EquationPointers eqns; | ||
| 830 | input VariablePointers vars; | ||
| 831 | output Matrix sub; | ||
| 832 | protected | ||
| 833 | Integer size = listLength(eqn_indices), j = 1; | ||
| 834 | array<ComponentRef> equation_names; | ||
| 835 | array<UnorderedSet<ComponentRef>> occurrences, repetitions; | ||
| 836 | array<UnorderedMap<ComponentRef, Dependency>> dependencies; | ||
| 837 | array<UnorderedMap<ComponentRef, Solvability>> solvabilities; | ||
| 838 | algorithm | ||
| 839 | sub := match full | ||
| 840 | case FULL() guard(size > 0) algorithm | ||
| 841 | 95 | equation_names := arrayCreate(size, ComponentRef.EMPTY()); | |
| 842 | 95 | occurrences := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 843 | 95 | dependencies := arrayCreate(size, UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual)); | |
| 844 | 95 | solvabilities := arrayCreate(size, UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual)); | |
| 845 | 95 | repetitions := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 846 |
2/2✓ Branch 0 taken 606 times.
✓ Branch 1 taken 95 times.
|
701 | for i in eqn_indices loop |
| 847 | 606 | equation_names[j] := full.equation_names[i]; | |
| 848 | 606 | occurrences[j] := full.occurrences[i]; | |
| 849 | 606 | dependencies[j] := full.dependencies[i]; | |
| 850 | 606 | solvabilities[j] := full.solvabilities[i]; | |
| 851 | 606 | repetitions[j] := full.repetitions[i]; | |
| 852 | 606 | j := j + 1; | |
| 853 | end for; | ||
| 854 | 95 | then FULL(equation_names, occurrences, dependencies, solvabilities, repetitions, Mapping.create(eqns, vars)); | |
| 855 | else EMPTY(MatrixStrictness.FULL); | ||
| 856 | end match; | ||
| 857 | end subFull; | ||
| 858 | |||
| 859 | function fullToFinal | ||
| 860 | input Matrix full; | ||
| 861 | input UnorderedMap<ComponentRef, Integer> vars_map; | ||
| 862 | input UnorderedMap<ComponentRef, Integer> eqns_map; | ||
| 863 | input EquationPointers eqns; | ||
| 864 | input MatrixStrictness st; | ||
| 865 | input Iterator iter = Iterator.EMPTY() "optional iterator the whole system might be surrounded by"; | ||
| 866 | output Matrix adj = upgrade(EMPTY(MatrixStrictness.FULL), full, vars_map, eqns_map, eqns, st, iter); | ||
| 867 | end fullToFinal; | ||
| 868 | |||
| 869 | function fullToSparsity | ||
| 870 | input Matrix full; | ||
| 871 | input list<StrongComponent> comps; | ||
| 872 | input UnorderedSet<ComponentRef> seed_set; | ||
| 873 | input UnorderedSet<ComponentRef> pder_set; | ||
| 874 | input UnorderedMap<ComponentRef, ComponentRef> diff_map; | ||
| 875 | input Boolean isAdjoint = false; | ||
| 876 | output Matrix sparsity; | ||
| 877 | |||
| 878 | type Dependencies = list<ComponentRef>; | ||
| 879 | function filterSet | ||
| 880 | input ComponentRef cref; | ||
| 881 | input UnorderedSet<ComponentRef> set; | ||
| 882 | output Boolean b = UnorderedSet.contains(cref, set) or | ||
| 883 | UnorderedSet.contains(ComponentRef.stripSubscriptsAll(cref), set); | ||
| 884 | end filterSet; | ||
| 885 | |||
| 886 | function expandSlice | ||
| 887 | "a slice (e.g. i[1:2]) whose elements are seeds depends on each of the elements" | ||
| 888 | input ComponentRef cref; | ||
| 889 | input UnorderedMap<ComponentRef, ComponentRef> diff_map; | ||
| 890 | output list<ComponentRef> crefs; | ||
| 891 | protected | ||
| 892 | Type ty; | ||
| 893 | algorithm | ||
| 894 | crefs := {cref}; | ||
| 895 |
4/4✓ Branch 1 taken 4522 times.
✓ Branch 2 taken 1885 times.
✓ Branch 5 taken 1260 times.
✓ Branch 6 taken 625 times.
|
6407 | if not (UnorderedMap.contains(cref, diff_map) or UnorderedMap.contains(ComponentRef.stripSubscriptsAll(cref), diff_map)) then |
| 896 | 625 | ty := ComponentRef.getSubscriptedType(cref); | |
| 897 |
3/4✓ Branch 1 taken 537 times.
✓ Branch 2 taken 88 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 88 times.
|
625 | if Type.isArray(ty) and Type.sizeOf(ty) <= 256 then |
| 898 |
6/6✓ Branch 2 taken 224 times.
✓ Branch 3 taken 144 times.
✓ Branch 4 taken 368 times.
✓ Branch 5 taken 88 times.
✓ Branch 6 taken 144 times.
✓ Branch 7 taken 88 times.
|
456 | crefs := list(c for c guard(UnorderedMap.contains(c, diff_map)) in ComponentRef.scalarizeAll(cref, false)); |
| 899 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 64 times.
|
88 | if listEmpty(crefs) then |
| 900 | crefs := {cref}; | ||
| 901 | end if; | ||
| 902 | end if; | ||
| 903 | end if; | ||
| 904 | end expandSlice; | ||
| 905 | algorithm | ||
| 906 | sparsity := match full | ||
| 907 | local | ||
| 908 | UnorderedMap<ComponentRef, Integer> index_map = UnorderedMap.new<Integer>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 909 | UnorderedMap<ComponentRef, Dependencies> inner_map = UnorderedMap.new<Dependencies>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 910 | list<Pointer<Equation>> eqns; | ||
| 911 | list<ComponentRef> var_crefs, pder_crefs, tmp_crefs, own_vars; | ||
| 912 | ComponentRef eqn_name, dep_cref, seed_cref, pder_cref; | ||
| 913 | Option<ComponentRef> oseed_cref; | ||
| 914 | Integer eqn_index; | ||
| 915 | Iterator iter; | ||
| 916 | Dependency dep; | ||
| 917 | list<tuple<list<ComponentRef>, Dependency, Boolean>> local_deps; | ||
| 918 | Boolean repeated; | ||
| 919 | list<ComponentRef> inner_deps; | ||
| 920 | Boolean changed; | ||
| 921 | Option<list<ComponentRef>> inner_opt; | ||
| 922 | UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 923 | UnorderedSet<ComponentRef> rep_set; | ||
| 924 | |||
| 925 | list<ComponentRef> eqn_names = {}; | ||
| 926 | list<Iterator> eqn_iters = {}; | ||
| 927 | list<UnorderedMap<ComponentRef, Dependency>> deps = {}; | ||
| 928 | list<UnorderedSet<ComponentRef>> reps = {}; | ||
| 929 | list<list<ComponentRef>> solved_crefs = {}; | ||
| 930 | list<ComponentRef> iter_names; | ||
| 931 | UnorderedSet<ComponentRef> own_iters; | ||
| 932 | UnorderedMap<ComponentRef, Dependencies> seed_elements = UnorderedMap.new<Dependencies>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 933 | UnorderedSet<ComponentRef> no_iters = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | ||
| 934 | UnorderedMap<ComponentRef, SliceAliases> slice_map = UnorderedMap.new<SliceAliases>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 935 | UnorderedMap<ComponentRef, InnerTemplates> template_map = UnorderedMap.new<InnerTemplates>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 936 | Boolean handled; | ||
| 937 | list<ComponentRef> alias_deps, template_deps; | ||
| 938 | |||
| 939 | case FULL() algorithm | ||
| 940 | // create the equation name -> index map | ||
| 941 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
✓ Branch 2 taken 169 times.
✗ Branch 3 not taken.
|
2034 | for i in 1:arrayLength(full.equation_names) loop |
| 942 | 1696 | UnorderedMap.add(full.equation_names[i], i, index_map); | |
| 943 | end for; | ||
| 944 | |||
| 945 | // element seeds by variable name, for dependencies with iterators that can not be resolved | ||
| 946 |
2/2✓ Branch 1 taken 1726 times.
✓ Branch 2 taken 169 times.
|
1895 | for key in UnorderedMap.keyList(diff_map) loop |
| 947 |
4/6✓ Branch 1 taken 122 times.
✓ Branch 2 taken 1604 times.
✓ Branch 5 taken 122 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 122 times.
✗ Branch 10 not taken.
|
1726 | if ComponentRef.hasSubscripts(key) and List.all(ComponentRef.subscriptsAllFlat(key), Subscript.isLiteral) |
| 948 | and not UnorderedMap.contains(ComponentRef.stripSubscriptsAll(key), diff_map) then | ||
| 949 | 244 | UnorderedMap.add(ComponentRef.stripSubscriptsAll(key), key :: UnorderedMap.getOrDefault(ComponentRef.stripSubscriptsAll(key), seed_elements, {}), seed_elements); | |
| 950 | end if; | ||
| 951 | end for; | ||
| 952 | |||
| 953 | // get only relevant equations | ||
| 954 | // check equation name. (STRONG COMPONENTS, NO NEED FOR EQUATIONS?) | ||
| 955 | // if it is EITHER inner or result, map all deps with tmp | ||
| 956 | // if it is an inner equation save the mapping to tmp name -> deps | ||
| 957 | // if it is a result equation save the mapping to final name -> deps | ||
| 958 |
2/2✓ Branch 0 taken 1701 times.
✓ Branch 1 taken 169 times.
|
1870 | for comp in comps loop |
| 959 | 1701 | eqns := StrongComponent.getEquations(comp); | |
| 960 | 1701 | var_crefs := StrongComponent.getVariableCrefs(comp); | |
| 961 | |||
| 962 |
2/2✓ Branch 0 taken 1704 times.
✓ Branch 1 taken 1701 times.
|
3405 | for eqn in eqns loop |
| 963 | 1704 | eqn_name := Equation.getEqnName(eqn); | |
| 964 | 1704 | eqn_index := UnorderedMap.getSafe(eqn_name, index_map, sourceInfo()); | |
| 965 | |||
| 966 | // map the dependencies with the inner maps | ||
| 967 | 1704 | local_deps := {}; | |
| 968 | 1704 | changed := false; | |
| 969 | // the variable a single equation solves is no input of it | ||
| 970 |
2/2✓ Branch 1 taken 1699 times.
✓ Branch 2 taken 5 times.
|
1704 | own_vars := if listLength(eqns) == 1 then var_crefs else {}; |
| 971 |
8/8✓ Branch 6 taken 911 times.
✓ Branch 7 taken 2979 times.
✓ Branch 8 taken 3890 times.
✓ Branch 9 taken 1704 times.
✓ Branch 10 taken 2979 times.
✓ Branch 11 taken 1704 times.
✓ Branch 13 taken 2979 times.
✓ Branch 14 taken 1704 times.
|
8573 | for tpl in list(t for t guard(not List.any(own_vars, function ComponentRef.isEqual(cref2 = Util.tuple21(t)))) |
| 972 | in UnorderedMap.toList(full.dependencies[eqn_index])) loop | ||
| 973 | 2979 | (dep_cref, dep) := tpl; | |
| 974 | 2979 | repeated := UnorderedSet.contains(dep_cref, full.repetitions[eqn_index]); | |
| 975 | (inner_deps, changed) := match UnorderedMap.get(dep_cref, inner_map) | ||
| 976 | // with resizable arrays other slices of the variable (e.g. solved by an algebraic | ||
| 977 | // loop) can have the same iterator but another range, also use their dependencies | ||
| 978 | case SOME(inner_deps) guard Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) and not filterSet(dep_cref, seed_set) and ComponentRef.hasSubscripts(dep_cref) algorithm | ||
| 979 | 70 | inner_opt := UnorderedMap.get(ComponentRef.stripSubscriptsAll(dep_cref), inner_map); | |
| 980 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
|
70 | if isSome(inner_opt) then |
| 981 |
6/6✓ Branch 2 taken 97 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 70 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 70 times.
|
180 | inner_deps := UnorderedSet.unique_list(listAppend(inner_deps, List.flatten(list(sparsityExpandForeignIterators(c, no_iters, seed_elements) |
| 982 | for c guard not List.contains(inner_deps, c, ComponentRef.isEqual) in Util.getOption(inner_opt)))), ComponentRef.hash, ComponentRef.isEqual); | ||
| 983 | end if; | ||
| 984 | then (inner_deps, true); | ||
| 985 | case SOME(inner_deps) then (inner_deps, true); | ||
| 986 | else algorithm | ||
| 987 | // Base-key fallback for subscripted inner LS vars (partial-slice NLS). | ||
| 988 | // Guard prevents outer seed elements (which strip to the same base key | ||
| 989 | // that may be in inner_map) from being misclassified as inner deps. | ||
| 990 | inner_deps := {dep_cref}; | ||
| 991 |
2/2✓ Branch 1 taken 235 times.
✓ Branch 2 taken 1967 times.
|
2202 | alias_deps := if filterSet(dep_cref, seed_set) then {} else sparsitySliceAliasDeps(dep_cref, slice_map); |
| 992 | handled := false; | ||
| 993 | 2202 | template_deps := {}; | |
| 994 |
2/2✓ Branch 1 taken 235 times.
✓ Branch 2 taken 1967 times.
|
2202 | if not filterSet(dep_cref, seed_set) then |
| 995 | 235 | (handled, template_deps) := sparsityTemplateDeps(dep_cref, template_map); | |
| 996 | end if; | ||
| 997 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2202 times.
|
2202 | if not listEmpty(alias_deps) then |
| 998 | inner_deps := dep_cref :: alias_deps; | ||
| 999 | changed := true; | ||
| 1000 | elseif handled then | ||
| 1001 | 116 | inner_deps := dep_cref :: template_deps; | |
| 1002 | changed := true; | ||
| 1003 | elseif not filterSet(dep_cref, seed_set) then | ||
| 1004 | 119 | inner_opt := UnorderedMap.get(ComponentRef.stripSubscriptsAll(dep_cref), inner_map); | |
| 1005 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 33 times.
|
119 | if isSome(inner_opt) then |
| 1006 | // keep the cref itself, other elements of the same array might be seeds. | ||
| 1007 | // iterators of the found dependencies belong to another equation and can not be | ||
| 1008 | // matched with the ones of this equation (e.g. x[i+1] = y[i]), use all elements | ||
| 1009 |
4/4✓ Branch 1 taken 412 times.
✓ Branch 2 taken 86 times.
✓ Branch 3 taken 412 times.
✓ Branch 4 taken 86 times.
|
498 | inner_deps := dep_cref :: List.flatten(list(sparsityExpandForeignIterators(c, no_iters, seed_elements) for c in Util.getOption(inner_opt))); |
| 1010 | changed := true; | ||
| 1011 | end if; | ||
| 1012 | end if; | ||
| 1013 | then (inner_deps, changed); | ||
| 1014 | end match; | ||
| 1015 |
2/2✓ Branch 0 taken 2702 times.
✓ Branch 1 taken 277 times.
|
5681 | local_deps := (inner_deps, dep, repeated) :: local_deps; |
| 1016 | end for; | ||
| 1017 | |||
| 1018 | 1704 | (pder_crefs, tmp_crefs) := List.splitOnTrue(var_crefs, function filterSet(set = pder_set)); | |
| 1019 | |||
| 1020 | // handle result rows | ||
| 1021 |
2/2✓ Branch 0 taken 871 times.
✓ Branch 1 taken 833 times.
|
1704 | if not listEmpty(pder_crefs) then |
| 1022 | // create a new dependency map for this row and get all relevant seeds | ||
| 1023 | 871 | dep_map := UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual); | |
| 1024 | 871 | rep_set := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 1025 | 871 | (iter_names, _, _) := Iterator.getFrames(Equation.getForIterator(Pointer.access(eqn))); | |
| 1026 | 871 | own_iters := UnorderedSet.fromList(iter_names, ComponentRef.hash, ComponentRef.isEqual); | |
| 1027 |
2/2✓ Branch 0 taken 2002 times.
✓ Branch 1 taken 871 times.
|
2873 | for tpl in local_deps loop |
| 1028 | // this might lead to duplicate occurrences. can and should not be optimized here | ||
| 1029 | // as dependency information might not be combinable. optimize afterwards! | ||
| 1030 | // ToDo: combine dependencies | ||
| 1031 | 2002 | (inner_deps, dep, repeated) := tpl; | |
| 1032 |
4/4✓ Branch 0 taken 2484 times.
✓ Branch 1 taken 2002 times.
✓ Branch 2 taken 2484 times.
✓ Branch 3 taken 2002 times.
|
4486 | inner_deps := List.flatten(list(sparsityExpandForeignIterators(c, own_iters, seed_elements) for c in inner_deps)); |
| 1033 |
6/6✓ Branch 0 taken 2493 times.
✓ Branch 1 taken 2002 times.
✓ Branch 2 taken 2493 times.
✓ Branch 3 taken 2002 times.
✓ Branch 6 taken 2523 times.
✓ Branch 7 taken 2002 times.
|
7018 | for dep_cref in List.flatten(list(expandSlice(c, diff_map) for c in inner_deps)) loop |
| 1034 |
2/2✓ Branch 1 taken 2468 times.
✓ Branch 2 taken 55 times.
|
2523 | if filterSet(dep_cref, seed_set) then |
| 1035 | // Try subscripted key first (NLS with per-element scalar seeds), then | ||
| 1036 | // base key with subscript copy (ODE/DAE with full-array base seeds). | ||
| 1037 | // Not found in either: not one of this Jacobian's own unknowns, so its | ||
| 1038 | // partial derivative here is zero -- skip instead of erroring. | ||
| 1039 | oseed_cref := match UnorderedMap.get(dep_cref, diff_map) | ||
| 1040 | case SOME(seed_cref) then SOME(seed_cref); | ||
| 1041 | else match UnorderedMap.get(ComponentRef.stripSubscriptsAll(dep_cref), diff_map) | ||
| 1042 | // Strip subscripts from the base seed before copying so that | ||
| 1043 | // origin subscripts (iterator or literal) merge onto an empty | ||
| 1044 | // template rather than clashing with existing literal subscripts. | ||
| 1045 | 394 | case SOME(seed_cref) then SOME(ComponentRef.copySubscripts(dep_cref, ComponentRef.stripSubscriptsAll(seed_cref))); | |
| 1046 | else NONE(); | ||
| 1047 | end match; | ||
| 1048 | end match; | ||
| 1049 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 2468 times.
✓ Branch 2 taken 2451 times.
✓ Branch 3 taken 17 times.
|
2468 | if isSome(oseed_cref) then |
| 1050 | 2451 | seed_cref := Util.getOption(oseed_cref); | |
| 1051 | 2451 | UnorderedMap.add(seed_cref, dep, dep_map); | |
| 1052 |
2/2✓ Branch 0 taken 67 times.
✓ Branch 1 taken 2384 times.
|
2451 | if repeated then |
| 1053 | 67 | UnorderedSet.add(seed_cref, rep_set); | |
| 1054 | end if; | ||
| 1055 | end if; | ||
| 1056 | end if; | ||
| 1057 | end for; | ||
| 1058 | end for; | ||
| 1059 | |||
| 1060 | // Store result variables (state derivatives) in inner_map so later | ||
| 1061 | // result equations can trace transitive dependencies through them. | ||
| 1062 | // e.g. der(x_i) = f(der(x_j), x_k) with der(x_j) = g(x_s) -> x_s dep. | ||
| 1063 |
2/2✓ Branch 0 taken 209 times.
✓ Branch 1 taken 662 times.
|
871 | if changed then |
| 1064 |
4/4✓ Branch 0 taken 479 times.
✓ Branch 1 taken 209 times.
✓ Branch 2 taken 479 times.
✓ Branch 3 taken 209 times.
|
688 | inner_deps := List.flatten(list(Util.tuple31(tpl) for tpl in local_deps)); |
| 1065 | 209 | inner_deps := UnorderedSet.unique_list(inner_deps, ComponentRef.hash, ComponentRef.isEqual); | |
| 1066 | else | ||
| 1067 | 662 | inner_deps := UnorderedMap.keyList(full.dependencies[eqn_index]); | |
| 1068 | end if; | ||
| 1069 |
4/4✓ Branch 0 taken 2214 times.
✓ Branch 1 taken 871 times.
✓ Branch 2 taken 2214 times.
✓ Branch 3 taken 871 times.
|
3085 | inner_deps := List.filterOnTrue(List.flatten(list(expandSlice(c, diff_map) for c in inner_deps)), function filterSet(set = seed_set)); |
| 1070 |
2/2✓ Branch 0 taken 873 times.
✓ Branch 1 taken 871 times.
|
1744 | for cref in pder_crefs loop |
| 1071 | 873 | sparsityAddInner(cref, inner_deps, inner_map); | |
| 1072 | 873 | sparsityAddTemplate(cref, inner_deps, template_map); | |
| 1073 | end for; | ||
| 1074 | |||
| 1075 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 860 times.
|
871 | if isAdjoint then |
| 1076 | // The adjoint evaluates rows of the primal Jacobian. Map each | ||
| 1077 | // primal result row to its adjoint seed variable. The runtime | ||
| 1078 | // later transposes the generated primal CSC pattern to CSR. | ||
| 1079 |
4/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 11 times.
|
22 | pder_crefs := list( |
| 1080 | match UnorderedMap.get(ComponentRef.stripSubscriptsAll(cref), diff_map) | ||
| 1081 | 11 | case SOME(pder_cref) then ComponentRef.copySubscripts(cref, pder_cref); | |
| 1082 | else algorithm | ||
| 1083 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed because no adjoint seed was found for " | |
| 1084 | + ComponentRef.toString(cref) + " in diff_map."}); | ||
| 1085 | ✗ | then fail(); | |
| 1086 | end match | ||
| 1087 | for cref in pder_crefs); | ||
| 1088 | else | ||
| 1089 | try | ||
| 1090 |
4/4✓ Branch 0 taken 862 times.
✓ Branch 1 taken 860 times.
✓ Branch 2 taken 862 times.
✓ Branch 3 taken 860 times.
|
1722 | pder_crefs := list(BVariable.getPartnerCref(cref, function BVariable.getVarPDer(isTmp = false)) for cref in pder_crefs); |
| 1091 | else | ||
| 1092 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for " + List.toString(pder_crefs, ComponentRef.toString) | |
| 1093 | + " because they were supposed to be a row vars but at least one does not have a corresponding partial derivative."}); | ||
| 1094 | ✗ | fail(); | |
| 1095 | end try; | ||
| 1096 | end if; | ||
| 1097 | |||
| 1098 | // save the row/result dependencies | ||
| 1099 | // get the iterators (potentially need local iterators?) | ||
| 1100 | 871 | eqn_names := eqn_name :: eqn_names; | |
| 1101 | 1742 | eqn_iters := Equation.getForIterator(Pointer.access(eqn)) :: eqn_iters; | |
| 1102 | 871 | deps := dep_map :: deps; | |
| 1103 | 871 | reps := rep_set :: reps; | |
| 1104 | solved_crefs := pder_crefs :: solved_crefs; | ||
| 1105 | end if; | ||
| 1106 | |||
| 1107 | // handle inner temporary dependencies | ||
| 1108 |
2/2✓ Branch 0 taken 838 times.
✓ Branch 1 taken 866 times.
|
1704 | if not listEmpty(tmp_crefs) then |
| 1109 |
2/2✓ Branch 0 taken 517 times.
✓ Branch 1 taken 321 times.
|
838 | if changed then |
| 1110 | // some dependencies were mapped. additional dependency information is irrelevant | ||
| 1111 |
4/4✓ Branch 0 taken 740 times.
✓ Branch 1 taken 517 times.
✓ Branch 2 taken 740 times.
✓ Branch 3 taken 517 times.
|
1257 | inner_deps := List.flatten(list(Util.tuple31(tpl) for tpl in local_deps)); |
| 1112 | 517 | inner_deps := UnorderedSet.unique_list(inner_deps, ComponentRef.hash, ComponentRef.isEqual); | |
| 1113 | else | ||
| 1114 | // nothing changed, just use the original dependencies | ||
| 1115 | 321 | inner_deps := UnorderedMap.keyList(full.dependencies[eqn_index]); | |
| 1116 | end if; | ||
| 1117 | |||
| 1118 | // filter inner dependencies for relevant seeds and add | ||
| 1119 |
4/4✓ Branch 0 taken 1700 times.
✓ Branch 1 taken 838 times.
✓ Branch 2 taken 1700 times.
✓ Branch 3 taken 838 times.
|
2538 | inner_deps := List.filterOnTrue(List.flatten(list(expandSlice(c, diff_map) for c in inner_deps)), function filterSet(set = seed_set)); |
| 1120 | // with resizable arrays the variables of an algebraic loop depend on whole arrays, | ||
| 1121 | // the iterators of its equations do not correspond to the ones of other equations | ||
| 1122 |
4/4✓ Branch 1 taken 128 times.
✓ Branch 2 taken 710 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 126 times.
|
838 | if Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) and StrongComponent.isAlgebraicLoop(comp) then |
| 1123 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 2 times.
|
7 | inner_deps := UnorderedSet.unique_list(list(ComponentRef.stripSubscriptsAll(c) for c in inner_deps), ComponentRef.hash, ComponentRef.isEqual); |
| 1124 | end if; | ||
| 1125 |
2/2✓ Branch 0 taken 885 times.
✓ Branch 1 taken 838 times.
|
1723 | for cref in tmp_crefs loop |
| 1126 | 885 | sparsityAddInner(cref, inner_deps, inner_map); | |
| 1127 | 885 | sparsityAddTemplate(cref, inner_deps, template_map); | |
| 1128 | end for; | ||
| 1129 | 838 | sparsityAddSliceAlias(Pointer.access(eqn), tmp_crefs, seed_set, slice_map); | |
| 1130 | end if; | ||
| 1131 | end for; | ||
| 1132 | end for; | ||
| 1133 | 169 | then SPARSITY( | |
| 1134 | equation_names = listArray(listReverse(eqn_names)), | ||
| 1135 | equation_iterators = listArray(listReverse(eqn_iters)), | ||
| 1136 | dependencies = listArray(listReverse(deps)), | ||
| 1137 | repetitions = listArray(listReverse(reps)), | ||
| 1138 | solved_crefs = listArray(listReverse(solved_crefs))); | ||
| 1139 | |||
| 1140 | ✗ | case EMPTY() then SPARSITY( | |
| 1141 | equation_names = listArray({}), | ||
| 1142 | equation_iterators = listArray({}), | ||
| 1143 | dependencies = listArray({}), | ||
| 1144 | repetitions = listArray({}), | ||
| 1145 | solved_crefs = listArray({})); | ||
| 1146 | |||
| 1147 | else algorithm | ||
| 1148 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong matrix type. | |
| 1149 | Expected: full, Got :" + strictnessString(getStrictness(full)) + "."}); | ||
| 1150 | ✗ | then fail(); | |
| 1151 | end match; | ||
| 1152 | |||
| 1153 |
1/2✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
|
169 | if Flags.isSet(Flags.BLT_MATRIX_DUMP) then |
| 1154 | ✗ | print(toString(sparsity) + "\n"); | |
| 1155 | end if; | ||
| 1156 | end fullToSparsity; | ||
| 1157 | |||
| 1158 | type InnerTemplate = tuple<ComponentRef, list<ComponentRef>> "solved cref with the subscripts of its equation, its dependencies"; | ||
| 1159 | type InnerTemplates = list<InnerTemplate>; | ||
| 1160 | |||
| 1161 | function sparsityAddTemplate | ||
| 1162 | input ComponentRef cref; | ||
| 1163 | input list<ComponentRef> deps; | ||
| 1164 | input UnorderedMap<ComponentRef, InnerTemplates> template_map; | ||
| 1165 | protected | ||
| 1166 | ComponentRef stripped = ComponentRef.stripSubscriptsAll(cref); | ||
| 1167 | algorithm | ||
| 1168 | 3516 | UnorderedMap.add(stripped, (cref, deps) :: UnorderedMap.getOrDefault(stripped, template_map, {}), template_map); | |
| 1169 | end sparsityAddTemplate; | ||
| 1170 | |||
| 1171 | function sparsityTemplateDeps | ||
| 1172 | "x[e] from the inner equations solving x[f(i)] with dependencies y[g(i)]: y[g(f^-1(e))]. | ||
| 1173 | Not handled if a subscript can not be matched this way." | ||
| 1174 | input ComponentRef cref; | ||
| 1175 | input UnorderedMap<ComponentRef, InnerTemplates> template_map; | ||
| 1176 | output Boolean handled = false; | ||
| 1177 | output list<ComponentRef> deps = {}; | ||
| 1178 | protected | ||
| 1179 | InnerTemplates templates = UnorderedMap.getOrDefault(ComponentRef.stripSubscriptsAll(cref), template_map, {}); | ||
| 1180 | list<Subscript> subs = ComponentRef.subscriptsAllWithWholeFlat(cref); | ||
| 1181 | Integer status; | ||
| 1182 | UnorderedMap<ComponentRef, Expression> bindings; | ||
| 1183 | ComponentRef key, dep; | ||
| 1184 | list<ComponentRef> key_deps; | ||
| 1185 | Boolean matched = false; | ||
| 1186 | algorithm | ||
| 1187 |
2/2✓ Branch 0 taken 264 times.
✓ Branch 1 taken 165 times.
|
429 | for template in templates loop |
| 1188 | 264 | (key, key_deps) := template; | |
| 1189 | 264 | (status, bindings) := sparsityUnify(ComponentRef.subscriptsAllWithWholeFlat(key), subs); | |
| 1190 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 194 times.
|
264 | if status == 2 then |
| 1191 | 70 | return; | |
| 1192 | elseif status == 1 then | ||
| 1193 | matched := true; | ||
| 1194 |
2/2✓ Branch 0 taken 246 times.
✓ Branch 1 taken 176 times.
|
422 | for d in key_deps loop |
| 1195 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 246 times.
|
246 | if sparsityHasUnbound(d, bindings) then |
| 1196 | // an iterator of the inner equation that does not occur in the solved cref | ||
| 1197 | ✗ | deps := ComponentRef.stripSubscriptsAll(d) :: deps; | |
| 1198 | else | ||
| 1199 | 246 | dep := ComponentRef.mapExp(ComponentRef.mapExp(d, function sparsityBind(bindings = bindings)), sparsitySimplify); | |
| 1200 |
1/2✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
|
246 | if sparsityInBounds(dep) then |
| 1201 | deps := dep :: deps; | ||
| 1202 | end if; | ||
| 1203 | end if; | ||
| 1204 | end for; | ||
| 1205 | end if; | ||
| 1206 | end for; | ||
| 1207 | handled := matched; | ||
| 1208 | end sparsityTemplateDeps; | ||
| 1209 | |||
| 1210 | function sparsityUnify | ||
| 1211 | "0: the subscripts address different elements, 1: they match with the bindings, 2: unknown" | ||
| 1212 | input list<Subscript> key_subs; | ||
| 1213 | input list<Subscript> subs; | ||
| 1214 | output Integer status = 1; | ||
| 1215 | output UnorderedMap<ComponentRef, Expression> bindings = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 1216 | protected | ||
| 1217 | Expression key_exp, exp, value, offset; | ||
| 1218 | Boolean ok, negated; | ||
| 1219 | ComponentRef iter; | ||
| 1220 | algorithm | ||
| 1221 |
2/2✓ Branch 2 taken 4 times.
✓ Branch 3 taken 260 times.
|
264 | if listLength(key_subs) <> listLength(subs) then |
| 1222 | status := 2; | ||
| 1223 | 4 | return; | |
| 1224 | end if; | ||
| 1225 |
2/2✓ Branch 1 taken 355 times.
✓ Branch 2 taken 176 times.
|
531 | for tpl in List.zip(key_subs, subs) loop |
| 1226 | () := match tpl | ||
| 1227 | case (Subscript.WHOLE(), _) then (); | ||
| 1228 | // a literal or a parameter (x[N]) binds nothing, it can only be told apart from another literal | ||
| 1229 | case (Subscript.INDEX(index = key_exp), _) guard(not sparsityHasIterator(key_exp)) algorithm | ||
| 1230 | () := match Util.tuple22(tpl) | ||
| 1231 | case Subscript.INDEX(index = exp) guard(Expression.isInteger(exp) and Expression.isInteger(key_exp)) algorithm | ||
| 1232 |
1/2✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | if Expression.integerValue(exp) <> Expression.integerValue(key_exp) then |
| 1233 | status := 0; | ||
| 1234 | end if; | ||
| 1235 | then (); | ||
| 1236 | else (); | ||
| 1237 | end match; | ||
| 1238 | then (); | ||
| 1239 | // a symbolic index without iterators (e.g. x[N] of a resizable array) may match, like a literal | ||
| 1240 | case (Subscript.INDEX(index = key_exp), _) guard(not Expression.contains(key_exp, Expression.isIterator)) then (); | ||
| 1241 | case (Subscript.INDEX(index = key_exp), Subscript.INDEX(index = exp)) algorithm | ||
| 1242 | 166 | (ok, iter, offset, negated) := sparsityIteratorOffset(key_exp); | |
| 1243 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 166 times.
|
166 | if ok then |
| 1244 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 165 times.
|
166 | value := if negated |
| 1245 | then SimplifyExp.simplify(Expression.BINARY(offset, Operator.makeSub(Type.INTEGER()), exp)) | ||
| 1246 | else SimplifyExp.simplify(Expression.BINARY(exp, Operator.makeSub(Type.INTEGER()), offset)); | ||
| 1247 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 166 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
166 | if UnorderedMap.contains(iter, bindings) and not Expression.isEqual(value, UnorderedMap.getSafe(iter, bindings, sourceInfo())) then |
| 1248 | status := 2; | ||
| 1249 | else | ||
| 1250 | 166 | UnorderedMap.add(iter, value, bindings); | |
| 1251 | end if; | ||
| 1252 | else | ||
| 1253 | status := 2; | ||
| 1254 | end if; | ||
| 1255 | then (); | ||
| 1256 | else algorithm | ||
| 1257 | status := 2; | ||
| 1258 | then (); | ||
| 1259 | end match; | ||
| 1260 | if status <> 1 then | ||
| 1261 | 84 | return; | |
| 1262 | end if; | ||
| 1263 | end for; | ||
| 1264 | end sparsityUnify; | ||
| 1265 | |||
| 1266 | function sparsityIteratorOffset | ||
| 1267 | "i + c, c + i, i - c and i as (i, c, false), c - i as (i, c, true); c without iterators" | ||
| 1268 | input Expression exp; | ||
| 1269 | output Boolean ok = true; | ||
| 1270 | output ComponentRef iter = ComponentRef.EMPTY(); | ||
| 1271 | output Expression offset = Expression.INTEGER(0); | ||
| 1272 | output Boolean negated = false; | ||
| 1273 | algorithm | ||
| 1274 | () := match exp | ||
| 1275 | case Expression.CREF() guard(ComponentRef.isIterator(exp.cref)) algorithm | ||
| 1276 | 155 | iter := exp.cref; | |
| 1277 | then (); | ||
| 1278 | case Expression.BINARY(exp1 = Expression.CREF(cref = iter), operator = Operator.OPERATOR(op = Op.ADD), exp2 = offset) | ||
| 1279 | guard(ComponentRef.isIterator(iter) and not sparsityHasIterator(offset)) then (); | ||
| 1280 | case Expression.BINARY(exp1 = offset, operator = Operator.OPERATOR(op = Op.ADD), exp2 = Expression.CREF(cref = iter)) | ||
| 1281 | guard(ComponentRef.isIterator(iter) and not sparsityHasIterator(offset)) then (); | ||
| 1282 | case Expression.BINARY(exp1 = Expression.CREF(cref = iter), operator = Operator.OPERATOR(op = Op.SUB), exp2 = offset) | ||
| 1283 | guard(ComponentRef.isIterator(iter) and not sparsityHasIterator(offset)) algorithm | ||
| 1284 | ✗ | offset := Expression.negate(offset); | |
| 1285 | then (); | ||
| 1286 | case Expression.BINARY(exp1 = offset, operator = Operator.OPERATOR(op = Op.SUB), exp2 = Expression.CREF(cref = iter)) | ||
| 1287 | guard(ComponentRef.isIterator(iter) and not sparsityHasIterator(offset)) algorithm | ||
| 1288 | ✗ | negated := true; | |
| 1289 | then (); | ||
| 1290 | case Expression.MULTARY(operator = Operator.OPERATOR(op = Op.ADD)) algorithm | ||
| 1291 | 2 | (ok, iter, offset, negated) := sparsityMultaryOffset(exp); | |
| 1292 | then (); | ||
| 1293 | else algorithm | ||
| 1294 | ok := false; | ||
| 1295 | then (); | ||
| 1296 | end match; | ||
| 1297 | end sparsityIteratorOffset; | ||
| 1298 | |||
| 1299 | function sparsityHasIterator | ||
| 1300 | input Expression exp; | ||
| 1301 | output Boolean b = UnorderedSet.any(Expression.extractCrefs(exp), ComponentRef.isIterator); | ||
| 1302 | end sparsityHasIterator; | ||
| 1303 | |||
| 1304 | function sparsitySimplify | ||
| 1305 | input output Expression exp; | ||
| 1306 | algorithm | ||
| 1307 | 753 | exp := SimplifyExp.simplify(exp); | |
| 1308 | end sparsitySimplify; | ||
| 1309 | |||
| 1310 | function sparsityHasUnbound | ||
| 1311 | input ComponentRef cref; | ||
| 1312 | input UnorderedMap<ComponentRef, Expression> bindings; | ||
| 1313 | output Boolean b = false; | ||
| 1314 | algorithm | ||
| 1315 | // whole dimension subscripts (:) have no expression to check | ||
| 1316 |
7/8✗ Branch 2 not taken.
✓ Branch 3 taken 267 times.
✓ Branch 4 taken 267 times.
✓ Branch 5 taken 246 times.
✓ Branch 6 taken 267 times.
✓ Branch 7 taken 246 times.
✓ Branch 8 taken 267 times.
✓ Branch 9 taken 246 times.
|
780 | for sub in list(s for s guard(not Subscript.isWhole(s)) in ComponentRef.subscriptsAllFlat(cref)) loop |
| 1317 |
2/2✓ Branch 3 taken 165 times.
✓ Branch 4 taken 267 times.
|
432 | for c in UnorderedSet.toList(Expression.extractCrefs(Subscript.toExp(sub))) loop |
| 1318 |
3/4✓ Branch 1 taken 126 times.
✓ Branch 2 taken 39 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 126 times.
|
165 | if ComponentRef.isIterator(c) and not UnorderedMap.contains(c, bindings) then |
| 1319 | b := true; | ||
| 1320 | ✗ | return; | |
| 1321 | end if; | ||
| 1322 | end for; | ||
| 1323 | end for; | ||
| 1324 | end sparsityHasUnbound; | ||
| 1325 | |||
| 1326 | function sparsityMultaryOffset | ||
| 1327 | "a sum with one iterator, which may be subtracted, and terms without iterators" | ||
| 1328 | input Expression exp; | ||
| 1329 | output Boolean ok = false; | ||
| 1330 | output ComponentRef iter = ComponentRef.EMPTY(); | ||
| 1331 | output Expression offset = Expression.INTEGER(0); | ||
| 1332 | output Boolean negated = false; | ||
| 1333 | protected | ||
| 1334 | list<Expression> its, inv_its, rest, inv_rest; | ||
| 1335 | algorithm | ||
| 1336 | () := match exp | ||
| 1337 | case Expression.MULTARY() algorithm | ||
| 1338 | 2 | (its, rest) := List.splitOnTrue(exp.arguments, sparsityIsIteratorExp); | |
| 1339 | 2 | (inv_its, inv_rest) := List.splitOnTrue(exp.inv_arguments, sparsityIsIteratorExp); | |
| 1340 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if listLength(its) + listLength(inv_its) == 1 then |
| 1341 | 2 | negated := listEmpty(its); | |
| 1342 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
3 | iter := Expression.toCref(listHead(if negated then inv_its else its)); |
| 1343 | 2 | offset := Expression.MULTARY(rest, inv_rest, exp.operator); | |
| 1344 | 2 | ok := not sparsityHasIterator(offset); | |
| 1345 | end if; | ||
| 1346 | then (); | ||
| 1347 | else (); | ||
| 1348 | end match; | ||
| 1349 | end sparsityMultaryOffset; | ||
| 1350 | |||
| 1351 | function sparsityIsIteratorExp | ||
| 1352 | input Expression exp; | ||
| 1353 | output Boolean b = Expression.isCref(exp) and ComponentRef.isIterator(Expression.toCref(exp)); | ||
| 1354 | end sparsityIsIteratorExp; | ||
| 1355 | |||
| 1356 | function sparsityBind | ||
| 1357 | input output Expression exp; | ||
| 1358 | input UnorderedMap<ComponentRef, Expression> bindings; | ||
| 1359 | algorithm | ||
| 1360 | exp := match exp | ||
| 1361 | case Expression.CREF() guard(UnorderedMap.contains(exp.cref, bindings)) | ||
| 1362 | 126 | then UnorderedMap.getSafe(exp.cref, bindings, sourceInfo()); | |
| 1363 | else exp; | ||
| 1364 | end match; | ||
| 1365 | end sparsityBind; | ||
| 1366 | |||
| 1367 | function sparsityInBounds | ||
| 1368 | "false if a literal subscript is outside of its dimension" | ||
| 1369 | input ComponentRef cref; | ||
| 1370 | output Boolean b = true; | ||
| 1371 | algorithm | ||
| 1372 | b := match cref | ||
| 1373 | local | ||
| 1374 | list<Dimension> dims; | ||
| 1375 | case ComponentRef.CREF() algorithm | ||
| 1376 | 497 | dims := Type.arrayDims(cref.ty); | |
| 1377 |
2/2✓ Branch 2 taken 495 times.
✓ Branch 3 taken 2 times.
|
497 | if listLength(dims) == listLength(cref.subscripts) then |
| 1378 |
2/2✓ Branch 1 taken 267 times.
✓ Branch 2 taken 495 times.
|
762 | for tpl in List.zip(cref.subscripts, dims) loop |
| 1379 | () := match tpl | ||
| 1380 | local | ||
| 1381 | Expression e; | ||
| 1382 | Dimension d; | ||
| 1383 | case (Subscript.INDEX(index = e), d) guard(Expression.isInteger(e) and Dimension.isKnown(d)) algorithm | ||
| 1384 |
2/4✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 140 times.
|
140 | if Expression.integerValue(e) < 1 or Expression.integerValue(e) > Dimension.size(d) then |
| 1385 | b := false; | ||
| 1386 | end if; | ||
| 1387 | then (); | ||
| 1388 | else (); | ||
| 1389 | end match; | ||
| 1390 | end for; | ||
| 1391 | end if; | ||
| 1392 |
2/4✓ Branch 0 taken 495 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 497 times.
|
497 | then b and sparsityInBounds(cref.restCref); |
| 1393 | else true; | ||
| 1394 | end match; | ||
| 1395 | end sparsityInBounds; | ||
| 1396 | |||
| 1397 | type SliceAlias = tuple<Expression, Expression, ComponentRef, Expression> "solved start, solved stop, seed, seed start"; | ||
| 1398 | type SliceAliases = list<SliceAlias>; | ||
| 1399 | |||
| 1400 | function sparsityAddSliceAlias | ||
| 1401 | "remembers x[a:b] = y[c:d] (or whole arrays) of an inner equation solved for x, | ||
| 1402 | so that x[e] can be resolved to y[e - a + c] instead of all of y" | ||
| 1403 | input Equation eqn; | ||
| 1404 | input list<ComponentRef> tmp_crefs; | ||
| 1405 | input UnorderedSet<ComponentRef> seed_set; | ||
| 1406 | input UnorderedMap<ComponentRef, SliceAliases> slice_map; | ||
| 1407 | protected | ||
| 1408 | ComponentRef lhs, rhs; | ||
| 1409 | algorithm | ||
| 1410 | () := match eqn | ||
| 1411 | case Equation.ARRAY_EQUATION(lhs = Expression.CREF(cref = lhs), rhs = Expression.CREF(cref = rhs)) algorithm | ||
| 1412 | 7 | sparsityAddSliceAlias2(lhs, rhs, tmp_crefs, seed_set, slice_map); | |
| 1413 | 7 | sparsityAddSliceAlias2(rhs, lhs, tmp_crefs, seed_set, slice_map); | |
| 1414 | then (); | ||
| 1415 | else (); | ||
| 1416 | end match; | ||
| 1417 | end sparsityAddSliceAlias; | ||
| 1418 | |||
| 1419 | function sparsityAddSliceAlias2 | ||
| 1420 | input ComponentRef solved; | ||
| 1421 | input ComponentRef seed; | ||
| 1422 | input list<ComponentRef> tmp_crefs; | ||
| 1423 | input UnorderedSet<ComponentRef> seed_set; | ||
| 1424 | input UnorderedMap<ComponentRef, SliceAliases> slice_map; | ||
| 1425 | protected | ||
| 1426 | ComponentRef solved_base = ComponentRef.stripSubscriptsAll(solved); | ||
| 1427 | ComponentRef seed_base = ComponentRef.stripSubscriptsAll(seed); | ||
| 1428 | Boolean ok1, ok2; | ||
| 1429 | Expression start1, stop1, start2, stop2; | ||
| 1430 | algorithm | ||
| 1431 |
3/4✓ Branch 3 taken 7 times.
✓ Branch 4 taken 7 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
|
14 | if not List.any(tmp_crefs, function sparsitySameBase(base = solved_base)) or not UnorderedSet.contains(seed_base, seed_set) then |
| 1432 | 14 | return; | |
| 1433 | end if; | ||
| 1434 | ✗ | (ok1, start1, stop1) := sparsitySliceBounds(solved); | |
| 1435 | ✗ | (ok2, start2, stop2) := sparsitySliceBounds(seed); | |
| 1436 | // the sides of an array equation have the same size, only literal bounds can be checked | ||
| 1437 | ✗ | if ok1 and ok2 and not (List.all({start1, stop1, start2, stop2}, Expression.isInteger) | |
| 1438 | and Expression.integerValue(stop1) - Expression.integerValue(start1) <> Expression.integerValue(stop2) - Expression.integerValue(start2)) then | ||
| 1439 | ✗ | UnorderedMap.add(solved_base, (start1, stop1, seed_base, start2) :: UnorderedMap.getOrDefault(solved_base, slice_map, {}), slice_map); | |
| 1440 | end if; | ||
| 1441 | end sparsityAddSliceAlias2; | ||
| 1442 | |||
| 1443 | function sparsitySameBase | ||
| 1444 | input ComponentRef cref; | ||
| 1445 | input ComponentRef base; | ||
| 1446 | output Boolean b = ComponentRef.isEqual(ComponentRef.stripSubscriptsAll(cref), base); | ||
| 1447 | end sparsitySameBase; | ||
| 1448 | |||
| 1449 | function sparsitySliceBounds | ||
| 1450 | "bounds of a one-dimensional variable or a unit step slice of it" | ||
| 1451 | input ComponentRef cref; | ||
| 1452 | output Boolean ok = false; | ||
| 1453 | output Expression start = Expression.INTEGER(1); | ||
| 1454 | output Expression stop = Expression.INTEGER(0); | ||
| 1455 | protected | ||
| 1456 | Type ty = ComponentRef.getSubscriptedType(ComponentRef.stripSubscriptsAll(cref)); | ||
| 1457 | list<Subscript> subs = ComponentRef.subscriptsAllFlat(cref); | ||
| 1458 | Integer istart, istep, istop; | ||
| 1459 | Expression size; | ||
| 1460 | algorithm | ||
| 1461 | ✗ | if Type.dimensionCount(ty) <> 1 or listLength(subs) <> listLength(ComponentRef.getSubscripts(cref)) then | |
| 1462 | ✗ | return; | |
| 1463 | end if; | ||
| 1464 | ✗ | if Type.hasKnownSize(ty) then | |
| 1465 | ✗ | size := Expression.INTEGER(Type.sizeOf(ty)); | |
| 1466 | else | ||
| 1467 | size := match Type.arrayDims(ty) | ||
| 1468 | local | ||
| 1469 | Dimension dim; | ||
| 1470 | ✗ | case {dim as Dimension.RESIZABLE()} then Dimension.sizeExp(dim); | |
| 1471 | ✗ | case {dim as Dimension.EXP()} then Dimension.sizeExp(dim); | |
| 1472 | else Expression.EMPTY(Type.INTEGER()); | ||
| 1473 | end match; | ||
| 1474 | end if; | ||
| 1475 | (ok, start, stop) := match subs | ||
| 1476 | local | ||
| 1477 | Expression range; | ||
| 1478 | list<Subscript> indices; | ||
| 1479 | ✗ | case {} then (not Expression.isEmpty(size), Expression.INTEGER(1), size); | |
| 1480 | ✗ | case {Subscript.WHOLE()} then (not Expression.isEmpty(size), Expression.INTEGER(1), size); | |
| 1481 | case {Subscript.SLICE(slice = range as Expression.RANGE())} guard(Expression.isLiteral(range)) algorithm | ||
| 1482 | ✗ | (istart, istep, istop) := Expression.getIntegerRange(range, false); | |
| 1483 | ✗ | then (istep == 1, Expression.INTEGER(istart), Expression.INTEGER(istop)); | |
| 1484 | case {Subscript.SLICE(slice = range as Expression.RANGE())} | ||
| 1485 | guard(Util.applyOptionOrDefault(range.step, function Expression.isEqual(exp2 = Expression.INTEGER(1)), true)) | ||
| 1486 | ✗ | then (true, range.start, range.stop); | |
| 1487 | case {Subscript.SLICE(slice = range as Expression.ARRAY())} | ||
| 1488 | ✗ | then sparsityConsecutive(Expression.arrayElementList(range)); | |
| 1489 | case {Subscript.EXPANDED_SLICE(indices = indices)} | ||
| 1490 | ✗ | then sparsityConsecutive(list(Subscript.toExp(sub) for sub in indices)); | |
| 1491 | ✗ | else (false, start, stop); | |
| 1492 | end match; | ||
| 1493 | end sparsitySliceBounds; | ||
| 1494 | |||
| 1495 | function sparsityConsecutive | ||
| 1496 | input list<Expression> indices; | ||
| 1497 | output Boolean ok; | ||
| 1498 | output Expression start_exp; | ||
| 1499 | output Expression stop_exp; | ||
| 1500 | protected | ||
| 1501 | Integer start = 0, stop = 0; | ||
| 1502 | algorithm | ||
| 1503 | ✗ | (ok, start, stop) := sparsityConsecutive2(indices); | |
| 1504 | ✗ | start_exp := Expression.INTEGER(start); | |
| 1505 | ✗ | stop_exp := Expression.INTEGER(stop); | |
| 1506 | end sparsityConsecutive; | ||
| 1507 | |||
| 1508 | function sparsityConsecutive2 | ||
| 1509 | input list<Expression> indices; | ||
| 1510 | output Boolean ok = true; | ||
| 1511 | output Integer start = 0; | ||
| 1512 | output Integer stop = 0; | ||
| 1513 | algorithm | ||
| 1514 | ✗ | for index in indices loop | |
| 1515 | ✗ | if not Expression.isInteger(index) then | |
| 1516 | ok := false; | ||
| 1517 | ✗ | return; | |
| 1518 | end if; | ||
| 1519 | ✗ | if stop == 0 then | |
| 1520 | ✗ | start := Expression.integerValue(index); | |
| 1521 | elseif Expression.integerValue(index) <> stop + 1 then | ||
| 1522 | ok := false; | ||
| 1523 | ✗ | return; | |
| 1524 | end if; | ||
| 1525 | ✗ | stop := Expression.integerValue(index); | |
| 1526 | end for; | ||
| 1527 | ✗ | ok := stop > 0; | |
| 1528 | end sparsityConsecutive2; | ||
| 1529 | |||
| 1530 | function sparsitySliceAliasDeps | ||
| 1531 | "x[e] with a slice alias x[a:b] = y[c:d] -> y[e - a + c]" | ||
| 1532 | input ComponentRef cref; | ||
| 1533 | input UnorderedMap<ComponentRef, SliceAliases> slice_map; | ||
| 1534 | output list<ComponentRef> deps = {}; | ||
| 1535 | protected | ||
| 1536 | list<SliceAlias> aliases; | ||
| 1537 | Expression start1, stop1, start2, index; | ||
| 1538 | ComponentRef seed; | ||
| 1539 | algorithm | ||
| 1540 | 235 | aliases := UnorderedMap.getOrDefault(ComponentRef.stripSubscriptsAll(cref), slice_map, {}); | |
| 1541 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
235 | if listEmpty(aliases) or listLength(ComponentRef.subscriptsAllFlat(cref)) <> listLength(ComponentRef.getSubscripts(cref)) then |
| 1542 | 235 | return; | |
| 1543 | end if; | ||
| 1544 | _ := match ComponentRef.getSubscripts(cref) | ||
| 1545 | case {Subscript.INDEX(index = index)} algorithm | ||
| 1546 | ✗ | for alias in aliases loop | |
| 1547 | ✗ | (start1, stop1, seed, start2) := alias; | |
| 1548 | ✗ | if not (Expression.isInteger(index) and ( | |
| 1549 | Expression.isInteger(start1) and Expression.integerValue(index) < Expression.integerValue(start1) or | ||
| 1550 | Expression.isInteger(stop1) and Expression.integerValue(index) > Expression.integerValue(stop1))) then | ||
| 1551 | ✗ | deps := ComponentRef.setSubscripts({Subscript.INDEX(SimplifyExp.simplify(Expression.BINARY( | |
| 1552 | Expression.BINARY(index, Operator.makeAdd(Type.INTEGER()), start2), | ||
| 1553 | Operator.makeSub(Type.INTEGER()), start1)))}, seed) :: deps; | ||
| 1554 | end if; | ||
| 1555 | end for; | ||
| 1556 | then (); | ||
| 1557 | else (); | ||
| 1558 | end match; | ||
| 1559 | end sparsitySliceAliasDeps; | ||
| 1560 | |||
| 1561 | function sparsityExpandForeignIterators | ||
| 1562 | "a dependency with iterators of another (inner) equation depends on all its seed elements" | ||
| 1563 | input ComponentRef cref; | ||
| 1564 | input UnorderedSet<ComponentRef> own_iters; | ||
| 1565 | input UnorderedMap<ComponentRef, list<ComponentRef>> seed_elements "base name -> element seeds"; | ||
| 1566 | output list<ComponentRef> crefs = {cref}; | ||
| 1567 | protected | ||
| 1568 | ComponentRef base; | ||
| 1569 | Type ty; | ||
| 1570 | algorithm | ||
| 1571 |
2/2✓ Branch 4 taken 2893 times.
✓ Branch 5 taken 16 times.
|
2909 | if not List.all(ComponentRef.subscriptsAllFlat(cref), function sparsityIsOwnSubscript(own_iters = own_iters)) then |
| 1572 | 16 | base := ComponentRef.stripSubscriptsAll(cref); | |
| 1573 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | if UnorderedMap.contains(base, seed_elements) then |
| 1574 | ✗ | crefs := UnorderedMap.getSafe(base, seed_elements, sourceInfo()); | |
| 1575 | else | ||
| 1576 | 16 | ty := ComponentRef.getSubscriptedType(base); | |
| 1577 |
3/4✓ Branch 1 taken 11 times.
✓ Branch 2 taken 5 times.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
|
16 | crefs := if Type.isArray(ty) and Type.sizeOf(ty) <= 1024 then ComponentRef.scalarizeAll(base, false) else {base}; |
| 1578 | end if; | ||
| 1579 | end if; | ||
| 1580 | end sparsityExpandForeignIterators; | ||
| 1581 | |||
| 1582 | function sparsityIsOwnSubscript | ||
| 1583 | input Subscript sub; | ||
| 1584 | input UnorderedSet<ComponentRef> own_iters; | ||
| 1585 | output Boolean b = Subscript.isLiteral(sub) or Subscript.isWhole(sub) or Subscript.isSliced(sub) | ||
| 1586 | or UnorderedSet.all(Expression.extractCrefs(Subscript.toExp(sub)), function sparsityIsOwnCref(own_iters = own_iters)); | ||
| 1587 | end sparsityIsOwnSubscript; | ||
| 1588 | |||
| 1589 | function sparsityIsOwnCref | ||
| 1590 | "an iterator of this equation or a parameter (x[N])" | ||
| 1591 | input ComponentRef cref; | ||
| 1592 | input UnorderedSet<ComponentRef> own_iters; | ||
| 1593 | output Boolean b = UnorderedSet.contains(cref, own_iters) or not ComponentRef.isIterator(cref); | ||
| 1594 | end sparsityIsOwnCref; | ||
| 1595 | |||
| 1596 | function sparsityAddInner | ||
| 1597 | "sliced inner variables are also added by their name, later equations might use other slices of them. | ||
| 1598 | entries are merged, several components can solve parts of the same variable" | ||
| 1599 | input ComponentRef cref; | ||
| 1600 | input list<ComponentRef> deps; | ||
| 1601 | input UnorderedMap<ComponentRef, list<ComponentRef>> inner_map; | ||
| 1602 | protected | ||
| 1603 | ComponentRef stripped = ComponentRef.stripSubscriptsAll(cref); | ||
| 1604 | algorithm | ||
| 1605 | // several components can solve slices of the same variable with the same cref (e.g. x[$i1]) | ||
| 1606 | 1758 | UnorderedMap.add(cref, UnorderedSet.unique_list(listAppend(deps, UnorderedMap.getOrDefault(cref, inner_map, {})), ComponentRef.hash, ComponentRef.isEqual), inner_map); | |
| 1607 |
2/2✓ Branch 1 taken 1272 times.
✓ Branch 2 taken 486 times.
|
1758 | if not ComponentRef.isEqual(stripped, cref) then |
| 1608 | 486 | UnorderedMap.add(stripped, UnorderedSet.unique_list(listAppend(deps, UnorderedMap.getOrDefault(stripped, inner_map, {})), ComponentRef.hash, ComponentRef.isEqual), inner_map); | |
| 1609 | end if; | ||
| 1610 | end sparsityAddInner; | ||
| 1611 | |||
| 1612 | function upgrade | ||
| 1613 | "upgrades a matrix using the information provided by the full matrix" | ||
| 1614 | input output Matrix adj; | ||
| 1615 | input Matrix full; | ||
| 1616 | input UnorderedMap<ComponentRef, Integer> vars_map; | ||
| 1617 | input UnorderedMap<ComponentRef, Integer> eqns_map; | ||
| 1618 | input EquationPointers eqns; | ||
| 1619 | input MatrixStrictness st; | ||
| 1620 | input Iterator iter = Iterator.EMPTY(); | ||
| 1621 | algorithm | ||
| 1622 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3399 times.
|
3399 | if Flags.isSet(Flags.BLT_MATRIX_DUMP) then |
| 1623 | ✗ | print(StringUtil.headline_1("Upgrading from [" + strictnessString(getStrictness(adj)) + "] to [" + strictnessString(st) +"]") + "\n"); | |
| 1624 | end if; | ||
| 1625 | |||
| 1626 | adj := match full | ||
| 1627 | local | ||
| 1628 | Integer min, max; | ||
| 1629 | IntMatrix.Builder builder; | ||
| 1630 | list<Integer> indices; | ||
| 1631 | |||
| 1632 | ✗ | case EMPTY() then EMPTY(st); | |
| 1633 | |||
| 1634 | case FULL() algorithm | ||
| 1635 | // empty matrices can have a strictness if we want to expand them, in this case ignore and overwrite | ||
| 1636 | // min is the rank the matrix already contains, -1 for an empty one | ||
| 1637 |
2/2✓ Branch 1 taken 1783 times.
✓ Branch 2 taken 1616 times.
|
3399 | if isEmpty(adj) then |
| 1638 | min := -1; | ||
| 1639 | 1783 | adj := initialize(full.mapping, st); | |
| 1640 | else | ||
| 1641 | 1616 | min := Solvability.rank(Solvability.fromStrictness(getStrictness(adj))); | |
| 1642 | end if; | ||
| 1643 | 3399 | max := Solvability.rank(Solvability.fromStrictness(st)); | |
| 1644 | |||
| 1645 | adj := match adj | ||
| 1646 | local | ||
| 1647 | Matrix result; | ||
| 1648 | list<ComponentRef> filtered; | ||
| 1649 | array<UnorderedSet<ComponentRef>> occ; | ||
| 1650 | array<UnorderedMap<ComponentRef, Dependency>> dep; | ||
| 1651 | array<UnorderedMap<ComponentRef, Solvability>> sol; | ||
| 1652 | array<UnorderedSet<ComponentRef>> rep; | ||
| 1653 | |||
| 1654 | // default case | ||
| 1655 | case FINAL() algorithm | ||
| 1656 | // only do if valid upgrade otherwise create from scratch and issue warning if failtrace is activated | ||
| 1657 |
1/2✓ Branch 0 taken 3397 times.
✗ Branch 1 not taken.
|
3397 | if max == min then |
| 1658 | result := adj; | ||
| 1659 | elseif max > min then | ||
| 1660 | 3397 | (occ, dep, sol, rep) := (full.occurrences, full.dependencies, full.solvabilities, full.repetitions); | |
| 1661 | 3397 | indices := UnorderedMap.valueList(eqns_map); | |
| 1662 | 3397 | builder := IntMatrix.toBuilder(adj.m, estimateEntries(occ, adj.mapping, indices), true); | |
| 1663 |
2/2✓ Branch 0 taken 18480 times.
✓ Branch 1 taken 3397 times.
|
21877 | for index in indices loop |
| 1664 | 18480 | filtered := Solvability.filter(UnorderedSet.toList(occ[index]), sol[index], vars_map, min + 1, max); | |
| 1665 | // upgrade the row and all meta data | ||
| 1666 | 18480 | upgradeRow(EquationPointers.getEqnAt(eqns, index), index, filtered, dep[index], rep[index], vars_map, vars_map, builder, adj.mapping, adj.modes, iter); | |
| 1667 | end for; | ||
| 1668 | 3397 | adj.m := IntMatrix.fromBuilder(builder, IntMatrix.rows(adj.m)); | |
| 1669 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3397 times.
|
6794 | adj.mT := IntMatrix.transpose(adj.m, arrayLength(adj.mapping.var_StA)); |
| 1670 | result := adj; | ||
| 1671 | else | ||
| 1672 | ✗ | if Flags.isSet(Flags.FAILTRACE) then | |
| 1673 | ✗ | Error.addCompilerWarning("Invalid matrix upgrade request. Cannot upgrade matrix of type " | |
| 1674 | + Solvability.toString(Solvability.fromStrictness(getStrictness(adj))) + " to type " | ||
| 1675 | + Solvability.toString(Solvability.fromStrictness(st)) + ". The new matrix will be | ||
| 1676 | created from using only the full adjacency matrix."); | ||
| 1677 | end if; | ||
| 1678 | ✗ | result := fullToFinal(full, vars_map, eqns_map, eqns, st, iter); | |
| 1679 | end if; | ||
| 1680 | then result; | ||
| 1681 | |||
| 1682 | // if its still empty even after initializing it, there are no variables or equations | ||
| 1683 | case EMPTY() then adj; | ||
| 1684 | |||
| 1685 | // cannot upgrade a full matrix | ||
| 1686 | case FULL() algorithm | ||
| 1687 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong matrix type for the 1st input. | |
| 1688 | Expected: final or empty, Got :" + strictnessString(getStrictness(adj)) + "."}); | ||
| 1689 | ✗ | then fail(); | |
| 1690 | end match; | ||
| 1691 | then adj; | ||
| 1692 | |||
| 1693 | else algorithm | ||
| 1694 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong matrix type for the 2nd input. | |
| 1695 | Expected: full, Got :" + strictnessString(getStrictness(full)) + "."}); | ||
| 1696 | ✗ | then fail(); | |
| 1697 | end match; | ||
| 1698 | |||
| 1699 |
1/2✓ Branch 1 taken 3399 times.
✗ Branch 2 not taken.
|
3399 | if Flags.isSet(Flags.BLT_MATRIX_DUMP) then |
| 1700 | ✗ | print(toString(adj, "Final") + "\n"); | |
| 1701 | end if; | ||
| 1702 | end upgrade; | ||
| 1703 | |||
| 1704 | function equalRows | ||
| 1705 | "equation index -> index of the equal equation in seed_eqns, 0 if none. | ||
| 1706 | Its rows in a final matrix over (seed_eqns, seed_vars) are its rows in one | ||
| 1707 | over (eqns, vars), so nothing is shared unless the variables are the same | ||
| 1708 | in the same order." | ||
| 1709 | input EquationPointers seed_eqns; | ||
| 1710 | input VariablePointers seed_vars; | ||
| 1711 | input EquationPointers eqns; | ||
| 1712 | input VariablePointers vars; | ||
| 1713 | output array<Integer> seed_index = arrayCreate(EquationPointers.lastUsedIndex(eqns), 0); | ||
| 1714 | protected | ||
| 1715 | Integer n = VariablePointers.size(vars), i; | ||
| 1716 | Pointer<Equation> seed_eqn; | ||
| 1717 | algorithm | ||
| 1718 |
3/6✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
|
6 | if n <> VariablePointers.size(seed_vars) or n <> VariablePointers.lastUsedIndex(vars) or n <> VariablePointers.lastUsedIndex(seed_vars) then return; end if; |
| 1719 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
428 | for j in 1:n loop |
| 1720 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 422 times.
|
422 | if not referenceEq(VariablePointers.getVarAt(vars, j), VariablePointers.getVarAt(seed_vars, j)) then return; end if; |
| 1721 | end for; | ||
| 1722 |
2/2✓ Branch 1 taken 541 times.
✓ Branch 2 taken 6 times.
|
547 | for eqn in EquationPointers.toList(eqns) loop |
| 1723 | 541 | i := EquationPointers.getEqnIndex(seed_eqns, Equation.getEqnName(eqn)); | |
| 1724 |
2/2✓ Branch 0 taken 539 times.
✓ Branch 1 taken 2 times.
|
541 | if i > 0 then |
| 1725 | 539 | seed_eqn := EquationPointers.getEqnAt(seed_eqns, i); | |
| 1726 |
2/2✓ Branch 3 taken 526 times.
✓ Branch 4 taken 13 times.
|
539 | if Equation.isEqual(Pointer.access(eqn), Pointer.access(seed_eqn)) then |
| 1727 | 526 | seed_index[EquationPointers.getEqnIndex(eqns, Equation.getEqnName(eqn))] := i; | |
| 1728 | end if; | ||
| 1729 | end if; | ||
| 1730 | end for; | ||
| 1731 | end equalRows; | ||
| 1732 | |||
| 1733 | function upgradeFrom | ||
| 1734 | "upgrade, taking the rows of equations with a seed_index (see equalRows) | ||
| 1735 | from seed, a final matrix of strictness st that shares its variables" | ||
| 1736 | input output Matrix adj; | ||
| 1737 | input Matrix full; | ||
| 1738 | input UnorderedMap<ComponentRef, Integer> vars_map; | ||
| 1739 | input UnorderedMap<ComponentRef, Integer> eqns_map; | ||
| 1740 | input EquationPointers eqns; | ||
| 1741 | input MatrixStrictness st; | ||
| 1742 | input Matrix seed; | ||
| 1743 | input array<Integer> seed_index; | ||
| 1744 | protected | ||
| 1745 | Integer min, max, rows, eqn_start, eqn_size, seed_start, own_entries = 0, shared_entries = 0; | ||
| 1746 | Boolean fresh = isEmpty(adj); | ||
| 1747 | IntMatrix m, own_m; | ||
| 1748 | IntMatrix.Builder builder; | ||
| 1749 | list<Integer> own = {}; | ||
| 1750 | list<ComponentRef> filtered; | ||
| 1751 | array<Integer> data, aux, seed_data, seed_aux; | ||
| 1752 | algorithm | ||
| 1753 | 12 | max := Solvability.rank(Solvability.fromStrictness(st)); | |
| 1754 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | min := if fresh then -1 else Solvability.rank(Solvability.fromStrictness(getStrictness(adj))); |
| 1755 | adj := match (adj, full, seed) | ||
| 1756 | case (_, FULL(), FINAL()) guard(min < max) algorithm | ||
| 1757 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if fresh then |
| 1758 | 6 | adj := initialize(full.mapping, st); | |
| 1759 | end if; | ||
| 1760 | adj := match adj | ||
| 1761 | case FINAL() algorithm | ||
| 1762 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if fresh then |
| 1763 | 6 | adj.modes := Vector.copy(seed.modes); | |
| 1764 | end if; | ||
| 1765 | 12 | rows := IntMatrix.rows(adj.m); | |
| 1766 |
2/2✓ Branch 1 taken 1082 times.
✓ Branch 2 taken 12 times.
|
1094 | for index in UnorderedMap.valueList(eqns_map) loop |
| 1767 | 1082 | (eqn_start, eqn_size) := adj.mapping.eqn_AtS[index]; | |
| 1768 |
2/2✓ Branch 1 taken 1052 times.
✓ Branch 2 taken 30 times.
|
1082 | if seed_index[index] > 0 then |
| 1769 | 1052 | (seed_start, _) := seed.mapping.eqn_AtS[seed_index[index]]; | |
| 1770 |
2/2✓ Branch 0 taken 970 times.
✓ Branch 1 taken 82 times.
|
1052 | for k in 0:eqn_size - 1 loop |
| 1771 | 1274 | shared_entries := shared_entries + seed.m.len[seed_start + k]; | |
| 1772 | end for; | ||
| 1773 | else | ||
| 1774 | own := index :: own; | ||
| 1775 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | for k in 0:eqn_size - 1 loop |
| 1776 | 30 | own_entries := own_entries + adj.m.len[eqn_start + k]; | |
| 1777 | end for; | ||
| 1778 | 30 | own_entries := own_entries + UnorderedSet.size(full.occurrences[index]) * eqn_size; | |
| 1779 | end if; | ||
| 1780 | end for; | ||
| 1781 | 12 | own := listReverse(own); | |
| 1782 | |||
| 1783 | // the own rows are built the way upgrade builds all rows | ||
| 1784 | 12 | builder := IntMatrix.newBuilder(own_entries, true); | |
| 1785 | 12 | data := IntMatrix.entries(adj.m); | |
| 1786 | 12 | aux := IntMatrix.payload(adj.m); | |
| 1787 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
|
42 | for index in own loop |
| 1788 | 30 | (eqn_start, eqn_size) := adj.mapping.eqn_AtS[index]; | |
| 1789 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
60 | for k in eqn_size - 1:-1:0 loop |
| 1790 |
2/2✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
|
63 | for p in adj.m.start[eqn_start + k] + adj.m.len[eqn_start + k] - 1:-1:adj.m.start[eqn_start + k] loop |
| 1791 |
1/2✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
|
33 | IntMatrix.builderAddAux(builder, eqn_start + k, data[p], if arrayLength(aux) > 0 then aux[p] else 0); |
| 1792 | end for; | ||
| 1793 | end for; | ||
| 1794 | end for; | ||
| 1795 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 12 times.
|
42 | for index in own loop |
| 1796 | 30 | filtered := Solvability.filter(UnorderedSet.toList(full.occurrences[index]), full.solvabilities[index], vars_map, min + 1, max); | |
| 1797 | 30 | upgradeRow(EquationPointers.getEqnAt(eqns, index), index, filtered, full.dependencies[index], full.repetitions[index], vars_map, vars_map, builder, adj.mapping, adj.modes); | |
| 1798 | end for; | ||
| 1799 | 12 | own_m := IntMatrix.fromBuilder(builder, rows); | |
| 1800 | |||
| 1801 | 12 | m := IntMatrix.new(rows); | |
| 1802 | 12 | IntMatrix.reserveData(m, shared_entries + IntMatrix.nonZeroCount(own_m), true); | |
| 1803 | 12 | data := IntMatrix.entries(own_m); | |
| 1804 | 12 | aux := IntMatrix.payload(own_m); | |
| 1805 | 12 | seed_data := IntMatrix.entries(seed.m); | |
| 1806 | 12 | seed_aux := IntMatrix.payload(seed.m); | |
| 1807 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if arrayLength(seed_aux) == 0 then |
| 1808 | ✗ | seed_aux := arrayCreate(arrayLength(seed_data), 0); | |
| 1809 | end if; | ||
| 1810 |
2/2✓ Branch 1 taken 1082 times.
✓ Branch 2 taken 12 times.
|
1094 | for index in UnorderedMap.valueList(eqns_map) loop |
| 1811 | 1082 | (eqn_start, eqn_size) := adj.mapping.eqn_AtS[index]; | |
| 1812 |
2/2✓ Branch 1 taken 1052 times.
✓ Branch 2 taken 30 times.
|
1082 | if seed_index[index] > 0 then |
| 1813 | 1052 | (seed_start, _) := seed.mapping.eqn_AtS[seed_index[index]]; | |
| 1814 |
2/2✓ Branch 0 taken 970 times.
✓ Branch 1 taken 82 times.
|
2326 | for k in 0:eqn_size - 1 loop |
| 1815 | 1274 | IntMatrix.copyRow(seed.m, seed_start + k, seed_data, seed_aux, m, eqn_start + k); | |
| 1816 | end for; | ||
| 1817 | else | ||
| 1818 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
60 | for k in 0:eqn_size - 1 loop |
| 1819 | 30 | IntMatrix.copyRow(own_m, eqn_start + k, data, aux, m, eqn_start + k); | |
| 1820 | end for; | ||
| 1821 | end if; | ||
| 1822 | end for; | ||
| 1823 | 12 | adj.m := m; | |
| 1824 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
24 | adj.mT := IntMatrix.transpose(m, arrayLength(adj.mapping.var_StA)); |
| 1825 | then adj; | ||
| 1826 | else adj; | ||
| 1827 | end match; | ||
| 1828 | then adj; | ||
| 1829 | ✗ | else upgrade(adj, full, vars_map, eqns_map, eqns, st); | |
| 1830 | end match; | ||
| 1831 | end upgradeFrom; | ||
| 1832 | |||
| 1833 | function expand | ||
| 1834 | "expands the adjacency matrix adj with new information provided by vn and en. | ||
| 1835 | If necessary it also expands the full matrix." | ||
| 1836 | input output Matrix adj "adjancency matrix to be expanded"; | ||
| 1837 | input output Matrix full "full matrix having all information"; | ||
| 1838 | input UnorderedMap<ComponentRef, Integer> vo, vn "old and new variable index map"; | ||
| 1839 | input UnorderedMap<ComponentRef, Integer> eo, en "old and new equation index map"; | ||
| 1840 | input VariablePointers vars "all variables, containing new and old"; | ||
| 1841 | input EquationPointers eqns "all equations, containing new and old"; | ||
| 1842 | input Partition.Kind kind; | ||
| 1843 | protected | ||
| 1844 | Integer size_vo, size_vn, size_eo, size_en; //only for debugging | ||
| 1845 | algorithm | ||
| 1846 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 479 times.
|
479 | if Flags.isSet(Flags.BLT_MATRIX_DUMP) then |
| 1847 | ✗ | size_vo := sum(ComponentRef.size(var, true) for var in UnorderedMap.keyList(vo)); | |
| 1848 | ✗ | size_vn := sum(ComponentRef.size(var, true) for var in UnorderedMap.keyList(vn)) + size_vo; | |
| 1849 | ✗ | size_eo := sum(ComponentRef.size(eqn, true) for eqn in UnorderedMap.keyList(eo)); | |
| 1850 | ✗ | size_en := sum(ComponentRef.size(eqn, true) for eqn in UnorderedMap.keyList(en)) + size_eo; | |
| 1851 | ✗ | print(StringUtil.headline_1("Expanding from size [vars: " + intString(size_vo) + "| eqns: " + intString(size_eo) + "] to [vars: " + intString(size_vn) + "| eqns: " + intString(size_en) + "]") + "\n"); | |
| 1852 | end if; | ||
| 1853 | |||
| 1854 | // check if full has to be expanded | ||
| 1855 | full := match full | ||
| 1856 | case FULL() guard(EquationPointers.size(eqns) > arrayLength(full.equation_names)) | ||
| 1857 | 28 | then expandFull(full, vo, vn, eo, en, vars, eqns, kind); | |
| 1858 | else full; | ||
| 1859 | end match; | ||
| 1860 | |||
| 1861 | adj := match (adj, full) | ||
| 1862 | local | ||
| 1863 | Matrix new; | ||
| 1864 | Integer rank, max_index_eq, max_index_var, eqn_scalar_size; | ||
| 1865 | list<ComponentRef> filtered; | ||
| 1866 | list<Integer> eo_lst, en_lst; | ||
| 1867 | IntMatrix.Builder builder; | ||
| 1868 | UnorderedMap<ComponentRef, Integer> v = vo; | ||
| 1869 | |||
| 1870 | // if the matrix is empty, initialize it first | ||
| 1871 | case (EMPTY(), FULL()) algorithm | ||
| 1872 | 43 | new := initialize(full.mapping, adj.st); | |
| 1873 |
2/2✓ Branch 1 taken 41 times.
✓ Branch 2 taken 2 times.
|
43 | if not isEmpty(new) then |
| 1874 | 41 | new := expand(new, full, vo, vn, eo, en, vars, eqns, kind); | |
| 1875 | end if; | ||
| 1876 | then new; | ||
| 1877 | |||
| 1878 | // default case | ||
| 1879 | case (FINAL(), FULL()) algorithm | ||
| 1880 | // 0. expand the integer matrix | ||
| 1881 | 436 | eqn_scalar_size := EquationPointers.scalarSize(eqns, true); | |
| 1882 | 436 | adj.mapping := full.mapping; | |
| 1883 | 436 | eo_lst := UnorderedMap.valueList(eo); | |
| 1884 | 436 | en_lst := UnorderedMap.valueList(en); | |
| 1885 | 436 | builder := IntMatrix.toBuilder(adj.m, | |
| 1886 | estimateEntries(full.occurrences, adj.mapping, eo_lst) + estimateEntries(full.occurrences, adj.mapping, en_lst), true); | ||
| 1887 | |||
| 1888 | |||
| 1889 | // get the strictness ranking | ||
| 1890 | 436 | rank := Solvability.rank(Solvability.fromStrictness(getStrictness(adj))); | |
| 1891 | // only merge if there is a second phase | ||
| 1892 |
3/4✓ Branch 1 taken 112 times.
✓ Branch 2 taken 324 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 112 times.
|
436 | if not UnorderedMap.isEmpty(vn) and not UnorderedMap.isEmpty(en) then |
| 1893 | ✗ | v := UnorderedMap.merge(v, vn, sourceInfo()); | |
| 1894 | end if; | ||
| 1895 | |||
| 1896 | // I. update all old equations with the new variables | ||
| 1897 |
2/2✓ Branch 1 taken 112 times.
✓ Branch 2 taken 324 times.
|
436 | if not UnorderedMap.isEmpty(vn) then |
| 1898 |
2/2✓ Branch 0 taken 2291 times.
✓ Branch 1 taken 112 times.
|
2403 | for e in eo_lst loop |
| 1899 | 2291 | filtered := Solvability.filter(UnorderedSet.toList(full.occurrences[e]), full.solvabilities[e], vn, 0, rank); | |
| 1900 | 2291 | upgradeRow(EquationPointers.getEqnAt(eqns, e), e, filtered, full.dependencies[e], full.repetitions[e], vn, vars.map, builder, adj.mapping, adj.modes); | |
| 1901 | end for; | ||
| 1902 | end if; | ||
| 1903 | |||
| 1904 | // II. update new equations with all variables | ||
| 1905 |
2/2✓ Branch 1 taken 202 times.
✓ Branch 2 taken 234 times.
|
436 | if not UnorderedMap.isEmpty(en) then |
| 1906 |
2/2✓ Branch 0 taken 3387 times.
✓ Branch 1 taken 202 times.
|
3589 | for e in en_lst loop |
| 1907 | 3387 | filtered := Solvability.filter(UnorderedSet.toList(full.occurrences[e]), full.solvabilities[e], v, 0, rank); | |
| 1908 | 3387 | upgradeRow(EquationPointers.getEqnAt(eqns, e), e, filtered, full.dependencies[e], full.repetitions[e], v, vars.map, builder, adj.mapping, adj.modes); | |
| 1909 | end for; | ||
| 1910 | end if; | ||
| 1911 | |||
| 1912 | // transpose the matrix | ||
| 1913 |
3/4✓ Branch 1 taken 41 times.
✓ Branch 2 taken 395 times.
✓ Branch 4 taken 41 times.
✗ Branch 5 not taken.
|
436 | if UnorderedMap.isEmpty(vo) and UnorderedMap.isEmpty(vn) then |
| 1914 | max_index_var := 0; | ||
| 1915 | else | ||
| 1916 |
8/8✓ Branch 1 taken 6072 times.
✓ Branch 2 taken 436 times.
✓ Branch 3 taken 6072 times.
✓ Branch 4 taken 436 times.
✓ Branch 6 taken 490 times.
✓ Branch 7 taken 436 times.
✓ Branch 8 taken 490 times.
✓ Branch 9 taken 436 times.
|
6998 | max_index_var := intMax(max(i for i in UnorderedMap.valueList(vo)), max(i for i in UnorderedMap.valueList(vn))); |
| 1917 | end if; | ||
| 1918 | 436 | adj.m := IntMatrix.fromBuilder(builder, eqn_scalar_size); | |
| 1919 | 436 | adj.mT := IntMatrix.transpose(adj.m, VariablePointers.scalarSize(vars, true)); | |
| 1920 | then adj; | ||
| 1921 | |||
| 1922 | // fail cases | ||
| 1923 | case (FINAL(), _) algorithm | ||
| 1924 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the full matrix expected to contain all information is instead of type " | |
| 1925 | + strictnessString(getStrictness(full)) + "."}); | ||
| 1926 | ✗ | then fail(); | |
| 1927 | |||
| 1928 | case (_, FULL()) algorithm | ||
| 1929 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the matrix to be expanded of type " | |
| 1930 | + strictnessString(getStrictness(adj)) + " should be of type final."}); | ||
| 1931 | ✗ | then fail(); | |
| 1932 | |||
| 1933 | else algorithm | ||
| 1934 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected types final and full, got types " + strictnessString(getStrictness(adj)) | |
| 1935 | + " and " + strictnessString(getStrictness(full)) + "."}); | ||
| 1936 | ✗ | then fail(); | |
| 1937 | end match; | ||
| 1938 | |||
| 1939 |
1/2✓ Branch 1 taken 479 times.
✗ Branch 2 not taken.
|
479 | if Flags.isSet(Flags.BLT_MATRIX_DUMP) then |
| 1940 | ✗ | print(toString(adj, "Expanded Final") + "\n"); | |
| 1941 | end if; | ||
| 1942 | end expand; | ||
| 1943 | |||
| 1944 | function expandFull | ||
| 1945 | "usually only called from expand()" | ||
| 1946 | input output Matrix full "full matrix having all information"; | ||
| 1947 | input UnorderedMap<ComponentRef, Integer> vo, vn "old and new variable index map"; | ||
| 1948 | input UnorderedMap<ComponentRef, Integer> eo, en "old and new equation index map"; | ||
| 1949 | input VariablePointers vars "all variables, containing new and old"; | ||
| 1950 | input EquationPointers eqns "all equations, containing new and old"; | ||
| 1951 | input Partition.Kind kind; | ||
| 1952 | algorithm | ||
| 1953 | full := match full | ||
| 1954 | local | ||
| 1955 | list<Pointer<Variable>> new_vars = list(VariablePointers.getVarAt(vars, idx) for idx in UnorderedMap.valueList(vn)); | ||
| 1956 | list<Pointer<Equation>> new_eqns = list(EquationPointers.getEqnAt(eqns, idx) for idx in UnorderedMap.valueList(en)); | ||
| 1957 | Integer index, size = EquationPointers.size(eqns); | ||
| 1958 | Pointer<Equation> eqn_ptr; | ||
| 1959 | UnorderedSet<ComponentRef> occ_set; | ||
| 1960 | case FULL() algorithm | ||
| 1961 | // 0. enlargen the arrays | ||
| 1962 | 28 | full := FULL(Array.expandToSize(size, full.equation_names, ComponentRef.EMPTY()), | |
| 1963 | Array.expandToSize(size, full.occurrences, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)), | ||
| 1964 | Array.expandToSize(size, full.dependencies, UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual)), | ||
| 1965 | Array.expandToSize(size, full.solvabilities, UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual)), | ||
| 1966 | Array.expandToSize(size, full.repetitions, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)), | ||
| 1967 | Mapping.expand(full.mapping, new_eqns, new_vars)); | ||
| 1968 | |||
| 1969 | // I. update all old equations with the new variables | ||
| 1970 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
|
28 | if not UnorderedMap.isEmpty(vn) then |
| 1971 | ✗ | for e in UnorderedMap.valueList(eo) loop | |
| 1972 | ✗ | eqn_ptr := EquationPointers.getEqnAt(eqns, e); | |
| 1973 | ✗ | index := UnorderedMap.getSafe(Equation.getEqnName(eqn_ptr), eqns.map, sourceInfo()); | |
| 1974 | ✗ | occ_set := collectDependenciesEquation(Pointer.access(eqn_ptr), kind, vn, full.dependencies[index], full.solvabilities[index], full.repetitions[index]); | |
| 1975 | ✗ | full.occurrences[index] := UnorderedSet.union(full.occurrences[index], occ_set); | |
| 1976 | end for; | ||
| 1977 | end if; | ||
| 1978 | |||
| 1979 | // II. update new equations with all variables | ||
| 1980 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | if not UnorderedMap.isEmpty(en) then |
| 1981 |
2/2✓ Branch 1 taken 54 times.
✓ Branch 2 taken 28 times.
|
82 | for e in UnorderedMap.valueList(en) loop |
| 1982 | 54 | eqn_ptr := EquationPointers.getEqnAt(eqns, e); | |
| 1983 | 54 | index := UnorderedMap.getSafe(Equation.getEqnName(eqn_ptr), eqns.map, sourceInfo()); | |
| 1984 | 54 | occ_set := collectDependenciesEquation(Pointer.access(eqn_ptr), kind, vars.map, full.dependencies[index], full.solvabilities[index], full.repetitions[index]); | |
| 1985 | 54 | full.equation_names[index] := Equation.getEqnName(eqn_ptr); | |
| 1986 | 54 | full.occurrences[index] := occ_set; | |
| 1987 | end for; | ||
| 1988 | end if; | ||
| 1989 | then full; | ||
| 1990 | |||
| 1991 | else algorithm | ||
| 1992 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected type full, got type " + strictnessString(getStrictness(full)) + "."}); | |
| 1993 | ✗ | then fail(); | |
| 1994 | end match; | ||
| 1995 | |||
| 1996 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | if Flags.isSet(Flags.BLT_MATRIX_DUMP) then |
| 1997 | ✗ | print(toString(full, "Expanded Full") + "\n"); | |
| 1998 | end if; | ||
| 1999 | end expandFull; | ||
| 2000 | |||
| 2001 | function containsLoopCref | ||
| 2002 | "true if the expression contains a cref of the set, also as an element of an array in the set" | ||
| 2003 | input Expression exp; | ||
| 2004 | input UnorderedSet<ComponentRef> set; | ||
| 2005 | output Boolean b = Expression.fold(exp, function isLoopCref(set = set), false); | ||
| 2006 | end containsLoopCref; | ||
| 2007 | |||
| 2008 | function isLoopCref | ||
| 2009 | input Expression exp; | ||
| 2010 | input output Boolean b; | ||
| 2011 | input UnorderedSet<ComponentRef> set; | ||
| 2012 | algorithm | ||
| 2013 | b := match (b, exp) | ||
| 2014 | case (false, Expression.CREF()) | ||
| 2015 |
4/4✓ Branch 1 taken 726 times.
✓ Branch 2 taken 83 times.
✓ Branch 5 taken 34 times.
✓ Branch 6 taken 692 times.
|
809 | then UnorderedSet.contains(exp.cref, set) or UnorderedSet.contains(ComponentRef.stripSubscriptsAll(exp.cref), set); |
| 2016 | else b; | ||
| 2017 | end match; | ||
| 2018 | end isLoopCref; | ||
| 2019 | |||
| 2020 | function refine | ||
| 2021 | "refines the solvability kind using differentiation | ||
| 2022 | Note: only updates the solvabilites of the variables and equations from the maps v and e" | ||
| 2023 | input output Matrix full; | ||
| 2024 | input UnorderedMap<Path, Function> funcMap; | ||
| 2025 | input UnorderedMap<ComponentRef, Integer> v "variables to refine"; | ||
| 2026 | input UnorderedMap<ComponentRef, Integer> e "equations to refine"; | ||
| 2027 | input VariablePointers vars "all variables"; | ||
| 2028 | input EquationPointers eqns "all equations"; | ||
| 2029 | input UnorderedSet<ComponentRef> vars_set "context variables to determine solvability"; | ||
| 2030 | input Boolean init "true if initial"; | ||
| 2031 | algorithm | ||
| 2032 | full := match full | ||
| 2033 | local | ||
| 2034 | DifferentiationArguments diffArgs = DifferentiationArguments.default(NBDifferentiate.DifferentiationType.SIMPLE, funcMap); | ||
| 2035 | Pointer<Equation> eqn_ptr; | ||
| 2036 | Expression residual = Expression.EMPTY(Type.REAL()), exp; | ||
| 2037 | Solve.Status status; | ||
| 2038 | Solvability sol; | ||
| 2039 | UnorderedSet<ComponentRef> linear_set, param_set, var_set; | ||
| 2040 | Boolean eqnIsDiscrete, eqnIsIf, eqnHasNoResidual, diffOk; | ||
| 2041 | Option<Expression> residual_opt; | ||
| 2042 | |||
| 2043 | case FULL() algorithm | ||
| 2044 |
3/4✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 4 taken 1657 times.
✓ Branch 5 taken 96 times.
|
1849 | for eqn_idx in UnorderedMap.valueArray(e) loop |
| 2045 | 1657 | eqn_ptr := EquationPointers.getEqnAt(eqns, eqn_idx); | |
| 2046 | // ALGORITHM equations have no simple scalar residual for getResidualExp -- | ||
| 2047 | // treat them like discrete equations (solveSimple fallback below) instead of | ||
| 2048 | // crashing, now that NBTearing.mo's initialize can pass them in here. | ||
| 2049 |
5/6✓ Branch 1 taken 1653 times.
✓ Branch 2 taken 4 times.
✓ Branch 4 taken 1653 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 1650 times.
|
1657 | eqnIsDiscrete := Equation.isDiscrete(eqn_ptr) or Equation.isWhenEquation(eqn_ptr) or Equation.isAlgorithm(eqn_ptr); |
| 2050 | 1657 | eqnIsIf := Equation.isIfEquation(eqn_ptr); | |
| 2051 | 1657 | eqnHasNoResidual := false; | |
| 2052 |
2/2✓ Branch 0 taken 1650 times.
✓ Branch 1 taken 7 times.
|
1657 | if not (eqnIsDiscrete or eqnIsIf) then |
| 2053 | // e.g. a RECORD_EQUATION whose type has no '+'/'-'/'0' operators (a plain | ||
| 2054 | // Medium ThermodynamicState, for example) can't have a residual built at | ||
| 2055 | // all -- fall back to IMPLICIT below instead of crashing. | ||
| 2056 | 1650 | residual_opt := Equation.tryGetResidualExp(eqn_ptr); | |
| 2057 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1650 times.
✓ Branch 2 taken 1641 times.
✓ Branch 3 taken 9 times.
|
1650 | if isSome(residual_opt) then |
| 2058 | 1641 | SOME(residual) := residual_opt; | |
| 2059 | else | ||
| 2060 | eqnHasNoResidual := true; | ||
| 2061 | end if; | ||
| 2062 | end if; | ||
| 2063 |
3/4✗ Branch 2 not taken.
✓ Branch 3 taken 1657 times.
✓ Branch 5 taken 4794 times.
✓ Branch 6 taken 1657 times.
|
8108 | for var in UnorderedSet.toArray(full.occurrences[eqn_idx]) loop |
| 2064 | // only do something if var is to be refined | ||
| 2065 |
2/2✓ Branch 1 taken 3925 times.
✓ Branch 2 taken 869 times.
|
4794 | if UnorderedMap.contains(var, v) then |
| 2066 | // only do something if it is not implicit or unsolvable) | ||
| 2067 | 3925 | sol := UnorderedMap.getSafe(var, full.solvabilities[eqn_idx], sourceInfo()); | |
| 2068 |
2/2✓ Branch 2 taken 3713 times.
✓ Branch 3 taken 212 times.
|
3925 | if Solvability.rank(sol) < Solvability.rank(Solvability.IMPLICIT()) then |
| 2069 | // booleans or (todo: enumerations) | ||
| 2070 |
6/6✓ Branch 0 taken 1805 times.
✓ Branch 1 taken 1908 times.
✓ Branch 3 taken 3703 times.
✓ Branch 4 taken 10 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 3701 times.
|
5518 | if eqnIsDiscrete or not BVariable.checkCref(var, function BVariable.isContinuous(staticAsContinuous = init), sourceInfo()) then |
| 2071 | // if the equation or cref type is boolean, it can only be solved if its isolated in the LHS or RHS | ||
| 2072 | // Use solveSimple for this and check if status is EXPLICIT | ||
| 2073 | 12 | (_, status, _) := Solve.solveSimple(Pointer.access(eqn_ptr), var); | |
| 2074 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
|
12 | sol := if status == NBSolve.Status.EXPLICIT then Solvability.EXPLICIT_LINEAR(NONE(), NONE()) else Solvability.UNSOLVABLE(); |
| 2075 | elseif eqnIsIf or eqnHasNoResidual then | ||
| 2076 | // TODO more thorough analysis | ||
| 2077 | sol := Solvability.IMPLICIT(); | ||
| 2078 | else | ||
| 2079 | // get the residual expression, differentiate and simplify it | ||
| 2080 | 3671 | diffArgs.diffCref := var; | |
| 2081 | try | ||
| 2082 | 3671 | (exp, diffArgs) := Differentiate.differentiateExpressionDump(residual, diffArgs, getInstanceName()); | |
| 2083 | 3671 | exp := SimplifyExp.simplifyDump(exp, true, getInstanceName()); | |
| 2084 | diffOk := true; | ||
| 2085 | else | ||
| 2086 | // not everything can be differentiated, e.g. functions with function inputs | ||
| 2087 | ✗ | exp := residual; | |
| 2088 | diffOk := false; | ||
| 2089 | end try; | ||
| 2090 |
1/2✓ Branch 0 taken 3671 times.
✗ Branch 1 not taken.
|
3671 | if not diffOk then |
| 2091 | sol := Solvability.IMPLICIT(); | ||
| 2092 | elseif Expression.isZero(exp) then | ||
| 2093 | sol := Solvability.UNSOLVABLE(); | ||
| 2094 | elseif containsLoopCref(exp, vars_set) then | ||
| 2095 | // nonlinear -> unique solution if does not contain the variable itself | ||
| 2096 | // TODO: might still be unique in some cases, even if contains the variable, e.g. `exp(x)` | ||
| 2097 |
2/2✓ Branch 1 taken 42 times.
✓ Branch 2 taken 75 times.
|
159 | sol := Solvability.EXPLICIT_NONLINEAR(not Expression.containsCref(exp, var)); |
| 2098 | else | ||
| 2099 | // linear -> find all contained crefs and split them by kind. remove constants and save params / variables | ||
| 2100 | 3554 | linear_set := Expression.extractCrefs(exp); | |
| 2101 | 3554 | linear_set := UnorderedSet.filterOnFalse(linear_set, function BVariable.checkCref(func = BVariable.isConst, info = sourceInfo())); | |
| 2102 | 3554 | (param_set, var_set) := UnorderedSet.splitOnTrue(linear_set, function BVariable.checkCref(func = BVariable.isParamOrConst, info = sourceInfo())); | |
| 2103 |
4/4✓ Branch 1 taken 473 times.
✓ Branch 2 taken 3081 times.
✓ Branch 5 taken 71 times.
✓ Branch 6 taken 3483 times.
|
3625 | sol := Solvability.EXPLICIT_LINEAR( |
| 2104 | pars = if UnorderedSet.isEmpty(param_set) then NONE() else SOME(param_set), | ||
| 2105 | vars = if UnorderedSet.isEmpty(var_set) then NONE() else SOME(var_set)); | ||
| 2106 | end if; | ||
| 2107 | end if; | ||
| 2108 | 3713 | UnorderedMap.add(var, sol, full.solvabilities[eqn_idx]); | |
| 2109 | end if; | ||
| 2110 | end if; | ||
| 2111 | end for; | ||
| 2112 | end for; | ||
| 2113 | 96 | then full; | |
| 2114 | else algorithm | ||
| 2115 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected type full, got type " + strictnessString(getStrictness(full)) + "."}); | |
| 2116 | ✗ | then fail(); | |
| 2117 | end match; | ||
| 2118 | |||
| 2119 |
1/2✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
|
96 | if Flags.isSet(Flags.BLT_MATRIX_DUMP) then |
| 2120 | ✗ | print(toString(full, "Refined Full") + "\n"); | |
| 2121 | end if; | ||
| 2122 | end refine; | ||
| 2123 | |||
| 2124 | function compress | ||
| 2125 | "use after equations have been removed" | ||
| 2126 | input output Matrix adj; | ||
| 2127 | input output Matrix full; | ||
| 2128 | input EquationPointers eqns; | ||
| 2129 | input VariablePointers vars; | ||
| 2130 | input UnorderedMap<ComponentRef, Integer> old_map; | ||
| 2131 | protected | ||
| 2132 | Integer index_old, index_new, size = EquationPointers.size(eqns); | ||
| 2133 | ComponentRef name; | ||
| 2134 | array<ComponentRef> equation_names; | ||
| 2135 | array<UnorderedSet<ComponentRef>> occurrences; | ||
| 2136 | array<UnorderedMap<ComponentRef, Dependency>> dependencies; | ||
| 2137 | array<UnorderedMap<ComponentRef, Solvability>> solvabilities; | ||
| 2138 | array<UnorderedSet<ComponentRef>> repetitions; | ||
| 2139 | Mapping mapping; | ||
| 2140 | IntMatrix m; | ||
| 2141 | array<Integer> m_data, m_aux; | ||
| 2142 | Integer old_start, old_size, new_start, new_size; | ||
| 2143 | algorithm | ||
| 2144 | (adj, full) := match (adj, full) | ||
| 2145 | local | ||
| 2146 | Matrix new_adj, new_full; | ||
| 2147 | case (FINAL(), FULL()) algorithm | ||
| 2148 | // create the index mapping from scratch | ||
| 2149 | ✗ | mapping := Mapping.create(eqns, vars); | |
| 2150 | |||
| 2151 | // create empty arrays for the structures | ||
| 2152 | ✗ | m := IntMatrix.new(arrayLength(mapping.eqn_StA)); | |
| 2153 | ✗ | m_data := IntMatrix.entries(adj.m); | |
| 2154 | ✗ | m_aux := IntMatrix.payload(adj.m); | |
| 2155 | ✗ | equation_names := arrayCreate(size, ComponentRef.EMPTY()); | |
| 2156 | ✗ | occurrences := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 2157 | ✗ | dependencies := arrayCreate(size, UnorderedMap.new<Dependency>(ComponentRef.hash, ComponentRef.isEqual)); | |
| 2158 | ✗ | solvabilities := arrayCreate(size, UnorderedMap.new<Solvability>(ComponentRef.hash, ComponentRef.isEqual)); | |
| 2159 | ✗ | repetitions := arrayCreate(size, UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 2160 | // loop over each equation and copy the corresponding maps and sets | ||
| 2161 | ✗ | for eqn_ptr in EquationPointers.toList(eqns) loop | |
| 2162 | ✗ | name := Equation.getEqnName(eqn_ptr); | |
| 2163 | ✗ | index_new := UnorderedMap.getSafe(name, eqns.map, sourceInfo()); | |
| 2164 | ✗ | index_old := UnorderedMap.getSafe(name, old_map, sourceInfo()); | |
| 2165 | // create structures for final matrix | ||
| 2166 | ✗ | (old_start, old_size) := adj.mapping.eqn_AtS[index_old]; | |
| 2167 | ✗ | (new_start, new_size) := mapping.eqn_AtS[index_new]; | |
| 2168 | ✗ | if old_size == new_size then | |
| 2169 | ✗ | for i in 0:old_size-1 loop | |
| 2170 | ✗ | IntMatrix.copyRow(adj.m, old_start+i, m_data, m_aux, m, new_start+i); | |
| 2171 | end for; | ||
| 2172 | else | ||
| 2173 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " sizes (old: " + intString(old_size) + ", new: " | |
| 2174 | + intString(new_size) + " do not mach for equation:\n" + Equation.pointerToString(eqn_ptr)}); | ||
| 2175 | ✗ | fail(); | |
| 2176 | end if; | ||
| 2177 | // create the structures for full matrix | ||
| 2178 | ✗ | equation_names[index_new] := name; | |
| 2179 | ✗ | occurrences[index_new] := full.occurrences[index_old]; | |
| 2180 | ✗ | dependencies[index_new] := full.dependencies[index_old]; | |
| 2181 | ✗ | solvabilities[index_new] := full.solvabilities[index_old]; | |
| 2182 | ✗ | repetitions[index_new] := full.repetitions[index_old]; | |
| 2183 | end for; | ||
| 2184 | |||
| 2185 | ✗ | new_adj := FINAL(m, IntMatrix.transpose(m, VariablePointers.scalarSize(vars, true)), mapping, adj.modes, adj.st); | |
| 2186 | ✗ | new_full := FULL(equation_names, occurrences, dependencies, solvabilities, repetitions, mapping); | |
| 2187 | then (new_adj, new_full); | ||
| 2188 | |||
| 2189 | else algorithm | ||
| 2190 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected types final and full, got types " + strictnessString(getStrictness(adj)) | |
| 2191 | + " and " + strictnessString(getStrictness(full)) + "."}); | ||
| 2192 | ✗ | then fail(); | |
| 2193 | end match; | ||
| 2194 | |||
| 2195 | ✗ | if Flags.isSet(Flags.BLT_MATRIX_DUMP) then | |
| 2196 | ✗ | print(toString(adj, "Compressed Final") + "\n"); | |
| 2197 | ✗ | print(toString(full, "Compressed Full") + "\n"); | |
| 2198 | end if; | ||
| 2199 | end compress; | ||
| 2200 | |||
| 2201 | function combine | ||
| 2202 | "for now only combines sparsity matrices as its the only one needed" | ||
| 2203 | input list<Matrix> matrices; | ||
| 2204 | output Matrix result; | ||
| 2205 | protected | ||
| 2206 | list<list<ComponentRef>> equation_names = {}; | ||
| 2207 | list<list<Iterator>> equation_iterators = {}; | ||
| 2208 | list<list<UnorderedMap<ComponentRef, Dependency>>> dependencies = {}; | ||
| 2209 | list<list<UnorderedSet<ComponentRef>>> repetitions = {}; | ||
| 2210 | list<list<list<ComponentRef>>> solved_crefs = {}; | ||
| 2211 | algorithm | ||
| 2212 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
|
6 | for matrix in listReverse(matrices) loop |
| 2213 | _ := match matrix | ||
| 2214 | case SPARSITY() algorithm | ||
| 2215 | 4 | equation_names := arrayList(matrix.equation_names) :: equation_names; | |
| 2216 | 4 | equation_iterators := arrayList(matrix.equation_iterators) :: equation_iterators; | |
| 2217 | 4 | dependencies := arrayList(matrix.dependencies) :: dependencies; | |
| 2218 | 4 | repetitions := arrayList(matrix.repetitions) :: repetitions; | |
| 2219 | 4 | solved_crefs := arrayList(matrix.solved_crefs) :: solved_crefs; | |
| 2220 | then (); | ||
| 2221 | |||
| 2222 | else algorithm | ||
| 2223 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " expected type sparsity, got type " + strictnessString(getStrictness(matrix)) + "."}); | |
| 2224 | ✗ | then fail(); | |
| 2225 | end match; | ||
| 2226 | end for; | ||
| 2227 | |||
| 2228 | // compile the final result | ||
| 2229 | 2 | result := SPARSITY( | |
| 2230 | equation_names = listArray(List.flatten(equation_names)), | ||
| 2231 | equation_iterators = listArray(List.flatten(equation_iterators)), | ||
| 2232 | dependencies = listArray(List.flatten(dependencies)), | ||
| 2233 | repetitions = listArray(List.flatten(repetitions)), | ||
| 2234 | solved_crefs = listArray(List.flatten(solved_crefs)) | ||
| 2235 | ); | ||
| 2236 | end combine; | ||
| 2237 | |||
| 2238 | function toString | ||
| 2239 | input Matrix adj; | ||
| 2240 | input output String str = ""; | ||
| 2241 | algorithm | ||
| 2242 | str := match adj | ||
| 2243 | local | ||
| 2244 | list<Type> types; | ||
| 2245 | array<String> solved, names, types_str, complex_sizes; | ||
| 2246 | Integer length0, length1, length2, length3; | ||
| 2247 | |||
| 2248 | case FULL() algorithm | ||
| 2249 | ✗ | str := StringUtil.headline_2(str + "FULL Adjacency Matrix") + "\n"; | |
| 2250 | ✗ | types := list(ComponentRef.getSubscriptedType(name) for name in adj.equation_names); | |
| 2251 | ✗ | complex_sizes := listArray(list(Util.applyOptionOrDefault(Type.complexSize(ty, true), intString, "0") for ty in types)); | |
| 2252 | ✗ | types_str := listArray(list(dimsString(Type.arrayDims(ty)) for ty in types)); | |
| 2253 | ✗ | names := listArray(list(ComponentRef.toString(name) for name in adj.equation_names)); | |
| 2254 | ✗ | length0 := max(stringLength(sz) for sz in complex_sizes); | |
| 2255 | ✗ | length1 := max(stringLength(ty) for ty in types_str) + 1; | |
| 2256 | ✗ | length2 := max(stringLength(name) for name in names) + 3; | |
| 2257 | ✗ | for i in 1:arrayLength(names) loop | |
| 2258 | ✗ | str := str | |
| 2259 | + arrayGet(complex_sizes, i) + " " + StringUtil.repeat(" ", length0 - stringLength(arrayGet(complex_sizes, i))) + " | " | ||
| 2260 | + arrayGet(types_str, i) + " " + StringUtil.repeat(".", length1 - stringLength(arrayGet(types_str, i))) | ||
| 2261 | + arrayGet(names, i) + " " + StringUtil.repeat(".", length2 - stringLength(arrayGet(names, i))) | ||
| 2262 | + " " + List.toString(UnorderedSet.toList(adj.occurrences[i]), function fullString(dep_map = adj.dependencies[i], | ||
| 2263 | sol_map = adj.solvabilities[i], rep_set = adj.repetitions[i])) + "\n"; | ||
| 2264 | end for; | ||
| 2265 | then str; | ||
| 2266 | |||
| 2267 | case FINAL() algorithm | ||
| 2268 | ✗ | str := StringUtil.headline_2(str + "FINAL Adjacency Matrix") + "\n"; | |
| 2269 | ✗ | if IntMatrix.rows(adj.m) > 0 then | |
| 2270 | ✗ | str := str + StringUtil.headline_4("Normal Adjacency Matrix (row = equation)"); | |
| 2271 | ✗ | str := str + IntMatrix.toString(adj.m); | |
| 2272 | end if; | ||
| 2273 | ✗ | str := str + "\n"; | |
| 2274 | ✗ | if IntMatrix.rows(adj.mT) > 0 then | |
| 2275 | ✗ | str := str + StringUtil.headline_4("Transposed Adjacency Matrix (row = variable)"); | |
| 2276 | ✗ | str := str + IntMatrix.toString(adj.mT); | |
| 2277 | end if; | ||
| 2278 | ✗ | str := str + "\n" + Mapping.toString(adj.mapping); | |
| 2279 | then str; | ||
| 2280 | |||
| 2281 | case SPARSITY() algorithm | ||
| 2282 | 4 | str := StringUtil.headline_2(str + "SPARSITY Adjacency Matrix") + "\n"; | |
| 2283 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
|
20 | types := list(ComponentRef.getSubscriptedType(name) for name in adj.equation_names); |
| 2284 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4 times.
|
10 | complex_sizes := listArray(list(Util.applyOptionOrDefault(Type.complexSize(ty, true), intString, "0") for ty in types)); |
| 2285 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 4 times.
|
10 | types_str := listArray(list(dimsString(Type.arrayDims(ty)) for ty in types)); |
| 2286 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
|
20 | names := listArray(list(ComponentRef.toString(name) for name in adj.equation_names)); |
| 2287 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
|
20 | solved := listArray(list(List.toString(var_list, ComponentRef.toString) for var_list in adj.solved_crefs)); |
| 2288 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
|
10 | length0 := max(stringLength(sz) for sz in complex_sizes); |
| 2289 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
|
10 | length1 := max(stringLength(ty) for ty in types_str) + 1; |
| 2290 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
|
10 | length2 := max(stringLength(name) for name in names) + 3; |
| 2291 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4 times.
|
10 | length3 := max(stringLength(var) for var in solved) + 3; |
| 2292 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
10 | for i in 1:arrayLength(names) loop |
| 2293 | 6 | str := str | |
| 2294 | + arrayGet(complex_sizes, i) + " " + StringUtil.repeat(" ", length0 - stringLength(arrayGet(complex_sizes, i))) + " | " | ||
| 2295 | + arrayGet(types_str, i) + " " + StringUtil.repeat(".", length1 - stringLength(arrayGet(types_str, i))) | ||
| 2296 | + arrayGet(names, i) + " " + StringUtil.repeat(".", length2 - stringLength(arrayGet(names, i))) | ||
| 2297 | + arrayGet(solved, i) + " " + StringUtil.repeat(".", length3 - stringLength(arrayGet(solved, i))) | ||
| 2298 | + " " + List.toString(UnorderedMap.keyList(adj.dependencies[i]), function sparsityString(dep_map = adj.dependencies[i], | ||
| 2299 | rep_set = adj.repetitions[i])) + "\n"; | ||
| 2300 | end for; | ||
| 2301 | then str; | ||
| 2302 | |||
| 2303 | ✗ | case EMPTY() then str + StringUtil.headline_4("EMPTY Adjacency Matrix") + "\n"; | |
| 2304 | else algorithm | ||
| 2305 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unknown adjacency matrix type."}); | |
| 2306 | ✗ | then fail(); | |
| 2307 | end match; | ||
| 2308 | end toString; | ||
| 2309 | |||
| 2310 | function solvabilityString | ||
| 2311 | input Matrix adj; | ||
| 2312 | input output String str = ""; | ||
| 2313 | algorithm | ||
| 2314 | str := match adj | ||
| 2315 | local | ||
| 2316 | list<ComponentRef> XX, II, NM, NP, LV, LP, LC, QQ; | ||
| 2317 | list<String> xx = {}, ii = {}, nm = {}, np = {}, lv = {}, lp = {}, lc = {}, qq = {}; | ||
| 2318 | array<String> names, types, XX_, II_, NM_, NP_, LV_, LP_, LC_, QQ_; | ||
| 2319 | Integer length1, length2, length_xx, length_ii, length_nm, length_np, length_lv, length_lp, length_lc, length_qq; | ||
| 2320 | |||
| 2321 | case FULL() algorithm | ||
| 2322 | ✗ | str := StringUtil.headline_2(str + " Solvability Adjacency Matrix") + "\n"; | |
| 2323 | ✗ | types := listArray(list(intString(Type.sizeOf(ComponentRef.getSubscriptedType(name), true)) for name in adj.equation_names)); | |
| 2324 | ✗ | names := listArray(list(ComponentRef.toString(name) for name in adj.equation_names)); | |
| 2325 | ✗ | for i in arrayLength(names):-1:1 loop | |
| 2326 | ✗ | (XX, II, NM, NP, LV, LP, LC, QQ) := Solvability.categorize(UnorderedSet.toList(adj.occurrences[i]), adj.solvabilities[i]); | |
| 2327 | ✗ | xx := List.toStringCustom(XX, ComponentRef.toString, "XX ", "{", ",", "}", false) :: xx; | |
| 2328 | ✗ | ii := List.toStringCustom(II, ComponentRef.toString, "II ", "{", ",", "}", false) :: ii; | |
| 2329 | ✗ | nm := List.toStringCustom(NM, ComponentRef.toString, "N- ", "{", ",", "}", false) :: nm; | |
| 2330 | ✗ | np := List.toStringCustom(NP, ComponentRef.toString, "N+ ", "{", ",", "}", false) :: np; | |
| 2331 | ✗ | lv := List.toStringCustom(LV, ComponentRef.toString, "LV ", "{", ",", "}", false) :: lv; | |
| 2332 | ✗ | lp := List.toStringCustom(LP, ComponentRef.toString, "LP ", "{", ",", "}", false) :: lp; | |
| 2333 | ✗ | lc := List.toStringCustom(LC, ComponentRef.toString, "LC ", "{", ",", "}", false) :: lc; | |
| 2334 | ✗ | qq := List.toStringCustom(QQ, ComponentRef.toString, "|| ", "{", ",", "}", false) :: qq; | |
| 2335 | end for; | ||
| 2336 | ✗ | XX_ := listArray(xx); | |
| 2337 | ✗ | II_ := listArray(ii); | |
| 2338 | ✗ | NM_ := listArray(nm); | |
| 2339 | ✗ | NP_ := listArray(np); | |
| 2340 | ✗ | LV_ := listArray(lv); | |
| 2341 | ✗ | LP_ := listArray(lp); | |
| 2342 | ✗ | LC_ := listArray(lc); | |
| 2343 | ✗ | QQ_ := listArray(qq); | |
| 2344 | ✗ | length1 := max(stringLength(ty) for ty in types) + 1; | |
| 2345 | ✗ | length2 := max(stringLength(name) for name in names) + 3; | |
| 2346 | ✗ | length_xx := max(stringLength(s) for s in XX_); | |
| 2347 | ✗ | length_ii := max(stringLength(s) for s in II_); | |
| 2348 | ✗ | length_nm := max(stringLength(s) for s in NM_); | |
| 2349 | ✗ | length_np := max(stringLength(s) for s in NP_); | |
| 2350 | ✗ | length_lv := max(stringLength(s) for s in LV_); | |
| 2351 | ✗ | length_lp := max(stringLength(s) for s in LP_); | |
| 2352 | ✗ | length_lc := max(stringLength(s) for s in LC_); | |
| 2353 | ✗ | length_qq := max(stringLength(s) for s in QQ_); | |
| 2354 | ✗ | for i in 1:arrayLength(names) loop | |
| 2355 | ✗ | str := str + arrayGet(types, i) + " " + StringUtil.repeat(".", length1 - stringLength(arrayGet(types, i))) + " " | |
| 2356 | + arrayGet(names, i) + " " + StringUtil.repeat(".", length2 - stringLength(arrayGet(names, i))) | ||
| 2357 | + arrayGet(LC_, i) + " " + StringUtil.repeat(".", length_lc - stringLength(arrayGet(LC_, i))) | ||
| 2358 | + arrayGet(LP_, i) + " " + StringUtil.repeat(".", length_lp - stringLength(arrayGet(LP_, i))) | ||
| 2359 | + arrayGet(LV_, i) + " " + StringUtil.repeat(".", length_lv - stringLength(arrayGet(LV_, i))) | ||
| 2360 | + arrayGet(NP_, i) + " " + StringUtil.repeat(".", length_np - stringLength(arrayGet(NP_, i))) | ||
| 2361 | + arrayGet(NM_, i) + " " + StringUtil.repeat(".", length_nm - stringLength(arrayGet(NM_, i))) | ||
| 2362 | + arrayGet(II_, i) + " " + StringUtil.repeat(".", length_ii - stringLength(arrayGet(II_, i))) | ||
| 2363 | + arrayGet(XX_, i) + " " + StringUtil.repeat(".", length_xx - stringLength(arrayGet(XX_, i))) | ||
| 2364 | + arrayGet(QQ_, i) + " " + StringUtil.repeat(".", length_qq - stringLength(arrayGet(QQ_, i))) + "\n"; | ||
| 2365 | end for; | ||
| 2366 | then str; | ||
| 2367 | ✗ | else toString(adj, str); | |
| 2368 | end match; | ||
| 2369 | end solvabilityString; | ||
| 2370 | |||
| 2371 | function dependencyString | ||
| 2372 | input Matrix adj; | ||
| 2373 | input output String str = ""; | ||
| 2374 | algorithm | ||
| 2375 | str := match adj | ||
| 2376 | local | ||
| 2377 | list<ComponentRef> F, R, E, A, S, K; | ||
| 2378 | list<String> f = {}, r = {}, e = {}, a = {}, s = {}, k = {}; | ||
| 2379 | array<String> names, types, F_, R_, E_, A_, S_, K_; | ||
| 2380 | Integer length1, length2, lengthf, lengthr, lengthe, lengtha, lengths, lengthk; | ||
| 2381 | |||
| 2382 | case FULL() algorithm | ||
| 2383 | ✗ | str := StringUtil.headline_2(str + " Dependency Adjacency Matrix") + "\n"; | |
| 2384 | ✗ | types := listArray(list(intString(Type.sizeOf(ComponentRef.getSubscriptedType(name), true)) for name in adj.equation_names)); | |
| 2385 | ✗ | names := listArray(list(ComponentRef.toString(name) for name in adj.equation_names)); | |
| 2386 | ✗ | for i in arrayLength(names):-1:1 loop | |
| 2387 | ✗ | (F, R, E, A, S, K) := Dependency.categorize(UnorderedSet.toList(adj.occurrences[i]), adj.dependencies[i], adj.repetitions[i]); | |
| 2388 | ✗ | f := List.toStringCustom(F, ComponentRef.toString, "[!]", "{", ",", "}", false) :: f; | |
| 2389 | ✗ | r := List.toStringCustom(R, ComponentRef.toString, "[-]", "{", ",", "}", false) :: r; | |
| 2390 | ✗ | e := List.toStringCustom(E, ComponentRef.toString, "[+]", "{", ",", "}", false) :: e; | |
| 2391 | ✗ | a := List.toStringCustom(A, ComponentRef.toString, "[:]", "{", ",", "}", false) :: a; | |
| 2392 | ✗ | s := List.toStringCustom(S, ComponentRef.toString, "[.]", "{", ",", "}", false) :: s; | |
| 2393 | ✗ | k := List.toStringCustom(K, ComponentRef.toString, "[o]", "{", ",", "}", false) :: k; | |
| 2394 | end for; | ||
| 2395 | ✗ | F_ := listArray(f); | |
| 2396 | ✗ | R_ := listArray(r); | |
| 2397 | ✗ | E_ := listArray(e); | |
| 2398 | ✗ | A_ := listArray(a); | |
| 2399 | ✗ | S_ := listArray(s); | |
| 2400 | ✗ | K_ := listArray(k); | |
| 2401 | ✗ | length1 := max(stringLength(ty) for ty in types) + 1; | |
| 2402 | ✗ | length2 := max(stringLength(name) for name in names) + 3; | |
| 2403 | ✗ | lengthf := max(stringLength(st) for st in F_); | |
| 2404 | ✗ | lengthr := max(stringLength(st) for st in R_); | |
| 2405 | ✗ | lengthe := max(stringLength(st) for st in E_); | |
| 2406 | ✗ | lengtha := max(stringLength(st) for st in A_); | |
| 2407 | ✗ | lengths := max(stringLength(st) for st in S_); | |
| 2408 | ✗ | lengthk := max(stringLength(st) for st in K_); | |
| 2409 | ✗ | for i in 1:arrayLength(names) loop | |
| 2410 | ✗ | str := str + arrayGet(types, i) + " " + StringUtil.repeat(".", length1 - stringLength(arrayGet(types, i))) + " " | |
| 2411 | + arrayGet(names, i) + " " + StringUtil.repeat(".", length2 - stringLength(arrayGet(names, i))) | ||
| 2412 | + arrayGet(K_, i) + " " + StringUtil.repeat(".", lengthk - stringLength(arrayGet(K_, i))) | ||
| 2413 | + arrayGet(S_, i) + " " + StringUtil.repeat(".", lengths - stringLength(arrayGet(S_, i))) | ||
| 2414 | + arrayGet(A_, i) + " " + StringUtil.repeat(".", lengtha - stringLength(arrayGet(A_, i))) | ||
| 2415 | + arrayGet(E_, i) + " " + StringUtil.repeat(".", lengthe - stringLength(arrayGet(E_, i))) | ||
| 2416 | + arrayGet(R_, i) + " " + StringUtil.repeat(".", lengthr - stringLength(arrayGet(R_, i))) | ||
| 2417 | + arrayGet(F_, i) + " " + StringUtil.repeat(".", lengthf - stringLength(arrayGet(F_, i))) + "\n"; | ||
| 2418 | end for; | ||
| 2419 | then str; | ||
| 2420 | ✗ | else toString(adj, str); | |
| 2421 | end match; | ||
| 2422 | end dependencyString; | ||
| 2423 | |||
| 2424 | function getStrictness | ||
| 2425 | input Matrix adj; | ||
| 2426 | output MatrixStrictness st; | ||
| 2427 | algorithm | ||
| 2428 | st := match adj | ||
| 2429 | case FULL() then MatrixStrictness.FULL; | ||
| 2430 | 2058 | case FINAL() then adj.st; | |
| 2431 | ✗ | case EMPTY() then adj.st; | |
| 2432 | else fail(); | ||
| 2433 | end match; | ||
| 2434 | end getStrictness; | ||
| 2435 | |||
| 2436 | function isEmpty | ||
| 2437 | input Matrix adj; | ||
| 2438 | output Boolean b; | ||
| 2439 | algorithm | ||
| 2440 | b := match adj | ||
| 2441 | case EMPTY() then true; | ||
| 2442 | else false; | ||
| 2443 | end match; | ||
| 2444 | end isEmpty; | ||
| 2445 | |||
| 2446 | function getMappingOpt | ||
| 2447 | input Matrix adj; | ||
| 2448 | output Option<Mapping> mapping; | ||
| 2449 | algorithm | ||
| 2450 | mapping := match adj | ||
| 2451 | 6 | case FULL() then SOME(adj.mapping); | |
| 2452 | 136 | case FINAL() then SOME(adj.mapping); | |
| 2453 | else NONE(); | ||
| 2454 | end match; | ||
| 2455 | end getMappingOpt; | ||
| 2456 | |||
| 2457 | function nonZeroCount | ||
| 2458 | input Matrix adj; | ||
| 2459 | output Integer count; | ||
| 2460 | algorithm | ||
| 2461 | count := match adj | ||
| 2462 | ✗ | case FINAL() then IntMatrix.nonZeroCount(adj.m); | |
| 2463 | case EMPTY() then 0; | ||
| 2464 | else algorithm | ||
| 2465 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unknown matrix type."}); | |
| 2466 | ✗ | then fail(); | |
| 2467 | end match; | ||
| 2468 | end nonZeroCount; | ||
| 2469 | |||
| 2470 | protected | ||
| 2471 | function fullString | ||
| 2472 | input ComponentRef cref; | ||
| 2473 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 2474 | input UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 2475 | input UnorderedSet<ComponentRef> rep_set; | ||
| 2476 | output String str = ComponentRef.toString(cref) + "["; | ||
| 2477 | algorithm | ||
| 2478 | ✗ | str := str + Solvability.toString(UnorderedMap.getSafe(cref, sol_map, sourceInfo())) | |
| 2479 | + "|" + Dependency.toString(UnorderedMap.getSafe(cref, dep_map, sourceInfo())); | ||
| 2480 | ✗ | if UnorderedSet.contains(cref, rep_set) then str := str + "+"; end if; | |
| 2481 | ✗ | str := str + "]"; | |
| 2482 | end fullString; | ||
| 2483 | |||
| 2484 | function sparsityString | ||
| 2485 | input ComponentRef cref; | ||
| 2486 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 2487 | input UnorderedSet<ComponentRef> rep_set; | ||
| 2488 | output String str = ComponentRef.toString(cref) + "["; | ||
| 2489 | algorithm | ||
| 2490 | 5 | str := str + Dependency.toString(UnorderedMap.getSafe(cref, dep_map, sourceInfo())); | |
| 2491 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | if UnorderedSet.contains(cref, rep_set) then str := str + "+"; end if; |
| 2492 | 5 | str := str + "]"; | |
| 2493 | end sparsityString; | ||
| 2494 | |||
| 2495 | function dimsString | ||
| 2496 | input list<Dimension> dims; | ||
| 2497 | output String str; | ||
| 2498 | algorithm | ||
| 2499 | str := match dims | ||
| 2500 | case {} then "{1}"; | ||
| 2501 |
4/4✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
|
2 | else List.toString(list(Dimension.size(d, true) for d in dims), intString); |
| 2502 | end match; | ||
| 2503 | end dimsString; | ||
| 2504 | |||
| 2505 | function initialize | ||
| 2506 | input Mapping mapping; | ||
| 2507 | input MatrixStrictness st; | ||
| 2508 | output Matrix adj; | ||
| 2509 | protected | ||
| 2510 | Integer eqn_scalar_size, var_scalar_size; | ||
| 2511 | algorithm | ||
| 2512 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1832 times.
|
1832 | eqn_scalar_size := arrayLength(mapping.eqn_StA); |
| 2513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1832 times.
|
1832 | var_scalar_size := arrayLength(mapping.var_StA); |
| 2514 |
2/2✓ Branch 0 taken 1828 times.
✓ Branch 1 taken 4 times.
|
1832 | if eqn_scalar_size > 0 or var_scalar_size > 0 then |
| 2515 | 1828 | adj := FINAL(IntMatrix.new(eqn_scalar_size), IntMatrix.new(var_scalar_size), mapping, Modes.new(), st); | |
| 2516 | else | ||
| 2517 | 4 | adj := EMPTY(st); | |
| 2518 | end if; | ||
| 2519 | end initialize; | ||
| 2520 | |||
| 2521 | function estimateEntries | ||
| 2522 | "estimates how many entries the given equations contribute, to size the builder" | ||
| 2523 | input array<UnorderedSet<ComponentRef>> occ; | ||
| 2524 | input Mapping mapping; | ||
| 2525 | input list<Integer> indices; | ||
| 2526 | output Integer n = 0; | ||
| 2527 | protected | ||
| 2528 | Integer sz; | ||
| 2529 | algorithm | ||
| 2530 |
2/2✓ Branch 0 taken 27325 times.
✓ Branch 1 taken 4269 times.
|
31594 | for i in indices loop |
| 2531 | 27325 | (_, sz) := mapping.eqn_AtS[i]; | |
| 2532 | 27325 | n := n + UnorderedSet.size(occ[i]) * sz; | |
| 2533 | end for; | ||
| 2534 | end estimateEntries; | ||
| 2535 | |||
| 2536 | function upgradeRow | ||
| 2537 | input Pointer<Equation> eqn_ptr; | ||
| 2538 | input Integer eqn_arr_idx; | ||
| 2539 | input list<ComponentRef> dependencies "dependent var crefs"; | ||
| 2540 | input UnorderedMap<ComponentRef, Dependency> dep "dependency map"; | ||
| 2541 | input UnorderedSet<ComponentRef> rep "repetition set"; | ||
| 2542 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 2543 | input UnorderedMap<ComponentRef, Integer> fullmap "unordered map to check for general relevance"; | ||
| 2544 | input IntMatrix.Builder m; | ||
| 2545 | input Mapping mapping; | ||
| 2546 | input ModeTable modes; | ||
| 2547 | input Iterator iter_ = Iterator.EMPTY(); | ||
| 2548 | protected | ||
| 2549 | Integer eqn_scal_idx, eqn_size; | ||
| 2550 | list<Integer> row; | ||
| 2551 | Equation eqn = Pointer.access(eqn_ptr); | ||
| 2552 | Iterator iter = Equation.getForIterator(eqn); | ||
| 2553 | Type ty = Equation.getType(eqn, true); | ||
| 2554 | list<ComponentRef> names; | ||
| 2555 | list<Expression> ranges; | ||
| 2556 | list<Option<Iterator>> maps; | ||
| 2557 | algorithm | ||
| 2558 | try | ||
| 2559 | // don't do this for if equations as soon as we properly split them | ||
| 2560 |
4/4✓ Branch 1 taken 23445 times.
✓ Branch 2 taken 743 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 23441 times.
|
24188 | if Equation.isAlgorithm(eqn_ptr) or Equation.isIfEquation(eqn_ptr) then |
| 2561 | // algorithm full dependency | ||
| 2562 | 747 | (eqn_scal_idx, eqn_size) := mapping.eqn_AtS[eqn_arr_idx]; | |
| 2563 | 747 | row := Slice.upgradeRowFull(dependencies, map, mapping); | |
| 2564 |
2/2✓ Branch 0 taken 147 times.
✓ Branch 1 taken 600 times.
|
1065 | for i in 0:eqn_size-1 loop |
| 2565 | 318 | IntMatrix.builderAddList(m, eqn_scal_idx+i, row); | |
| 2566 | end for; | ||
| 2567 | else | ||
| 2568 | // todo: if, when single equation (needs to be updated for if) | ||
| 2569 | |||
| 2570 | // add the optional surrounding iterator frames | ||
| 2571 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 23435 times.
|
23441 | if not Iterator.isEmpty(iter_) then |
| 2572 | 6 | (names, ranges, maps) := Iterator.getFrames(iter_); | |
| 2573 | 6 | iter := Iterator.addFrames(iter, List.zip3(names, ranges, maps)); | |
| 2574 | end if; | ||
| 2575 | |||
| 2576 | 23441 | Slice.upgradeRow(Equation.getEqnName(eqn_ptr), eqn_arr_idx, iter, ty, dependencies, dep, rep, map, fullmap, m, mapping, modes); | |
| 2577 | end if; | ||
| 2578 | else | ||
| 2579 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for:\n" + Equation.pointerToString(eqn_ptr)}); | |
| 2580 | ✗ | fail(); | |
| 2581 | end try; | ||
| 2582 | end upgradeRow; | ||
| 2583 | |||
| 2584 | end Matrix; | ||
| 2585 | |||
| 2586 | uniontype Dependency | ||
| 2587 | "the dependency kind to show how a component reference occurs in an equation. | ||
| 2588 | for each dimension there has to be one dependency kind." | ||
| 2589 | type Kind = enumeration(REGULAR, REDUCTION); | ||
| 2590 | |||
| 2591 | record DEPENDENCY | ||
| 2592 | array<list<Integer>> skips; | ||
| 2593 | list<Dependency.Kind> kinds; | ||
| 2594 | end DEPENDENCY; | ||
| 2595 | |||
| 2596 | function toString | ||
| 2597 | input Dependency dep; | ||
| 2598 | output String str; | ||
| 2599 | protected | ||
| 2600 | function kindString | ||
| 2601 | input Kind kind; | ||
| 2602 | output String str; | ||
| 2603 | algorithm | ||
| 2604 | str := match kind | ||
| 2605 | case Kind.REGULAR then ":"; | ||
| 2606 | else "-"; | ||
| 2607 | end match; | ||
| 2608 | end kindString; | ||
| 2609 | String str1, str2; | ||
| 2610 | algorithm | ||
| 2611 | 244 | str1 := Array.toString(dep.skips, function List.toString( | |
| 2612 | inPrintFunc = intString, style = List.Style.FLAT_CURLY), "", "", ", ", ""); | ||
| 2613 | 244 | str2 := List.toString(dep.kinds, kindString, List.Style.FLAT); | |
| 2614 |
2/8✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 244 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
244 | str := if str1 == "" or str2 == "" then str1 + str2 else str1 + ", " + str2; |
| 2615 | 244 | str := "{" + str + "}"; | |
| 2616 | end toString; | ||
| 2617 | |||
| 2618 | function toBoolean | ||
| 2619 | "converts the regular/reduction part of the dependency to a boolean list for scalarization" | ||
| 2620 | input Dependency dep; | ||
| 2621 | output list<Boolean> b = list(not isReductionKind(k) for k in dep.kinds); | ||
| 2622 | end toBoolean; | ||
| 2623 | |||
| 2624 | function create | ||
| 2625 | input Type sub_ty; | ||
| 2626 | input Integer depth; | ||
| 2627 | output Dependency dep; | ||
| 2628 | algorithm | ||
| 2629 |
6/6✓ Branch 2 taken 459 times.
✓ Branch 3 taken 1926 times.
✓ Branch 4 taken 2385 times.
✓ Branch 5 taken 28135 times.
✓ Branch 6 taken 1926 times.
✓ Branch 7 taken 28135 times.
|
30520 | dep := DEPENDENCY(arrayCreate(depth, {}), list(Kind.REGULAR for dim guard(not Dimension.isOne(dim)) in Type.arrayDims(sub_ty))); |
| 2630 | end create; | ||
| 2631 | |||
| 2632 | function update | ||
| 2633 | "sets the dependency of num dimensions | ||
| 2634 | REGULAR -> REDUCTION" | ||
| 2635 | input ComponentRef cref; | ||
| 2636 | input Integer num "number of dependencies to turn to reductions. negative means all"; | ||
| 2637 | input Boolean reverse "true = from right, false = from left"; | ||
| 2638 | input UnorderedMap<ComponentRef, Dependency> map; | ||
| 2639 | protected | ||
| 2640 | Option<Dependency> opt_dep = UnorderedMap.get(cref, map); | ||
| 2641 | Dependency dep; | ||
| 2642 | list<Kind> kinds; | ||
| 2643 | Integer res; | ||
| 2644 | |||
| 2645 | function makeNewKinds | ||
| 2646 | input output list<Kind> kinds; | ||
| 2647 | input output Integer num; | ||
| 2648 | algorithm | ||
| 2649 | (kinds, num) := match (kinds, num) | ||
| 2650 | local | ||
| 2651 | list<Kind> rest; | ||
| 2652 | case (_, 0) then (kinds, num); | ||
| 2653 | case (_::rest, _) algorithm | ||
| 2654 | 634 | (kinds, num) := makeNewKinds(rest, num-1); | |
| 2655 | 634 | then (Kind.REDUCTION :: kinds, num); | |
| 2656 | else (kinds, num); | ||
| 2657 | end match; | ||
| 2658 | end makeNewKinds; | ||
| 2659 | algorithm | ||
| 2660 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 3156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3156 times.
|
3156 | if isSome(opt_dep) then |
| 2661 | 3156 | SOME(dep) := opt_dep; | |
| 2662 | |||
| 2663 | // turn to reductions | ||
| 2664 |
2/2✓ Branch 0 taken 212 times.
✓ Branch 1 taken 2944 times.
|
3156 | if reverse then |
| 2665 | 212 | (kinds, res) := makeNewKinds(listReverse(dep.kinds), num); | |
| 2666 | 212 | dep.kinds := listReverse(kinds); | |
| 2667 | else | ||
| 2668 | 2944 | (kinds, res) := makeNewKinds(dep.kinds, num); | |
| 2669 | 2944 | dep.kinds := kinds; | |
| 2670 | end if; | ||
| 2671 | |||
| 2672 | // if any remain, remove from skips | ||
| 2673 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3144 times.
|
3156 | if res > 0 then |
| 2674 | 12 | removeSkips(cref, map, res, reverse); | |
| 2675 | end if; | ||
| 2676 | |||
| 2677 | // add the updated dependency back to the map | ||
| 2678 | 3156 | UnorderedMap.add(cref, dep, map); | |
| 2679 | else | ||
| 2680 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because cref " | |
| 2681 | + ComponentRef.toString(cref) + " was not found in the map."}); | ||
| 2682 | ✗ | fail(); | |
| 2683 | end if; | ||
| 2684 | end update; | ||
| 2685 | |||
| 2686 | function skip | ||
| 2687 | input ComponentRef cref; | ||
| 2688 | input Integer depth; | ||
| 2689 | input Integer sk; | ||
| 2690 | input UnorderedMap<ComponentRef, Dependency> map; | ||
| 2691 | protected | ||
| 2692 | Option<Dependency> opt_dep = UnorderedMap.get(cref, map); | ||
| 2693 | Dependency dep; | ||
| 2694 | algorithm | ||
| 2695 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1106 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1106 times.
|
1106 | if isSome(opt_dep) then |
| 2696 | 1106 | SOME(dep) := opt_dep; | |
| 2697 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 1106 times.
✓ Branch 2 taken 1097 times.
✓ Branch 3 taken 9 times.
|
2212 | if arrayLength(dep.skips) >= depth then |
| 2698 | // this might scale badly, try to unique the lists in the end or always use sets here | ||
| 2699 | 2194 | arrayUpdate(dep.skips, depth, UnorderedSet.unique_list(sk :: dep.skips[depth], Util.id, intEq)); | |
| 2700 | else | ||
| 2701 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
|
9 | if Flags.isSet(Flags.FAILTRACE) then |
| 2702 | ✗ | Error.addCompilerWarning(getInstanceName() + ": Cref " + ComponentRef.toString(cref) | |
| 2703 | + " was saved with depth " + intString(arrayLength(dep.skips)) + " but depth " + intString(depth) + " was requested."); | ||
| 2704 | end if; | ||
| 2705 | end if; | ||
| 2706 | |||
| 2707 | 1106 | UnorderedMap.add(cref, dep, map); | |
| 2708 | else | ||
| 2709 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because cref " | |
| 2710 | + ComponentRef.toString(cref) + " was not found in the map."}); | ||
| 2711 | ✗ | fail(); | |
| 2712 | end if; | ||
| 2713 | end skip; | ||
| 2714 | |||
| 2715 | function removeSkips | ||
| 2716 | input ComponentRef cref; | ||
| 2717 | input UnorderedMap<ComponentRef, Dependency> map; | ||
| 2718 | input Integer num = -1 "number of skips to remove. negative implys all"; | ||
| 2719 | input Boolean reverse = false "if num > 0 this removes true->from right, false->from left"; | ||
| 2720 | protected | ||
| 2721 | Option<Dependency> opt_dep = UnorderedMap.get(cref, map); | ||
| 2722 | Dependency dep; | ||
| 2723 | Integer rest = num; | ||
| 2724 | Integer i, len; | ||
| 2725 | algorithm | ||
| 2726 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 554 times.
|
554 | if isSome(opt_dep) then |
| 2727 | 554 | SOME(dep) := opt_dep; | |
| 2728 |
2/2✓ Branch 0 taken 542 times.
✓ Branch 1 taken 12 times.
|
554 | if num < 0 then |
| 2729 | // remove all skips | ||
| 2730 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 542 times.
✓ Branch 2 taken 127 times.
✓ Branch 3 taken 415 times.
|
1211 | for i in 1:arrayLength(dep.skips) loop |
| 2731 | 127 | arrayUpdate(dep.skips, i, {}); | |
| 2732 | end for; | ||
| 2733 | else | ||
| 2734 | // remove specific number | ||
| 2735 |
3/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
|
12 | i := if reverse then arrayLength(dep.skips) else 1; |
| 2736 |
4/6✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
|
20 | while rest > 0 and i > 0 and i < arrayLength(dep.skips)+1 loop |
| 2737 | 4 | len := listLength(dep.skips[i]); | |
| 2738 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if len <= rest then |
| 2739 | // can remove full list | ||
| 2740 | 4 | arrayUpdate(dep.skips, i, {}); | |
| 2741 | elseif len > 0 then | ||
| 2742 | // list needs to be reduced | ||
| 2743 | ✗ | if reverse then | |
| 2744 | ✗ | arrayUpdate(dep.skips, i, List.firstN(dep.skips[i], len - rest)); | |
| 2745 | else | ||
| 2746 | ✗ | arrayUpdate(dep.skips, i, List.lastN(dep.skips[i], len - rest)); | |
| 2747 | end if; | ||
| 2748 | end if; | ||
| 2749 | // update rest to remove and move iterator | ||
| 2750 | 4 | rest := rest - len; | |
| 2751 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | i := if reverse then i - 1 else i + 1; |
| 2752 | end while; | ||
| 2753 | end if; | ||
| 2754 | 554 | UnorderedMap.add(cref, dep, map); | |
| 2755 | else | ||
| 2756 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because cref " | |
| 2757 | + ComponentRef.toString(cref) + " was not found in the map."}); | ||
| 2758 | ✗ | fail(); | |
| 2759 | end if; | ||
| 2760 | end removeSkips; | ||
| 2761 | |||
| 2762 | function updateList | ||
| 2763 | input list<ComponentRef> lst; | ||
| 2764 | input Integer num; | ||
| 2765 | input Boolean reverse; | ||
| 2766 | input UnorderedMap<ComponentRef, Dependency> map; | ||
| 2767 | algorithm | ||
| 2768 |
2/2✓ Branch 0 taken 3156 times.
✓ Branch 1 taken 3749 times.
|
6905 | for cref in lst loop |
| 2769 | 3156 | update(cref, num, reverse, map); | |
| 2770 | end for; | ||
| 2771 | end updateList; | ||
| 2772 | |||
| 2773 | function skipList | ||
| 2774 | input list<ComponentRef> lst; | ||
| 2775 | input Integer depth; | ||
| 2776 | input Integer sk; | ||
| 2777 | input UnorderedMap<ComponentRef, Dependency> map; | ||
| 2778 | algorithm | ||
| 2779 |
2/2✓ Branch 0 taken 659 times.
✓ Branch 1 taken 346 times.
|
1005 | for cref in lst loop |
| 2780 | 659 | skip(cref, depth, sk, map); | |
| 2781 | end for; | ||
| 2782 | end skipList; | ||
| 2783 | |||
| 2784 | function removeSkipsList | ||
| 2785 | input list<ComponentRef> lst; | ||
| 2786 | input UnorderedMap<ComponentRef, Dependency> map; | ||
| 2787 | algorithm | ||
| 2788 |
2/2✓ Branch 0 taken 542 times.
✓ Branch 1 taken 679 times.
|
1221 | for cref in lst loop |
| 2789 | 542 | removeSkips(cref, map); | |
| 2790 | end for; | ||
| 2791 | end removeSkipsList; | ||
| 2792 | |||
| 2793 | function addListFull | ||
| 2794 | "adds a list and applies full dependency" | ||
| 2795 | input list<ComponentRef> lst; | ||
| 2796 | input Integer depth; | ||
| 2797 | input UnorderedMap<ComponentRef, Dependency> map; | ||
| 2798 | input UnorderedSet<ComponentRef> rep; | ||
| 2799 | protected | ||
| 2800 | Dependency dep; | ||
| 2801 | algorithm | ||
| 2802 |
2/2✓ Branch 0 taken 212 times.
✓ Branch 1 taken 794 times.
|
1006 | for cref in lst loop |
| 2803 | 212 | UnorderedMap.add(cref, create(ComponentRef.getSubscriptedType(cref), depth), map); | |
| 2804 | 212 | UnorderedSet.add(cref, rep); | |
| 2805 | end for; | ||
| 2806 | 794 | updateList(lst, -1, false, map); | |
| 2807 | end addListFull; | ||
| 2808 | |||
| 2809 | function isReductionKind | ||
| 2810 | input Dependency.Kind kind; | ||
| 2811 | output Boolean b = kind == Kind.REDUCTION; | ||
| 2812 | end isReductionKind; | ||
| 2813 | |||
| 2814 | function categorize | ||
| 2815 | input list<ComponentRef> crefs; | ||
| 2816 | input UnorderedMap<ComponentRef, Dependency> map; | ||
| 2817 | input UnorderedSet<ComponentRef> rep_set; | ||
| 2818 | output list<ComponentRef> F = {}; | ||
| 2819 | output list<ComponentRef> R = {}; | ||
| 2820 | output list<ComponentRef> E = {}; | ||
| 2821 | output list<ComponentRef> A = {}; | ||
| 2822 | output list<ComponentRef> S = {}; | ||
| 2823 | output list<ComponentRef> K = {}; | ||
| 2824 | protected | ||
| 2825 | Boolean repeats; | ||
| 2826 | algorithm | ||
| 2827 | ✗ | for cref in crefs loop | |
| 2828 | ✗ | repeats := UnorderedSet.contains(cref, rep_set); | |
| 2829 | _ := match UnorderedMap.getSafe(cref, map, sourceInfo()) | ||
| 2830 | local | ||
| 2831 | array<list<Integer>> skips; | ||
| 2832 | list<Kind> kinds; | ||
| 2833 | case DEPENDENCY(skips = skips) guard(not Array.all(skips, listEmpty)) | ||
| 2834 | algorithm K := cref :: K; then (); | ||
| 2835 | case DEPENDENCY(kinds = {}) guard(repeats) | ||
| 2836 | algorithm E := cref :: E; then (); | ||
| 2837 | case DEPENDENCY(kinds = {}) | ||
| 2838 | algorithm S := cref :: S; then (); | ||
| 2839 | case DEPENDENCY(kinds = kinds) algorithm | ||
| 2840 | ✗ | if List.any(kinds, isReductionKind) then | |
| 2841 | ✗ | if repeats then | |
| 2842 | F := cref :: F; | ||
| 2843 | else | ||
| 2844 | R := cref :: R; | ||
| 2845 | end if; | ||
| 2846 | else | ||
| 2847 | A := cref :: A; | ||
| 2848 | end if; | ||
| 2849 | then (); | ||
| 2850 | else (); | ||
| 2851 | end match; | ||
| 2852 | end for; | ||
| 2853 | end categorize; | ||
| 2854 | |||
| 2855 | function convert | ||
| 2856 | input Dependency dep; | ||
| 2857 | output OldSimCode.Dependency odep; | ||
| 2858 | protected | ||
| 2859 | function convertKind | ||
| 2860 | input Kind kind; | ||
| 2861 | output Boolean okind = kind == Kind.REDUCTION; | ||
| 2862 | end convertKind; | ||
| 2863 | algorithm | ||
| 2864 |
6/6✓ Branch 0 taken 237 times.
✓ Branch 1 taken 6121 times.
✓ Branch 2 taken 237 times.
✓ Branch 3 taken 6121 times.
✓ Branch 5 taken 224 times.
✓ Branch 6 taken 13 times.
|
6595 | odep := OldSimCode.DEPENDENCY(dep.skips, list(convertKind(kind) for kind in dep.kinds)); |
| 2865 | end convert; | ||
| 2866 | end Dependency; | ||
| 2867 | |||
| 2868 | uniontype Solvability | ||
| 2869 | record UNKNOWN end UNKNOWN; // do not set, only used as default if unset | ||
| 2870 | record UNSOLVABLE end UNSOLVABLE; | ||
| 2871 | record IMPLICIT end IMPLICIT; | ||
| 2872 | |||
| 2873 | record EXPLICIT_NONLINEAR | ||
| 2874 | Boolean unique "true if it has a unique solution when solved"; | ||
| 2875 | end EXPLICIT_NONLINEAR; | ||
| 2876 | |||
| 2877 | record EXPLICIT_LINEAR | ||
| 2878 | Option<UnorderedSet<ComponentRef>> pars "parameters we need to divide by to solve"; | ||
| 2879 | Option<UnorderedSet<ComponentRef>> vars "variables we need to divide by to solve"; | ||
| 2880 | end EXPLICIT_LINEAR; | ||
| 2881 | |||
| 2882 | function toString | ||
| 2883 | input Solvability sol; | ||
| 2884 | output String str; | ||
| 2885 | algorithm | ||
| 2886 | str := match sol | ||
| 2887 | case UNSOLVABLE() then "XX"; | ||
| 2888 | case IMPLICIT() then "II"; | ||
| 2889 | ✗ | case EXPLICIT_NONLINEAR() then "N" + (if sol.unique then "+" else "-"); | |
| 2890 | ✗ | case EXPLICIT_LINEAR() then "L" + (if isSome(sol.vars) then "V" elseif isSome(sol.pars) then "P" else "C"); | |
| 2891 | case UNKNOWN() then "||"; | ||
| 2892 | else algorithm | ||
| 2893 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unknown solvability kind."}); | |
| 2894 | ✗ | then fail(); | |
| 2895 | end match; | ||
| 2896 | end toString; | ||
| 2897 | |||
| 2898 | function rank | ||
| 2899 | input Solvability sol; | ||
| 2900 | output Integer r; | ||
| 2901 | algorithm | ||
| 2902 | r := match sol | ||
| 2903 | case UNSOLVABLE() then 7; | ||
| 2904 | case IMPLICIT() then 6; | ||
| 2905 | case EXPLICIT_NONLINEAR(unique = false) then 5; | ||
| 2906 | case EXPLICIT_NONLINEAR() then 4; | ||
| 2907 | case EXPLICIT_LINEAR(vars = SOME(_)) then 3; | ||
| 2908 | case EXPLICIT_LINEAR(pars = SOME(_)) then 2; | ||
| 2909 | case EXPLICIT_LINEAR() then 1; | ||
| 2910 | case UNKNOWN() then 0; | ||
| 2911 | else algorithm | ||
| 2912 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unknown solvability kind."}); | |
| 2913 | ✗ | then fail(); | |
| 2914 | end match; | ||
| 2915 | end rank; | ||
| 2916 | |||
| 2917 | function update | ||
| 2918 | "sets the solvability of a component reference if it is of | ||
| 2919 | higher rank than previously determined" | ||
| 2920 | input ComponentRef cref; | ||
| 2921 | input Solvability sol; | ||
| 2922 | input UnorderedMap<ComponentRef, Solvability> map; | ||
| 2923 | algorithm | ||
| 2924 |
2/2✓ Branch 4 taken 3095 times.
✓ Branch 5 taken 30235 times.
|
33330 | if rank(sol) > rank(Util.getOptionOrDefault(UnorderedMap.get(cref, map), UNKNOWN())) then |
| 2925 | 30235 | UnorderedMap.add(cref, sol, map); | |
| 2926 | end if; | ||
| 2927 | end update; | ||
| 2928 | |||
| 2929 | function updateList | ||
| 2930 | input list<ComponentRef> lst; | ||
| 2931 | input Solvability sol; | ||
| 2932 | input UnorderedMap<ComponentRef, Solvability> map; | ||
| 2933 | algorithm | ||
| 2934 |
2/2✓ Branch 0 taken 1425 times.
✓ Branch 1 taken 3861 times.
|
5286 | for cref in lst loop |
| 2935 | 1425 | Solvability.update(cref, sol, map); | |
| 2936 | end for; | ||
| 2937 | end updateList; | ||
| 2938 | |||
| 2939 | function categorize | ||
| 2940 | input list<ComponentRef> crefs; | ||
| 2941 | input UnorderedMap<ComponentRef, Solvability> map; | ||
| 2942 | output list<ComponentRef> XX = {}; | ||
| 2943 | output list<ComponentRef> II = {}; | ||
| 2944 | output list<ComponentRef> NM = {}; | ||
| 2945 | output list<ComponentRef> NP = {}; | ||
| 2946 | output list<ComponentRef> LV = {}; | ||
| 2947 | output list<ComponentRef> LP = {}; | ||
| 2948 | output list<ComponentRef> LC = {}; | ||
| 2949 | output list<ComponentRef> QQ = {}; | ||
| 2950 | algorithm | ||
| 2951 | ✗ | for cref in crefs loop | |
| 2952 | _ := match UnorderedMap.getSafe(cref, map, sourceInfo()) | ||
| 2953 | case UNSOLVABLE() algorithm XX := cref :: XX; then(); | ||
| 2954 | case IMPLICIT() algorithm II := cref :: II; then(); | ||
| 2955 | case EXPLICIT_NONLINEAR(unique = false) algorithm NM := cref :: NM; then(); | ||
| 2956 | case EXPLICIT_NONLINEAR() algorithm NP := cref :: NP; then(); | ||
| 2957 | case EXPLICIT_LINEAR(vars = SOME(_)) algorithm LV := cref :: LV; then(); | ||
| 2958 | case EXPLICIT_LINEAR(pars = SOME(_)) algorithm LP := cref :: LP; then(); | ||
| 2959 | case EXPLICIT_LINEAR() algorithm LC := cref :: LC; then(); | ||
| 2960 | else algorithm QQ := cref :: QQ; then(); | ||
| 2961 | end match; | ||
| 2962 | end for; | ||
| 2963 | end categorize; | ||
| 2964 | |||
| 2965 | function filter | ||
| 2966 | "filters the cref list for all relevant crefs (checked with the rel map) | ||
| 2967 | and with solvability ranking between (and including) min and max" | ||
| 2968 | input list<ComponentRef> all_occ; | ||
| 2969 | input UnorderedMap<ComponentRef, Solvability> map; | ||
| 2970 | input UnorderedMap<ComponentRef, Integer> rel "check for relevance"; | ||
| 2971 | input Integer min; | ||
| 2972 | input Integer max; | ||
| 2973 | output list<ComponentRef> occ = {}; | ||
| 2974 | protected | ||
| 2975 | Integer r; | ||
| 2976 | algorithm | ||
| 2977 |
2/2✓ Branch 0 taken 47556 times.
✓ Branch 1 taken 24188 times.
|
71744 | for cref in all_occ loop |
| 2978 |
2/2✓ Branch 1 taken 42287 times.
✓ Branch 2 taken 5269 times.
|
47556 | if UnorderedMap.contains(cref, rel) then |
| 2979 | 42287 | r := rank(UnorderedMap.getSafe(cref, map, sourceInfo())); | |
| 2980 |
2/2✓ Branch 0 taken 24243 times.
✓ Branch 1 taken 18044 times.
|
42287 | if r >= min and r <= max then |
| 2981 | occ := cref :: occ; | ||
| 2982 | end if; | ||
| 2983 | end if; | ||
| 2984 | end for; | ||
| 2985 | end filter; | ||
| 2986 | |||
| 2987 | function fromStrictness | ||
| 2988 | input MatrixStrictness st; | ||
| 2989 | output Solvability sol; | ||
| 2990 | algorithm | ||
| 2991 | sol := match st | ||
| 2992 | 120 | case MatrixStrictness.LINEAR then EXPLICIT_LINEAR(NONE(), SOME(UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual))); | |
| 2993 | case MatrixStrictness.MATCHING then IMPLICIT(); | ||
| 2994 | case MatrixStrictness.SORTING then UNSOLVABLE(); | ||
| 2995 | else UNKNOWN(); | ||
| 2996 | end match; | ||
| 2997 | end fromStrictness; | ||
| 2998 | |||
| 2999 | function isNonlinearOrImplicit | ||
| 3000 | input Solvability sol; | ||
| 3001 | output Boolean b; | ||
| 3002 | algorithm | ||
| 3003 | b := match sol | ||
| 3004 | case EXPLICIT_NONLINEAR() then true; | ||
| 3005 | case IMPLICIT() then true; | ||
| 3006 | else false; | ||
| 3007 | end match; | ||
| 3008 | end isNonlinearOrImplicit; | ||
| 3009 | end Solvability; | ||
| 3010 | |||
| 3011 | function collectDependenciesEquation | ||
| 3012 | "collects all relevant component references from an equation | ||
| 3013 | furthermore it collects additional data about dependency and solvability." | ||
| 3014 | input Equation eqn; | ||
| 3015 | input Partition.Kind kind; | ||
| 3016 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 3017 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 3018 | input UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 3019 | input UnorderedSet<ComponentRef> rep_set; | ||
| 3020 | output UnorderedSet<ComponentRef> occurrences; | ||
| 3021 | protected | ||
| 3022 | list<ComponentRef> inputs, outputs; | ||
| 3023 | algorithm | ||
| 3024 | occurrences := match eqn | ||
| 3025 | local | ||
| 3026 | UnorderedSet<ComponentRef> occ1, occ2; | ||
| 3027 | Equation body; | ||
| 3028 | Slice.filterCref filter; | ||
| 3029 | |||
| 3030 | case Equation.SCALAR_EQUATION() algorithm | ||
| 3031 | 12874 | occ1 := collectDependencies(eqn.lhs, 0, map, dep_map, sol_map, rep_set); | |
| 3032 | 12874 | occ2 := collectDependencies(eqn.rhs, 0, map, dep_map, sol_map, rep_set); | |
| 3033 | 12874 | then UnorderedSet.union(occ1, occ2); | |
| 3034 | |||
| 3035 | case Equation.ARRAY_EQUATION() algorithm | ||
| 3036 | 1035 | occ1 := collectDependencies(eqn.lhs, 0, map, dep_map, sol_map, rep_set); | |
| 3037 | 1035 | occ2 := collectDependencies(eqn.rhs, 0, map, dep_map, sol_map, rep_set); | |
| 3038 | 1035 | then UnorderedSet.union(occ1, occ2); | |
| 3039 | |||
| 3040 | case Equation.RECORD_EQUATION() algorithm | ||
| 3041 | 115 | occ1 := collectDependencies(eqn.lhs, 0, map, dep_map, sol_map, rep_set); | |
| 3042 | 115 | occ2 := collectDependencies(eqn.rhs, 0, map, dep_map, sol_map, rep_set); | |
| 3043 | 115 | then UnorderedSet.union(occ1, occ2); | |
| 3044 | |||
| 3045 | case Equation.ALGORITHM() algorithm | ||
| 3046 | // filter inputs for solvable (not occuring only in conditions) | ||
| 3047 | 397 | inputs := collectDependenciesAlgorithmInputs(eqn.alg.statements, eqn.alg.inputs); | |
| 3048 | // collect all crefs expanding potential records | ||
| 3049 |
4/4✓ Branch 0 taken 111 times.
✓ Branch 1 taken 397 times.
✓ Branch 2 taken 111 times.
✓ Branch 3 taken 397 times.
|
508 | inputs := List.flatten(list(collectDependenciesCref(c, 0, map, dep_map, sol_map) for c in inputs)); |
| 3050 |
4/4✓ Branch 0 taken 162 times.
✓ Branch 1 taken 397 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 397 times.
|
559 | outputs := List.flatten(list(collectDependenciesCref(c, 0, map, dep_map, sol_map) for c in eqn.alg.outputs)); |
| 3051 | // create dependencies for inputs and outputs | ||
| 3052 | 397 | Dependency.addListFull(inputs, 0, dep_map, rep_set); | |
| 3053 | 397 | Dependency.addListFull(outputs, 0, dep_map, rep_set); | |
| 3054 | // make inputs unsolvable and outputs solvable (maybe check if algorithm can be reversed) | ||
| 3055 | 397 | Solvability.updateList(inputs, Solvability.IMPLICIT(), sol_map); | |
| 3056 | 397 | Solvability.updateList(outputs, Solvability.EXPLICIT_LINEAR(NONE(), NONE()), sol_map); | |
| 3057 | 397 | then UnorderedSet.fromList(listAppend(inputs, outputs), ComponentRef.hash, ComponentRef.isEqual); | |
| 3058 | |||
| 3059 | case Equation.FOR_EQUATION(body = {body}) algorithm | ||
| 3060 | // gather solvables from body | ||
| 3061 | 1442 | occ1 := collectDependenciesEquation(body, kind, map, dep_map, sol_map, rep_set); | |
| 3062 | // gather unsolvables from iterator | ||
| 3063 | 1442 | occ2 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 3064 | 1442 | filter := function Slice.getDependentCref(map = map, pseudo = true); | |
| 3065 | 2884 | _ := Iterator.map(eqn.iter, function Slice.filterExp(filter = filter, acc = occ2), | |
| 3066 | SOME(function filter(acc = occ2)), Expression.mapShallow); | ||
| 3067 | // update unsolvables | ||
| 3068 | 1442 | Solvability.updateList(UnorderedSet.toList(occ2), Solvability.UNSOLVABLE(), sol_map); | |
| 3069 | 1442 | then UnorderedSet.union(occ1, occ2); | |
| 3070 | |||
| 3071 | case Equation.IF_EQUATION() | ||
| 3072 | 10 | then collectDependenciesIf(eqn.body, kind, map, dep_map, sol_map, rep_set); | |
| 3073 | |||
| 3074 | case Equation.WHEN_EQUATION() | ||
| 3075 | 75 | then collectDependenciesWhen(eqn.body, kind, map, dep_map, sol_map, rep_set); | |
| 3076 | |||
| 3077 | ✗ | else UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 3078 | end match; | ||
| 3079 | end collectDependenciesEquation; | ||
| 3080 | |||
| 3081 | function collectDependencies | ||
| 3082 | "collects all relevant component references from an expression | ||
| 3083 | furthermore it collects additional data about dependency and solvability." | ||
| 3084 | input Expression exp; | ||
| 3085 | input Integer depth; | ||
| 3086 | input UnorderedMap<ComponentRef, Integer> map "unknowns map to check for relevance"; | ||
| 3087 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 3088 | input UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 3089 | input UnorderedSet<ComponentRef> rep_set; | ||
| 3090 | output UnorderedSet<ComponentRef> set; | ||
| 3091 | algorithm | ||
| 3092 | set := match exp | ||
| 3093 | local | ||
| 3094 | Dependency dep; | ||
| 3095 | UnorderedSet<ComponentRef> set1, set2, diff; | ||
| 3096 | list<UnorderedSet<ComponentRef>> sets = {}; | ||
| 3097 | Expression call_exp; | ||
| 3098 | Call call; | ||
| 3099 | Boolean repeatLeft, repeatRight, reduce; | ||
| 3100 | Integer ind, new_depth; | ||
| 3101 | Boolean isTuple; | ||
| 3102 | |||
| 3103 | // add a cref dependency | ||
| 3104 | 38087 | case Expression.CREF() then UnorderedSet.fromList(collectDependenciesCref(exp.cref, depth, map, dep_map, sol_map), ComponentRef.hash, ComponentRef.isEqual); | |
| 3105 | |||
| 3106 | // add skips for arrays | ||
| 3107 | case Expression.ARRAY(literal = false) algorithm | ||
| 3108 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 146 times.
✓ Branch 2 taken 146 times.
✗ Branch 3 not taken.
|
632 | for i in 1:arrayLength(exp.elements) loop |
| 3109 | 340 | set1 := collectDependencies(exp.elements[i], depth + 1, map, dep_map, sol_map, rep_set); | |
| 3110 | 340 | Dependency.skipList(UnorderedSet.toList(set1), depth + 1, i, dep_map); | |
| 3111 | sets := set1 :: sets; | ||
| 3112 | end for; | ||
| 3113 | 146 | then UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual); | |
| 3114 | |||
| 3115 | // add skips for tuples | ||
| 3116 | case Expression.TUPLE() algorithm | ||
| 3117 | ind := 1; | ||
| 3118 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for elem in exp.elements loop |
| 3119 | 4 | set1 := collectDependencies(elem, depth + 1, map, dep_map, sol_map, rep_set); | |
| 3120 | 4 | Dependency.skipList(UnorderedSet.toList(set1), depth + 1, ind, dep_map); | |
| 3121 | sets := set1 :: sets; | ||
| 3122 | 4 | ind := ind + 1; | |
| 3123 | end for; | ||
| 3124 | 2 | set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual); | |
| 3125 | then set; | ||
| 3126 | |||
| 3127 | // reduce the dependency and remove skips for these | ||
| 3128 | case Expression.SUBSCRIPTED_EXP() algorithm | ||
| 3129 | 146 | set := collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set); | |
| 3130 | 146 | Dependency.updateList(UnorderedSet.toList(set), listLength(exp.subscripts), true, dep_map); | |
| 3131 | 146 | Dependency.removeSkipsList(UnorderedSet.toList(set), dep_map); | |
| 3132 | // collect dependencies from subscript expressions (e.g. arr[i] depends on i) | ||
| 3133 | // subscript variables are unsolvable (cannot determine i from arr[i] = c) | ||
| 3134 |
4/5✓ Branch 0 taken 137 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 146 times.
✓ Branch 4 taken 146 times.
|
292 | for sub in exp.subscripts loop |
| 3135 | set2 := match sub | ||
| 3136 | 137 | case Subscript.INDEX() then collectDependencies(sub.index, 0, map, dep_map, sol_map, rep_set); | |
| 3137 | 9 | case Subscript.SLICE() then collectDependencies(sub.slice, 0, map, dep_map, sol_map, rep_set); | |
| 3138 | ✗ | else UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 3139 | end match; | ||
| 3140 | 146 | Solvability.updateList(UnorderedSet.toList(set2), Solvability.UNSOLVABLE(), sol_map); | |
| 3141 | 146 | set := UnorderedSet.union(set, set2); | |
| 3142 | end for; | ||
| 3143 | then set; | ||
| 3144 | |||
| 3145 | // should not change anything | ||
| 3146 | ✗ | case Expression.TUPLE_ELEMENT() then collectDependencies(exp.tupleExp, depth, map, dep_map, sol_map, rep_set); | |
| 3147 | 57 | case Expression.RECORD_ELEMENT() then collectDependencies(exp.recordExp, depth, map, dep_map, sol_map, rep_set); | |
| 3148 | |||
| 3149 | case Expression.BINARY() algorithm | ||
| 3150 | 667 | set1 := collectDependencies(exp.exp1, depth, map, dep_map, sol_map, rep_set); | |
| 3151 | 667 | set2 := collectDependencies(exp.exp2, depth, map, dep_map, sol_map, rep_set); | |
| 3152 | // add repetitions if needed (.+, .*) | ||
| 3153 | 667 | (repeatLeft, repeatRight) := Operator.repetition(exp.operator); | |
| 3154 |
2/2✓ Branch 0 taken 164 times.
✓ Branch 1 taken 503 times.
|
667 | if repeatLeft then addRepetitions(set1, rep_set); end if; |
| 3155 |
2/2✓ Branch 0 taken 158 times.
✓ Branch 1 taken 509 times.
|
667 | if repeatRight then addRepetitions(set2, rep_set); end if; |
| 3156 | // add reductions if needed | ||
| 3157 | 667 | reduce := Operator.reduction(exp.operator); | |
| 3158 |
2/2✓ Branch 0 taken 207 times.
✓ Branch 1 taken 460 times.
|
667 | if reduce then |
| 3159 | 207 | Dependency.updateList(UnorderedSet.toList(set1), 1, true, dep_map); | |
| 3160 | 207 | Dependency.updateList(UnorderedSet.toList(set2), 1, false, dep_map); | |
| 3161 | // a scalar result has no elements to skip to, e.g. {1, 2} * {x, y} | ||
| 3162 |
2/2✓ Branch 2 taken 55 times.
✓ Branch 3 taken 152 times.
|
207 | if not Type.isArray(Expression.typeOf(exp)) then |
| 3163 | 55 | Dependency.removeSkipsList(UnorderedSet.toList(set1), dep_map); | |
| 3164 | 55 | Dependency.removeSkipsList(UnorderedSet.toList(set2), dep_map); | |
| 3165 | end if; | ||
| 3166 | end if; | ||
| 3167 | 667 | then UnorderedSet.union(set1, set2); | |
| 3168 | |||
| 3169 | // mostly equal to binary | ||
| 3170 | case Expression.MULTARY() algorithm | ||
| 3171 | // add repetitions if needed (.+, .*) | ||
| 3172 | 11878 | (repeatLeft, repeatRight) := Operator.repetition(exp.operator); | |
| 3173 | 11878 | repeatLeft := repeatLeft or repeatRight; | |
| 3174 | // traverse arguments | ||
| 3175 |
2/2✓ Branch 0 taken 21061 times.
✓ Branch 1 taken 11878 times.
|
32939 | for arg in exp.arguments loop |
| 3176 | 21061 | set1 := collectDependencies(arg, depth, map, dep_map, sol_map, rep_set); | |
| 3177 | // add repetitions if needed | ||
| 3178 | 21061 | addRepetitionsCond(set1, arg, repeatLeft, rep_set); | |
| 3179 | sets := set1 :: sets; | ||
| 3180 | end for; | ||
| 3181 | // traverse inverse arguments | ||
| 3182 |
2/2✓ Branch 0 taken 3754 times.
✓ Branch 1 taken 11878 times.
|
15632 | for arg in exp.inv_arguments loop |
| 3183 | 3754 | set2 := collectDependencies(arg, depth, map, dep_map, sol_map, rep_set); | |
| 3184 | // add repetitions if needed | ||
| 3185 | 3754 | addRepetitionsCond(set2, arg, repeatLeft, rep_set); | |
| 3186 | sets := set2 :: sets; | ||
| 3187 | end for; | ||
| 3188 | 11878 | set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual); | |
| 3189 | then set; | ||
| 3190 | |||
| 3191 | // cannot solve from lbinary | ||
| 3192 | case Expression.LBINARY() algorithm | ||
| 3193 | 158 | set1 := collectDependencies(exp.exp1, depth, map, dep_map, sol_map, rep_set); | |
| 3194 | 158 | set2 := collectDependencies(exp.exp2, depth, map, dep_map, sol_map, rep_set); | |
| 3195 | 158 | set := UnorderedSet.union(set1, set2); | |
| 3196 | 158 | Solvability.updateList(UnorderedSet.toList(set), Solvability.UNSOLVABLE(), sol_map); | |
| 3197 | then set; | ||
| 3198 | |||
| 3199 | // cannot solve from relation | ||
| 3200 | case Expression.RELATION() algorithm | ||
| 3201 | 434 | set1 := collectDependencies(exp.exp1, depth, map, dep_map, sol_map, rep_set); | |
| 3202 | 434 | set2 := collectDependencies(exp.exp2, depth, map, dep_map, sol_map, rep_set); | |
| 3203 | 434 | set := UnorderedSet.union(set1, set2); | |
| 3204 | 434 | Solvability.updateList(UnorderedSet.toList(set), Solvability.UNSOLVABLE(), sol_map); | |
| 3205 | then set; | ||
| 3206 | |||
| 3207 | // these don't really change anything, just pass on the argument | ||
| 3208 | 151 | case Expression.CAST() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set); | |
| 3209 | ✗ | case Expression.BOX() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set); | |
| 3210 | ✗ | case Expression.UNBOX() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set); | |
| 3211 | 622 | case Expression.UNARY() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set); | |
| 3212 | 137 | case Expression.LUNARY() then collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set); | |
| 3213 | ✗ | case Expression.MUTABLE() then collectDependencies(Mutable.access(exp.exp), depth, map, dep_map, sol_map, rep_set); | |
| 3214 | |||
| 3215 | // in the size() operator nothing is solvable | ||
| 3216 | case Expression.SIZE() algorithm | ||
| 3217 | ✗ | set := collectDependencies(exp.exp, depth, map, dep_map, sol_map, rep_set); | |
| 3218 | ✗ | if isSome(exp.dimIndex) then | |
| 3219 | ✗ | set2 := collectDependencies(Util.getOption(exp.dimIndex), depth, map, dep_map, sol_map, rep_set); | |
| 3220 | ✗ | set := UnorderedSet.union(set, set2); | |
| 3221 | end if; | ||
| 3222 | ✗ | Solvability.updateList(UnorderedSet.toList(set), Solvability.UNSOLVABLE(), sol_map); | |
| 3223 | then set; | ||
| 3224 | |||
| 3225 | // variables in conditions are unsolvable and variables not occuring in both branches are implicit | ||
| 3226 | case Expression.IF() algorithm | ||
| 3227 | 277 | set1 := collectDependencies(exp.trueBranch, depth, map, dep_map, sol_map, rep_set); | |
| 3228 | 277 | set2 := collectDependencies(exp.falseBranch, depth, map, dep_map, sol_map, rep_set); | |
| 3229 | // variables not occuring in both branches will be tagged implicit | ||
| 3230 | 277 | diff := UnorderedSet.sym_difference(set1, set2); | |
| 3231 | 277 | Solvability.updateList(UnorderedSet.toList(diff), Solvability.IMPLICIT(), sol_map); | |
| 3232 | // variables in conditions are unsolvable, their skips have to be removed and they can be repeated | ||
| 3233 | 277 | set := collectDependencies(exp.condition, depth, map, dep_map, sol_map, rep_set); | |
| 3234 | 277 | addRepetitions(set, rep_set); | |
| 3235 | 277 | updateConditionCrefs(UnorderedSet.toList(set), dep_map, sol_map); | |
| 3236 | 277 | then UnorderedSet.union_list({set, set1, set2}, ComponentRef.hash, ComponentRef.isEqual); | |
| 3237 | |||
| 3238 | // for array constructors replace all iterators (temporarily) | ||
| 3239 | case Expression.CALL(call = call as Call.TYPED_ARRAY_CONSTRUCTOR(exp = call_exp)) algorithm | ||
| 3240 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 34 times.
|
68 | for iter in call.iters loop |
| 3241 | 34 | call_exp := Expression.replaceIterator(call_exp, Util.tuple21(iter), Util.tuple22(iter)); | |
| 3242 | end for; | ||
| 3243 | // if these are not simplified before this step, they can only be solved implicitely | ||
| 3244 | 34 | set := collectDependencies(call_exp, depth, map, dep_map, sol_map, rep_set); | |
| 3245 | 34 | Solvability.updateList(UnorderedSet.toList(set), Solvability.IMPLICIT(), sol_map); | |
| 3246 | then set; | ||
| 3247 | |||
| 3248 | // for reductions set the dependency to full reduction | ||
| 3249 | case Expression.CALL(call = call as Call.TYPED_REDUCTION(exp = call_exp)) algorithm | ||
| 3250 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 25 times.
|
50 | for iter in call.iters loop |
| 3251 | 25 | call_exp := Expression.replaceIterator(call_exp, Util.tuple21(iter), Util.tuple22(iter)); | |
| 3252 | end for; | ||
| 3253 | 25 | set := collectDependencies(call_exp, depth, map, dep_map, sol_map, rep_set); | |
| 3254 | 25 | Dependency.updateList(UnorderedSet.toList(set), -1, false, dep_map); | |
| 3255 | then set; | ||
| 3256 | |||
| 3257 | // for functions set the dependency to full reduction (+ repetition) and solvability to implicit | ||
| 3258 | case Expression.CALL(call = call as Call.TYPED_CALL()) algorithm | ||
| 3259 | // add depth if return type is tuple | ||
| 3260 | 1939 | isTuple := Type.isTuple(call.ty); | |
| 3261 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1937 times.
|
1939 | new_depth := if isTuple then depth + 1 else depth; |
| 3262 |
2/2✓ Branch 0 taken 3714 times.
✓ Branch 1 taken 1939 times.
|
5653 | for arg in call.arguments loop |
| 3263 | 3714 | sets := collectDependencies(arg, new_depth, map, dep_map, sol_map, rep_set) :: sets; | |
| 3264 | end for; | ||
| 3265 | 1939 | set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual); | |
| 3266 | 1939 | Dependency.updateList(UnorderedSet.toList(set), -1, false, dep_map); | |
| 3267 | // discrete arguments cannot be iterated on and no argument can be solved from a | ||
| 3268 | // discrete result (e.g. integer(x)), so they are unsolvable | ||
| 3269 |
2/2✓ Branch 1 taken 2214 times.
✓ Branch 2 taken 1939 times.
|
4153 | for cref in UnorderedSet.toList(set) loop |
| 3270 |
4/4✓ Branch 2 taken 2166 times.
✓ Branch 3 taken 48 times.
✓ Branch 6 taken 55 times.
✓ Branch 7 taken 2111 times.
|
2269 | Solvability.update(cref, if not Type.isDiscrete(call.ty) and BVariable.checkCref(cref, function BVariable.isContinuous(staticAsContinuous = true), sourceInfo()) |
| 3271 | then Solvability.IMPLICIT() else Solvability.UNSOLVABLE(), sol_map); | ||
| 3272 | end for; | ||
| 3273 | 1939 | addRepetitions(set, rep_set); | |
| 3274 | // if the return type has to be skipped - add empty skip | ||
| 3275 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1937 times.
|
1939 | if isTuple then |
| 3276 | 2 | Dependency.skipList(UnorderedSet.toList(set), depth + 1, 0, dep_map); | |
| 3277 | end if; | ||
| 3278 | then set; | ||
| 3279 | |||
| 3280 | // for not inlined record constructors set the dependency to full reduction (+ repetition) and solvability to implicit | ||
| 3281 | case Expression.RECORD() algorithm | ||
| 3282 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
|
24 | for arg in exp.elements loop |
| 3283 | 16 | sets := collectDependencies(arg, depth, map, dep_map, sol_map, rep_set) :: sets; | |
| 3284 | end for; | ||
| 3285 | 8 | set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual); | |
| 3286 | 8 | Dependency.updateList(UnorderedSet.toList(set), -1, false, dep_map); | |
| 3287 | 8 | Solvability.updateList(UnorderedSet.toList(set), Solvability.IMPLICIT(), sol_map); | |
| 3288 | 8 | addRepetitions(set, rep_set); | |
| 3289 | then set; | ||
| 3290 | |||
| 3291 | // nothing is solvable from ranges | ||
| 3292 | case Expression.RANGE() algorithm | ||
| 3293 | 9 | sets := collectDependencies(exp.start, depth, map, dep_map, sol_map, rep_set) :: sets; | |
| 3294 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
9 | if isSome(exp.step) then |
| 3295 | ✗ | sets := collectDependencies(Util.getOption(exp.step), depth, map, dep_map, sol_map, rep_set) :: sets; | |
| 3296 | end if; | ||
| 3297 | 9 | sets := collectDependencies(exp.stop, depth, map, dep_map, sol_map, rep_set) :: sets; | |
| 3298 | 9 | set := UnorderedSet.union_list(sets, ComponentRef.hash, ComponentRef.isEqual); | |
| 3299 | 9 | Solvability.updateList(UnorderedSet.toList(set), Solvability.UNSOLVABLE(), sol_map); | |
| 3300 | then set; | ||
| 3301 | |||
| 3302 | 7243 | else UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 3303 | end match; | ||
| 3304 | end collectDependencies; | ||
| 3305 | |||
| 3306 | function collectDependenciesCref | ||
| 3307 | input ComponentRef cref; | ||
| 3308 | input Integer depth; | ||
| 3309 | input UnorderedMap<ComponentRef, Integer> map "unknowns map to check for relevance"; | ||
| 3310 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 3311 | input UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 3312 | output list<ComponentRef> crefs; | ||
| 3313 | protected | ||
| 3314 | Pointer<Variable> var; | ||
| 3315 | Integer sk = 1; | ||
| 3316 | list<Subscript> subs; | ||
| 3317 | list<ComponentRef> scalar_matches; | ||
| 3318 | Boolean hasSetSub = false; | ||
| 3319 | algorithm | ||
| 3320 |
2/2✓ Branch 1 taken 15916 times.
✓ Branch 2 taken 38807 times.
|
54723 | for s in ComponentRef.subscriptsAllFlat(cref) loop |
| 3321 | // WHOLE (":") and SLICE (e.g. "1:3") are ordinary, common range subscripts | ||
| 3322 | // that the exact-match check below already handles correctly -- only a | ||
| 3323 | // literal/array-valued INDEX subscript (e.g. the "{1, 2}" in i_s[{1, 2}]) | ||
| 3324 | // is the set-subscript case this function needs to special-case. | ||
| 3325 |
3/4✓ Branch 1 taken 405 times.
✓ Branch 2 taken 15511 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 405 times.
|
15916 | if not Subscript.isScalar(s) and not Subscript.isSliced(s) then |
| 3326 | hasSetSub := true; | ||
| 3327 | end if; | ||
| 3328 | end for; | ||
| 3329 | |||
| 3330 | // a cref with a set/array-valued subscript (e.g. i_s[{1, 2}], produced when a torn | ||
| 3331 | // slice's residual equation keeps its original vector-valued RHS subexpression -- | ||
| 3332 | // see NBTearing.scalarSlices) must not go through the ordinary exact-match check | ||
| 3333 | // below: "map" here can use stripped (subscript-ignoring) cref equality | ||
| 3334 | // (VariablePointers' non-scalarized mode), under which i_s[{1, 2}] can spuriously | ||
| 3335 | // "contain"-match some unrelated whole-array entry for the same base variable, | ||
| 3336 | // recording that wrong, un-scalarized cref as the dependency and silently breaking | ||
| 3337 | // the seed/column mapping in fullToSparsity downstream (whose seed set is matched by | ||
| 3338 | // strict, non-stripped equality). Resolve those via their individual scalar elements | ||
| 3339 | // instead, matched strictly against map. | ||
| 3340 |
3/4✓ Branch 0 taken 38807 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 29691 times.
✓ Branch 4 taken 9116 times.
|
38807 | if not hasSetSub and UnorderedMap.contains(cref, map) then |
| 3341 |
2/2✓ Branch 1 taken 27923 times.
✓ Branch 2 taken 1768 times.
|
29691 | if not UnorderedMap.contains(cref, dep_map) then |
| 3342 | 27923 | UnorderedMap.add(cref, Dependency.create(ComponentRef.getSubscriptedType(cref), depth), dep_map); | |
| 3343 | end if; | ||
| 3344 | 29691 | Solvability.update(cref, Solvability.EXPLICIT_LINEAR(NONE(), NONE()), sol_map); | |
| 3345 | crefs := {cref}; | ||
| 3346 | 29691 | return; | |
| 3347 | end if; | ||
| 3348 | |||
| 3349 | // a slice (e.g. i[1:2]) of variables whose elements are the unknowns is resolved via its elements as well | ||
| 3350 |
4/6✓ Branch 0 taken 9116 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 514 times.
✓ Branch 5 taken 8602 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 514 times.
|
9116 | if not hasSetSub and Type.isArray(ComponentRef.getSubscriptedType(cref)) and Type.sizeOf(ComponentRef.getSubscriptedType(cref)) <= 256 then |
| 3351 | hasSetSub := true; | ||
| 3352 | end if; | ||
| 3353 | |||
| 3354 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8602 times.
|
8602 | if hasSetSub then |
| 3355 |
4/6✓ Branch 2 taken 2686 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2686 times.
✓ Branch 5 taken 514 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 514 times.
|
3200 | scalar_matches := list(c for c guard(UnorderedMap.contains(c, map)) in ComponentRef.scalarize(cref, false)); |
| 3356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 514 times.
|
514 | if not listEmpty(scalar_matches) then |
| 3357 | ✗ | for c in scalar_matches loop | |
| 3358 | ✗ | if not UnorderedMap.contains(c, dep_map) then | |
| 3359 | ✗ | UnorderedMap.add(c, Dependency.create(ComponentRef.getSubscriptedType(c), depth), dep_map); | |
| 3360 | end if; | ||
| 3361 | ✗ | Solvability.update(c, Solvability.EXPLICIT_LINEAR(NONE(), NONE()), sol_map); | |
| 3362 | end for; | ||
| 3363 | crefs := scalar_matches; | ||
| 3364 | ✗ | return; | |
| 3365 | end if; | ||
| 3366 | end if; | ||
| 3367 | |||
| 3368 | 9116 | var := BVariable.getVarPointer(cref, sourceInfo()); | |
| 3369 |
2/2✓ Branch 1 taken 239 times.
✓ Branch 2 taken 8877 times.
|
9116 | if BVariable.isRecord(var) then |
| 3370 | 239 | subs := ComponentRef.subscriptsAllFlat(cref); | |
| 3371 | // get all Record children that are relevant for current context | ||
| 3372 |
4/4✓ Branch 1 taken 572 times.
✓ Branch 2 taken 239 times.
✓ Branch 3 taken 572 times.
✓ Branch 4 taken 239 times.
|
811 | crefs := list(BVariable.getVarName(child) for child in BVariable.getRecordChildren(var)); |
| 3373 |
6/6✓ Branch 1 taken 125 times.
✓ Branch 2 taken 447 times.
✓ Branch 3 taken 572 times.
✓ Branch 4 taken 239 times.
✓ Branch 5 taken 447 times.
✓ Branch 6 taken 239 times.
|
811 | crefs := list(child for child guard(UnorderedMap.contains(child, map)) in crefs); |
| 3374 | // add original subscripts | ||
| 3375 |
4/4✓ Branch 0 taken 447 times.
✓ Branch 1 taken 239 times.
✓ Branch 2 taken 447 times.
✓ Branch 3 taken 239 times.
|
686 | crefs := list(ComponentRef.mergeSubscripts(subs, child) for child in crefs); |
| 3376 | // collect dependencies | ||
| 3377 |
4/4✓ Branch 0 taken 447 times.
✓ Branch 1 taken 239 times.
✓ Branch 2 taken 447 times.
✓ Branch 3 taken 239 times.
|
686 | crefs := List.flatten(list(collectDependenciesCref(child, depth + 1, map, dep_map, sol_map) for child in crefs)); |
| 3378 |
2/2✓ Branch 0 taken 447 times.
✓ Branch 1 taken 239 times.
|
686 | for cref in crefs loop |
| 3379 | 447 | Dependency.skip(cref, depth + 1, sk, dep_map); | |
| 3380 | 447 | sk := sk + 1; | |
| 3381 | end for; | ||
| 3382 | else | ||
| 3383 | crefs := {}; | ||
| 3384 | end if; | ||
| 3385 | end collectDependenciesCref; | ||
| 3386 | |||
| 3387 | function addRepetitionsCond | ||
| 3388 | "adds component references from a set to the repetition set, | ||
| 3389 | only if the expression they appear in is of size 1" | ||
| 3390 | input UnorderedSet<ComponentRef> occ; | ||
| 3391 | input Expression exp; | ||
| 3392 | input Boolean isRep; | ||
| 3393 | input UnorderedSet<ComponentRef> rep_set; | ||
| 3394 | algorithm | ||
| 3395 |
4/4✓ Branch 0 taken 24563 times.
✓ Branch 1 taken 252 times.
✓ Branch 4 taken 106 times.
✓ Branch 5 taken 146 times.
|
24815 | if isRep and Type.sizeOf(Expression.typeOf(exp)) == 1 then |
| 3396 | 146 | addRepetitions(occ, rep_set); | |
| 3397 | end if; | ||
| 3398 | end addRepetitionsCond; | ||
| 3399 | |||
| 3400 | function addRepetitions | ||
| 3401 | "adds component references to the repetition set" | ||
| 3402 | input UnorderedSet<ComponentRef> occ; | ||
| 3403 | input UnorderedSet<ComponentRef> rep_set; | ||
| 3404 | algorithm | ||
| 3405 |
2/2✓ Branch 1 taken 2692 times.
✓ Branch 2 taken 2723 times.
|
5415 | for cref in UnorderedSet.toList(occ) loop |
| 3406 | 2692 | UnorderedSet.add(cref, rep_set); | |
| 3407 | end for; | ||
| 3408 | end addRepetitions; | ||
| 3409 | |||
| 3410 | function collectDependenciesIf | ||
| 3411 | "collects all relevant component references from an if equation body | ||
| 3412 | furthermore it collects additional data about dependency and solvability. | ||
| 3413 | variables in conditions and variables not contained in all branches are unsolvable" | ||
| 3414 | input IfEquationBody body; | ||
| 3415 | input Partition.Kind kind; | ||
| 3416 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 3417 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 3418 | input UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 3419 | input UnorderedSet<ComponentRef> rep_set; | ||
| 3420 | output UnorderedSet<ComponentRef> set; | ||
| 3421 | protected | ||
| 3422 | list<UnorderedSet<ComponentRef>> sets1 = {}; | ||
| 3423 | UnorderedSet<ComponentRef> set1, set2, diff; | ||
| 3424 | algorithm | ||
| 3425 | // variables in conditions are unsolvable, repeated and get their skips removed | ||
| 3426 | 20 | set := collectDependencies(body.condition, 0, map, dep_map, sol_map, rep_set); | |
| 3427 | 20 | addRepetitions(set, rep_set); | |
| 3428 | 20 | updateConditionCrefs(UnorderedSet.toList(set), dep_map, sol_map); | |
| 3429 | |||
| 3430 | // get variables from 'then' branch | ||
| 3431 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
|
40 | for eqn in body.then_eqns loop |
| 3432 | 20 | sets1 := collectDependenciesEquation(Pointer.access(eqn), kind, map, dep_map, sol_map, rep_set) :: sets1; | |
| 3433 | end for; | ||
| 3434 | |||
| 3435 | // if there is an 'else' branch, mark those not occuring in both as implicit (maybe it should be unsolvable?) | ||
| 3436 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 10 times.
|
20 | if isSome(body.else_if) then |
| 3437 | 10 | set1 := UnorderedSet.union_list(sets1, ComponentRef.hash, ComponentRef.isEqual); | |
| 3438 | 10 | set2 := collectDependenciesIf(Util.getOption(body.else_if), kind, map, dep_map, sol_map, rep_set); | |
| 3439 | 10 | diff := UnorderedSet.sym_difference(set1, set2); | |
| 3440 | 10 | Solvability.updateList(UnorderedSet.toList(diff), Solvability.IMPLICIT(), sol_map); | |
| 3441 | 10 | set := UnorderedSet.union_list({set, set1, set2}, ComponentRef.hash, ComponentRef.isEqual); | |
| 3442 | else | ||
| 3443 | 10 | set := UnorderedSet.union_list(set :: sets1, ComponentRef.hash, ComponentRef.isEqual); | |
| 3444 | end if; | ||
| 3445 | end collectDependenciesIf; | ||
| 3446 | |||
| 3447 | function collectDependenciesWhen | ||
| 3448 | "collects all relevant component references from a when equation body | ||
| 3449 | furthermore it collects additional data about dependency and solvability. | ||
| 3450 | variables assigned on the left hand side are solvable, | ||
| 3451 | variables from the right hand side (-lhs variables) are unsolvable" | ||
| 3452 | input WhenEquationBody body; | ||
| 3453 | input Partition.Kind kind; | ||
| 3454 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 3455 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 3456 | input UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 3457 | input UnorderedSet<ComponentRef> rep_set; | ||
| 3458 | output UnorderedSet<ComponentRef> set; | ||
| 3459 | protected | ||
| 3460 | UnorderedSet<ComponentRef> set1 "solvables"; | ||
| 3461 | UnorderedSet<ComponentRef> set2 "potentially unsolvables"; | ||
| 3462 | UnorderedSet<ComponentRef> diff "set2 / set1 unsolvables"; | ||
| 3463 | list<UnorderedSet<ComponentRef>> lst = {}, lst1, lst2; | ||
| 3464 | list<tuple<UnorderedSet<ComponentRef>, UnorderedSet<ComponentRef>>> tpl_lst = {}; | ||
| 3465 | algorithm | ||
| 3466 | // variables in conditions are unsolvable, reduced and get their skips removed | ||
| 3467 | 126 | set := collectDependencies(body.condition, 0, map, dep_map, sol_map, rep_set); | |
| 3468 | 126 | updateConditionCrefs(UnorderedSet.toList(set), dep_map, sol_map); | |
| 3469 | |||
| 3470 | // make condition repeat if the body is larger than 1 | ||
| 3471 |
6/6✓ Branch 0 taken 126 times.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 126 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 115 times.
|
252 | if sum(WhenStatement.size(stmt, true) for stmt in body.when_stmts) > 1 then |
| 3472 | 11 | addRepetitions(set, rep_set); | |
| 3473 | end if; | ||
| 3474 | |||
| 3475 | // collect all dependencies from the statments | ||
| 3476 |
2/2✓ Branch 0 taken 126 times.
✓ Branch 1 taken 126 times.
|
252 | for stmt in body.when_stmts loop |
| 3477 | 126 | tpl_lst := collectDependenciesStmt(stmt, map, dep_map, sol_map, rep_set) :: tpl_lst; | |
| 3478 | end for; | ||
| 3479 | |||
| 3480 | // create the two sets for solvables and potentially unsovables | ||
| 3481 | 126 | (lst1, lst2) := List.unzip(tpl_lst); | |
| 3482 | 126 | set1 := UnorderedSet.union_list(lst1, ComponentRef.hash, ComponentRef.isEqual); | |
| 3483 | 126 | set2 := UnorderedSet.union_list(lst2, ComponentRef.hash, ComponentRef.isEqual); | |
| 3484 | |||
| 3485 | // get the set difference to determine the unsolvables and tag them as such | ||
| 3486 | 126 | diff := UnorderedSet.difference(set2, set1); | |
| 3487 | 126 | Solvability.updateList(UnorderedSet.toList(diff), Solvability.UNSOLVABLE(), sol_map); | |
| 3488 | |||
| 3489 | // traverse else when if it exists | ||
| 3490 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 75 times.
|
126 | if isSome(body.else_when) then |
| 3491 | 51 | lst := collectDependenciesWhen(Util.getOption(body.else_when), kind, map, dep_map, sol_map, rep_set) :: lst; | |
| 3492 | end if; | ||
| 3493 | 126 | set := UnorderedSet.union_list(set :: set1 :: set2 :: lst, ComponentRef.hash, ComponentRef.isEqual); | |
| 3494 | end collectDependenciesWhen; | ||
| 3495 | |||
| 3496 | function collectDependenciesStmt | ||
| 3497 | "collects all relevant component references from a when statement | ||
| 3498 | furthermore it collects additional data about dependency and solvability. | ||
| 3499 | Returns a tuple of two sets, one containing the solvables and the other | ||
| 3500 | containing potentially unsolvables" | ||
| 3501 | input WhenStatement stmt; | ||
| 3502 | input UnorderedMap<ComponentRef, Integer> map "unordered map to check for relevance"; | ||
| 3503 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 3504 | input UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 3505 | input UnorderedSet<ComponentRef> rep_set; | ||
| 3506 | output tuple<UnorderedSet<ComponentRef>, UnorderedSet<ComponentRef>> set_tpl; | ||
| 3507 | protected | ||
| 3508 | UnorderedSet<ComponentRef> set1 "solvable"; | ||
| 3509 | UnorderedSet<ComponentRef> set2 "potentially unsolvable"; | ||
| 3510 | algorithm | ||
| 3511 | set_tpl := match stmt | ||
| 3512 | case WhenStatement.ASSIGN() algorithm | ||
| 3513 | 126 | set1 := collectDependencies(stmt.lhs, 0, map, dep_map, sol_map, rep_set); | |
| 3514 | 126 | set2 := collectDependencies(stmt.rhs, 0, map, dep_map, sol_map, rep_set); | |
| 3515 | 126 | then (set1, set2); | |
| 3516 | |||
| 3517 | case WhenStatement.REINIT() algorithm | ||
| 3518 | ✗ | set1 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 3519 | ✗ | set2 := collectDependencies(stmt.value, 0, map, dep_map, sol_map, rep_set); | |
| 3520 | ✗ | then (set1, set2); | |
| 3521 | |||
| 3522 | case WhenStatement.ASSERT() algorithm | ||
| 3523 | ✗ | set1 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 3524 | ✗ | set2 := collectDependencies(stmt.condition, 0, map, dep_map, sol_map, rep_set); | |
| 3525 | ✗ | updateConditionCrefs(UnorderedSet.toList(set2), dep_map, sol_map); | |
| 3526 | ✗ | then (set1, set2); | |
| 3527 | |||
| 3528 | else algorithm | ||
| 3529 | ✗ | set1 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 3530 | ✗ | set2 := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 3531 | ✗ | then (set1, set2); | |
| 3532 | end match; | ||
| 3533 | end collectDependenciesStmt; | ||
| 3534 | |||
| 3535 | function collectDependenciesAlgorithmInputs | ||
| 3536 | "collects dependencies from algorithm inputs. | ||
| 3537 | Only consider inputs that appear outside of when/if conditions" | ||
| 3538 | input list<Statement> stmts; | ||
| 3539 | input output list<ComponentRef> inputs; | ||
| 3540 | protected | ||
| 3541 | UnorderedSet<ComponentRef> candidates = UnorderedSet.fromList(inputs, ComponentRef.hash, ComponentRef.isEqual); | ||
| 3542 | UnorderedSet<ComponentRef> result = UnorderedSet.fromList(inputs, ComponentRef.hash, ComponentRef.isEqual); | ||
| 3543 | algorithm | ||
| 3544 |
2/2✓ Branch 0 taken 493 times.
✓ Branch 1 taken 397 times.
|
890 | for stmt in stmts loop |
| 3545 | 493 | collectDependenciesAlgorithmStatement(stmt, candidates, result); | |
| 3546 | end for; | ||
| 3547 | 397 | inputs := UnorderedSet.toList(result); | |
| 3548 | end collectDependenciesAlgorithmInputs; | ||
| 3549 | |||
| 3550 | function collectDependenciesAlgorithmStatement | ||
| 3551 | input Statement stmt; | ||
| 3552 | input UnorderedSet<ComponentRef> candidates; | ||
| 3553 | input UnorderedSet<ComponentRef> result; | ||
| 3554 | algorithm | ||
| 3555 | _ := match stmt | ||
| 3556 | |||
| 3557 | // actual occurence can only happen here | ||
| 3558 | case Statement.ASSIGNMENT() algorithm | ||
| 3559 | 183 | Slice.filterExp(stmt.lhs, function Equation.collectFromSet(check_set = candidates), result); | |
| 3560 | 183 | Slice.filterExp(stmt.rhs, function Equation.collectFromSet(check_set = candidates), result); | |
| 3561 | then (); | ||
| 3562 | |||
| 3563 | // map body | ||
| 3564 | case Statement.FOR() algorithm | ||
| 3565 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 26 times.
|
54 | for s in stmt.body loop |
| 3566 | 28 | collectDependenciesAlgorithmStatement(s, candidates, result); | |
| 3567 | end for; | ||
| 3568 | then (); | ||
| 3569 | |||
| 3570 | // map body | ||
| 3571 | case Statement.WHILE() algorithm | ||
| 3572 | ✗ | for s in stmt.body loop | |
| 3573 | ✗ | collectDependenciesAlgorithmStatement(s, candidates, result); | |
| 3574 | end for; | ||
| 3575 | then (); | ||
| 3576 | |||
| 3577 | // skip conditions but map body | ||
| 3578 | case Statement.IF() algorithm | ||
| 3579 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 35 times.
|
86 | for branch in stmt.branches loop |
| 3580 |
2/2✓ Branch 1 taken 75 times.
✓ Branch 2 taken 51 times.
|
126 | for s in Util.tuple22(branch) loop |
| 3581 | 75 | collectDependenciesAlgorithmStatement(s, candidates, result); | |
| 3582 | end for; | ||
| 3583 | end for; | ||
| 3584 | then (); | ||
| 3585 | |||
| 3586 | // skip conditions but map body | ||
| 3587 | case Statement.WHEN() algorithm | ||
| 3588 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
|
24 | for branch in stmt.branches loop |
| 3589 |
2/2✓ Branch 1 taken 16 times.
✓ Branch 2 taken 12 times.
|
28 | for s in Util.tuple22(branch) loop |
| 3590 | 16 | collectDependenciesAlgorithmStatement(s, candidates, result); | |
| 3591 | end for; | ||
| 3592 | end for; | ||
| 3593 | then (); | ||
| 3594 | |||
| 3595 | // all other cases do not produce an occurence | ||
| 3596 | else (); | ||
| 3597 | end match; | ||
| 3598 | end collectDependenciesAlgorithmStatement; | ||
| 3599 | |||
| 3600 | function updateConditionCrefs | ||
| 3601 | "variables in conditions are unsolvable, reduced and get their skips removed" | ||
| 3602 | input list<ComponentRef> crefs; | ||
| 3603 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 3604 | input UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 3605 | algorithm | ||
| 3606 | 423 | Dependency.removeSkipsList(crefs, dep_map); | |
| 3607 | 423 | Dependency.updateList(crefs, -1, false, dep_map); | |
| 3608 | 423 | Solvability.updateList(crefs, Solvability.UNSOLVABLE(), sol_map); | |
| 3609 | end updateConditionCrefs; | ||
| 3610 | |||
| 3611 | function addInitialStartOccurrences | ||
| 3612 | "in the initial system start value dependencies must be included. | ||
| 3613 | - x has a start value x.start which is unfixed | ||
| 3614 | - x is iteration variable in an algebraic loop | ||
| 3615 | - the equation for x.start has to be solved before x is used" | ||
| 3616 | input UnorderedSet<ComponentRef> occs; | ||
| 3617 | input UnorderedMap<ComponentRef, Dependency> dep_map; | ||
| 3618 | input UnorderedMap<ComponentRef, Solvability> sol_map; | ||
| 3619 | input UnorderedSet<ComponentRef> rep_set; | ||
| 3620 | input Partition.Kind kind; | ||
| 3621 | algorithm | ||
| 3622 | // only do something if its an initial partition | ||
| 3623 |
2/2✓ Branch 1 taken 9390 times.
✓ Branch 2 taken 5042 times.
|
14432 | if Partition.kindIsInitial(kind) then |
| 3624 |
2/2✓ Branch 2 taken 10120 times.
✓ Branch 3 taken 5042 times.
|
15162 | for cref in UnorderedSet.toList(occs) loop |
| 3625 | () := match BVariable.getVarStart(BVariable.getVarPointer(cref, sourceInfo())) | ||
| 3626 | local | ||
| 3627 | Pointer<Variable> start; | ||
| 3628 | ComponentRef start_cref; | ||
| 3629 | |||
| 3630 | // only save the x -> x.start dependency not the other way around | ||
| 3631 | case SOME(start) guard(BVariable.isStart(start)) algorithm | ||
| 3632 | 571 | start_cref := ComponentRef.copySubscripts(cref, BVariable.getVarName(start)); | |
| 3633 | // add the start cref dependency in the same way the original variable occured | ||
| 3634 | // but with UNSOLVABLE as it is only relevant for sorting and cannot be solved | ||
| 3635 | 571 | UnorderedSet.add(start_cref, occs); | |
| 3636 | 571 | UnorderedMap.add(start_cref, UnorderedMap.getSafe(cref, dep_map, sourceInfo()), dep_map); | |
| 3637 | 571 | UnorderedMap.add(start_cref, Solvability.UNSOLVABLE(), sol_map); | |
| 3638 |
2/2✓ Branch 1 taken 60 times.
✓ Branch 2 taken 511 times.
|
571 | if UnorderedSet.contains(cref, rep_set) then |
| 3639 | 60 | UnorderedSet.add(start_cref, rep_set); | |
| 3640 | end if; | ||
| 3641 | then (); | ||
| 3642 | else (); | ||
| 3643 | end match; | ||
| 3644 | end for; | ||
| 3645 | end if; | ||
| 3646 | end addInitialStartOccurrences; | ||
| 3647 | |||
| 3648 | annotation(__OpenModelica_Interface="nbackend"); | ||
| 3649 | end NBAdjacency; | ||
| 3650 |