OMCompiler/Compiler/NBackEnd/Util/NBResizable.mo
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of OpenModelica. | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), | ||
| 5 | * c/o Linköpings universitet, Department of Computer and Information Science, | ||
| 6 | * SE-58183 Linköping, Sweden. | ||
| 7 | * | ||
| 8 | * All rights reserved. | ||
| 9 | * | ||
| 10 | * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR | ||
| 11 | * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. | ||
| 12 | * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES | ||
| 13 | * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL | ||
| 14 | * VERSION 3, ACCORDING TO RECIPIENTS CHOICE. | ||
| 15 | * | ||
| 16 | * The OpenModelica software and the OSMC (Open Source Modelica Consortium) | ||
| 17 | * Public License (OSMC-PL) are obtained from OSMC, either from the above | ||
| 18 | * address, from the URLs: | ||
| 19 | * http://www.openmodelica.org or | ||
| 20 | * https://github.com/OpenModelica/ or | ||
| 21 | * http://www.ida.liu.se/projects/OpenModelica, | ||
| 22 | * and in the OpenModelica distribution. | ||
| 23 | * | ||
| 24 | * GNU AGPL version 3 is obtained from: | ||
| 25 | * https://www.gnu.org/licenses/licenses.html#GPL | ||
| 26 | * | ||
| 27 | * This program is distributed WITHOUT ANY WARRANTY; without | ||
| 28 | * even the implied warranty of MERCHANTABILITY or FITNESS | ||
| 29 | * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH | ||
| 30 | * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. | ||
| 31 | * | ||
| 32 | * See the full OSMC Public License conditions for more details. | ||
| 33 | * | ||
| 34 | */ | ||
| 35 | |||
| 36 | encapsulated uniontype NBResizable | ||
| 37 | " file: NBResizable.mo | ||
| 38 | package: NBResizable | ||
| 39 | description: This file contains util functions for resizable parameters. | ||
| 40 | " | ||
| 41 | |||
| 42 | protected | ||
| 43 | // frontend imports | ||
| 44 | import NFBackendExtension.{BackendInfo, VariableAttributes}; | ||
| 45 | import Binding = NFBinding; | ||
| 46 | import Call = NFCall; | ||
| 47 | import ComponentRef = NFComponentRef; | ||
| 48 | import Dimension = NFDimension; | ||
| 49 | import Expression = NFExpression; | ||
| 50 | import SimplifyExp = NFSimplifyExp; | ||
| 51 | import Subscript = NFSubscript; | ||
| 52 | import Type = NFType; | ||
| 53 | import Operator = NFOperator; | ||
| 54 | import Variable = NFVariable; | ||
| 55 | |||
| 56 | // backend imports | ||
| 57 | import NFInstNode.InstNode; | ||
| 58 | import NBEquation.{Equation, Iterator, EquationPointers, EquationAttributes, EquationKind}; | ||
| 59 | import NBVariable.{VarData, VariablePointers}; | ||
| 60 | import BVariable = NBVariable; | ||
| 61 | import Differentiate = NBDifferentiate; | ||
| 62 | import NBDifferentiate.DifferentiationArguments; | ||
| 63 | import Replacements = NBReplacements; | ||
| 64 | import Solve = NBSolve; | ||
| 65 | public | ||
| 66 | constant Boolean debug = false; // SET TO TRUE FOR DEBUGGING | ||
| 67 | type EvalOrder = enumeration(INDEPENDENT, FORWARD, BACKWARD, FAILED); | ||
| 68 | |||
| 69 | function resize | ||
| 70 | "this resizes the resizable parameters to the optimal value to get the smallest possible system" | ||
| 71 | input output EquationPointers equations; | ||
| 72 | input output VarData varData; | ||
| 73 | protected | ||
| 74 | UnorderedSet<ComponentRef> parameters, min_parameters; | ||
| 75 | UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 76 | // c2p: constraint to parameters map | ||
| 77 | // p2c: parameter to constraints map | ||
| 78 | // i: inequality constraints | ||
| 79 | // e: equality constraints | ||
| 80 | UnorderedMap<Expression, ParameterList> c2pi, c2pe; | ||
| 81 | UnorderedMap<ComponentRef, ConstraintList> p2ci, p2ce; | ||
| 82 | partial function applyFunc | ||
| 83 | input output Type ty; | ||
| 84 | end applyFunc; | ||
| 85 | applyFunc func; | ||
| 86 | algorithm | ||
| 87 | varData := match varData | ||
| 88 | // only do something if there are resizable variables | ||
| 89 | case VarData.VAR_DATA_SIM() guard(VariablePointers.size(varData.resizables) > 0) algorithm | ||
| 90 | // prepare sets and maps | ||
| 91 | 15 | parameters := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 92 | 15 | min_parameters := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 93 | 15 | optimal_values := UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | |
| 94 | 15 | c2pi := UnorderedMap.new<ParameterList>(Expression.hash, Expression.isEqual); | |
| 95 | 15 | c2pe := UnorderedMap.new<ParameterList>(Expression.hash, Expression.isEqual); | |
| 96 | |||
| 97 | // find the optimal values for iterators | ||
| 98 | 15 | EquationPointers.map(equations, function findOptimalResizableValues(parameters = parameters, min_parameters = min_parameters, optimal_values = optimal_values, c2pi = c2pi, c2pe = c2pe)); | |
| 99 | |||
| 100 | // initialize the optimal values for parameters with their min or max attribute (or 0 if none available) | ||
| 101 | 15 | parameters := UnorderedSet.selfMap(parameters, function setInitialValues(min_parameters = min_parameters, optimal_values = optimal_values)); | |
| 102 | |||
| 103 | if debug then | ||
| 104 | print(optimalValuesToString(optimal_values, StringUtil.headline_2("[debug] Initial Resizable Parameter Values:") + "\n")); | ||
| 105 | print(StringUtil.headline_2("[debug] Final Inequality Constraints:")); | ||
| 106 | if UnorderedMap.isEmpty(c2pi) then | ||
| 107 | print(" <No Constraints>\n\n"); | ||
| 108 | else | ||
| 109 | print(List.toStringCustom(UnorderedMap.keyList(c2pi), Expression.toString, "", " 0 >= ", "\n 0 >= ", "\n") + "\n"); | ||
| 110 | end if; | ||
| 111 | print(StringUtil.headline_2("[debug] Final Equality Constraints:")); | ||
| 112 | if UnorderedMap.isEmpty(c2pe) then | ||
| 113 | print(" <No Constraints>\n\n"); | ||
| 114 | else | ||
| 115 | print(List.toStringCustom(UnorderedMap.keyList(c2pe), Expression.toString, "", " 0 = ", "\n 0 = ", "\n") + "\n"); | ||
| 116 | end if; | ||
| 117 | end if; | ||
| 118 | |||
| 119 | // compute the optimal values by checking constraints | ||
| 120 | 15 | p2ci := invertConstraintParameterMap(c2pi, parameters); | |
| 121 | 15 | p2ce := invertConstraintParameterMap(c2pe, parameters); | |
| 122 | 15 | computeOptimalValues(optimal_values, c2pi, p2ci, c2pe, p2ce); | |
| 123 | |||
| 124 | // traverse the model and update all values depending on these resizable parameters | ||
| 125 | 15 | func := function Type.applyToDims(func = function updateDimension(optimal_values = optimal_values)); | |
| 126 | // update variables | ||
| 127 | 30 | varData.variables := VariablePointers.map(varData.variables, function Variable.applyToType(func = func)); | |
| 128 | 30 | varData.variables := VariablePointers.mapPtr(varData.variables, function BVariable.updateResizableParameter(optimal_values = optimal_values)); | |
| 129 | 30 | varData.variables := VariablePointers.mapPtr(varData.variables, function BVariable.mapExp(funcExp = function Expression.applyToType(func = func), mapFunc = Expression.map)); | |
| 130 | // update equations | ||
| 131 | 15 | EquationPointers.mapPtr(equations, function Equation.applyToType(func = func)); | |
| 132 | 15 | equations := EquationPointers.mapExp(equations, function Expression.applyToType(func = func)); | |
| 133 | 15 | EquationPointers.mapRes(equations, function BVariable.applyToType(func = func)); | |
| 134 | |||
| 135 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | if Flags.isSet(Flags.DUMP_RESIZABLE) or debug then |
| 136 | ✗ | print(optimalValuesToString(optimal_values)); | |
| 137 | end if; | ||
| 138 | then varData; | ||
| 139 | |||
| 140 | else algorithm | ||
| 141 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 178 times.
|
178 | if Flags.isSet(Flags.DUMP_RESIZABLE) or debug then |
| 142 | ✗ | print(StringUtil.headline_2("[dumpResizable] No resizable parameters were detected in the model.")); | |
| 143 | end if; | ||
| 144 | then varData; | ||
| 145 | end match; | ||
| 146 | end resize; | ||
| 147 | |||
| 148 | function detect | ||
| 149 | "this function detects if an equation is resizable" | ||
| 150 | input Equation eqn; | ||
| 151 | input ComponentRef cref_to_solve; | ||
| 152 | output UnorderedMap<ComponentRef, EvalOrder> order = UnorderedMap.new<EvalOrder>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 153 | protected | ||
| 154 | Pointer<Variable> var_ptr = BVariable.getVarPointer(cref_to_solve, sourceInfo()); | ||
| 155 | UnorderedSet<ComponentRef> var_occurences = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | ||
| 156 | UnorderedSet<ComponentRef> ite_occurences; | ||
| 157 | list<ComponentRef> occ_lst, iterators; | ||
| 158 | list<list<Subscript>> subs; | ||
| 159 | list<Subscript> subs_to_solve, local_subs; | ||
| 160 | Subscript sub_to_solve; | ||
| 161 | ComponentRef iter; | ||
| 162 | DifferentiationArguments args; | ||
| 163 | Option<Integer> opt_factor; | ||
| 164 | Integer factor; | ||
| 165 | Integer shift_value, v2; | ||
| 166 | EvalOrder eval; | ||
| 167 | Boolean stop; | ||
| 168 | algorithm | ||
| 169 | order := match eqn | ||
| 170 | case Equation.FOR_EQUATION() algorithm | ||
| 171 |
2/2✓ Branch 0 taken 589 times.
✓ Branch 1 taken 589 times.
|
1178 | for body in eqn.body loop |
| 172 | 589 | Equation.map(body, function collectVars(func = function BVariable.equalName(var_ptr2 = var_ptr), collector = var_occurences)); | |
| 173 | 589 | occ_lst := UnorderedSet.toList(var_occurences); | |
| 174 | 589 | (iterators, _) := Iterator.getFrames(Equation.getForIterator(eqn)); | |
| 175 |
2/2✓ Branch 0 taken 657 times.
✓ Branch 1 taken 589 times.
|
1246 | order := UnorderedMap.fromLists(iterators, list(EvalOrder.INDEPENDENT for i in iterators), ComponentRef.hash, ComponentRef.isEqual); |
| 176 |
2/2✓ Branch 1 taken 22 times.
✓ Branch 2 taken 567 times.
|
589 | if not List.hasOneElement(occ_lst) then |
| 177 |
4/4✓ Branch 0 taken 44 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 22 times.
|
66 | subs := list(ComponentRef.subscriptsAllWithWholeFlat(cref) for cref in occ_lst); |
| 178 | 22 | subs := List.transposeList(subs); | |
| 179 | 22 | subs_to_solve := ComponentRef.subscriptsAllWithWholeFlat(cref_to_solve); | |
| 180 | 22 | stop := false; | |
| 181 |
2/2✓ Branch 1 taken 27 times.
✓ Branch 2 taken 22 times.
|
49 | for dim in List.zip(subs, subs_to_solve) loop |
| 182 | 27 | (local_subs, sub_to_solve) := dim; | |
| 183 | 27 | ite_occurences := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 184 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 27 times.
|
81 | for sub in local_subs loop |
| 185 | 54 | Subscript.mapExp(sub, function collectVars(func = BVariable.isIterator, collector = ite_occurences)); | |
| 186 | end for; | ||
| 187 | 27 | iterators := UnorderedSet.toList(ite_occurences); | |
| 188 | () := match iterators | ||
| 189 | // literal subscripts in this dimension do not restrict the order | ||
| 190 | case {} then (); | ||
| 191 | |||
| 192 | case {iter} algorithm | ||
| 193 | 27 | eval := UnorderedMap.getSafe(iter, order, sourceInfo()); | |
| 194 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if eval < EvalOrder.FAILED then |
| 195 | 27 | args := DifferentiationArguments.simpleCref(iter); | |
| 196 | opt_factor := NONE(); | ||
| 197 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 27 times.
|
81 | for sub in local_subs loop |
| 198 | 54 | factor := getFactor(Subscript.toExp(sub), args, opt_factor); | |
| 199 | opt_factor := SOME(factor); | ||
| 200 | end for; | ||
| 201 | |||
| 202 | () := match opt_factor | ||
| 203 | case SOME(factor) guard(factor <> 0) algorithm | ||
| 204 | try | ||
| 205 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
|
27 | Expression.INTEGER(shift_value) := getShift(Subscript.toExp(sub_to_solve), iter); |
| 206 |
2/2✓ Branch 0 taken 54 times.
✓ Branch 1 taken 27 times.
|
81 | for sub in local_subs loop |
| 207 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
|
54 | Expression.INTEGER(v2) := getShift(Subscript.toExp(sub), iter); |
| 208 | eval := match eval | ||
| 209 | case EvalOrder.INDEPENDENT guard(shift_value == v2) then EvalOrder.INDEPENDENT; | ||
| 210 | case EvalOrder.INDEPENDENT guard(shift_value > v2) then EvalOrder.FORWARD; | ||
| 211 | case EvalOrder.INDEPENDENT guard(shift_value < v2) then EvalOrder.BACKWARD; | ||
| 212 | case EvalOrder.FORWARD guard(shift_value >= v2) then EvalOrder.FORWARD; | ||
| 213 | case EvalOrder.BACKWARD guard(shift_value <= v2) then EvalOrder.BACKWARD; | ||
| 214 | else EvalOrder.FAILED; | ||
| 215 | end match; | ||
| 216 | end for; | ||
| 217 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if eval == EvalOrder.FAILED then break; end if; |
| 218 | else | ||
| 219 | eval := EvalOrder.FAILED; | ||
| 220 | end try; | ||
| 221 | 27 | UnorderedMap.add(iter, eval, order); | |
| 222 | then (); | ||
| 223 | else (); | ||
| 224 | end match; | ||
| 225 | end if; | ||
| 226 | then (); | ||
| 227 | |||
| 228 | else algorithm | ||
| 229 | ✗ | for it in iterators loop | |
| 230 | ✗ | UnorderedMap.add(it, EvalOrder.FAILED, order); | |
| 231 | end for; | ||
| 232 | stop := true; | ||
| 233 | then (); | ||
| 234 | end match; | ||
| 235 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | if stop then break; end if; |
| 236 | end for; | ||
| 237 | end if; | ||
| 238 | end for; | ||
| 239 | 589 | then order; | |
| 240 | else algorithm | ||
| 241 | 540 | order := UnorderedMap.fromLists({ComponentRef.EMPTY()}, {EvalOrder.FAILED}, ComponentRef.hash, ComponentRef.isEqual); | |
| 242 | then order; | ||
| 243 | end match; | ||
| 244 | end detect; | ||
| 245 | |||
| 246 | function addDimensionParameters | ||
| 247 | "A dimension of a resizable array that is an expression of parameters (N-1, | ||
| 248 | nT+1) gets an Integer parameter $DIM_k with the expression as start value. | ||
| 249 | The init.xml refers to it by value reference like to a plain size parameter, | ||
| 250 | and the generated function updateStructuralParameters computes it from the | ||
| 251 | start values of the other parameters (possibly changed with -override) before | ||
| 252 | the runtime allocates the arrays." | ||
| 253 | input output VarData varData; | ||
| 254 | protected | ||
| 255 | list<Expression> dim_exps = {}; | ||
| 256 | list<Pointer<Variable>> dim_params = {}; | ||
| 257 | Pointer<Variable> var_ptr; | ||
| 258 | Variable var; | ||
| 259 | ComponentRef cref; | ||
| 260 | Integer idx = 1; | ||
| 261 | algorithm | ||
| 262 | varData := match varData | ||
| 263 | case VarData.VAR_DATA_SIM() algorithm | ||
| 264 | // all lists: e.g. the function alias variables of the initialization are not in variables | ||
| 265 |
6/6✓ Branch 7 taken 84 times.
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 84 times.
✓ Branch 10 taken 12 times.
✓ Branch 13 taken 439 times.
✓ Branch 14 taken 12 times.
|
535 | for v in List.flatten(list(VariablePointers.toList(l) for l in {varData.variables, varData.unknowns, |
| 266 | varData.knowns, varData.initials, varData.auxiliaries, varData.aliasVars, varData.nonTrivialAlias})) loop | ||
| 267 | // calculated size parameters (s.N = N) have no start value at runtime | ||
| 268 | 439 | Pointer.update(v, Variable.applyToType(Pointer.access(v), function Type.applyToDims(func = resolveSizeParameters))); | |
| 269 |
2/2✓ Branch 3 taken 294 times.
✓ Branch 4 taken 439 times.
|
733 | for dim in Type.arrayDims(Variable.typeOf(Pointer.access(v))) loop |
| 270 | dim_exps := match dim | ||
| 271 | case Dimension.RESIZABLE() guard isDimensionExpression(dim.exp) and not List.isMemberOnTrue(dim.exp, dim_exps, Expression.isEqual) | ||
| 272 | 9 | then dim.exp :: dim_exps; | |
| 273 | case Dimension.EXP() guard isDimensionExpression(dim.exp) and not List.isMemberOnTrue(dim.exp, dim_exps, Expression.isEqual) | ||
| 274 | ✗ | then dim.exp :: dim_exps; | |
| 275 | else dim_exps; | ||
| 276 | end match; | ||
| 277 | end for; | ||
| 278 | end for; | ||
| 279 |
2/2✓ Branch 1 taken 9 times.
✓ Branch 2 taken 12 times.
|
21 | for e in listReverse(dim_exps) loop |
| 280 | 9 | (var_ptr, cref) := BVariable.makeAuxVar("$DIM", idx, Type.INTEGER(), true); | |
| 281 | 9 | var := BVariable.setStartAttribute(Pointer.access(var_ptr), e, true); | |
| 282 | 9 | Pointer.update(var_ptr, var); | |
| 283 | dim_params := var_ptr :: dim_params; | ||
| 284 | 9 | idx := idx + 1; | |
| 285 | end for; | ||
| 286 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if not listEmpty(dim_params) then |
| 287 | 6 | dim_params := listReverse(dim_params); | |
| 288 | 6 | varData.variables := VariablePointers.addList(dim_params, varData.variables); | |
| 289 | 6 | varData.knowns := VariablePointers.addList(dim_params, varData.knowns); | |
| 290 | 6 | varData.resizables := VariablePointers.addList(dim_params, varData.resizables); | |
| 291 | end if; | ||
| 292 | then varData; | ||
| 293 | else varData; | ||
| 294 | end match; | ||
| 295 | end addDimensionParameters; | ||
| 296 | |||
| 297 | function resolveSizeParameters | ||
| 298 | "replaces Integer parameters with a non-literal binding in a resizable | ||
| 299 | dimension by their binding, e.g. s.N with binding N" | ||
| 300 | input output Dimension dim; | ||
| 301 | algorithm | ||
| 302 | dim := match dim | ||
| 303 | case Dimension.RESIZABLE() algorithm | ||
| 304 | 500 | dim.exp := Expression.map(dim.exp, resolveSizeParameter); | |
| 305 | then dim; | ||
| 306 | else dim; | ||
| 307 | end match; | ||
| 308 | end resolveSizeParameters; | ||
| 309 | |||
| 310 | function resolveSizeParameter | ||
| 311 | input output Expression exp; | ||
| 312 | protected | ||
| 313 | Pointer<Variable> var_ptr; | ||
| 314 | Variable var; | ||
| 315 | algorithm | ||
| 316 | exp := match exp | ||
| 317 | case Expression.CREF(ty = Type.INTEGER()) guard InstNode.isVar(ComponentRef.node(exp.cref)) algorithm | ||
| 318 | 506 | var_ptr := BVariable.getVarPointer(exp.cref, sourceInfo()); | |
| 319 | 506 | var := Pointer.access(var_ptr); | |
| 320 | then match Binding.getExpOpt(var.binding) | ||
| 321 | local | ||
| 322 | Expression b; | ||
| 323 | case SOME(b) guard BVariable.isParamOrConst(var_ptr) and not Expression.isLiteral(b) | ||
| 324 | 6 | then Expression.map(b, resolveSizeParameter); | |
| 325 | else exp; | ||
| 326 | end match; | ||
| 327 | else exp; | ||
| 328 | end match; | ||
| 329 | end resolveSizeParameter; | ||
| 330 | |||
| 331 | function isDimensionExpression | ||
| 332 | "true for a dimension that is neither a literal nor a plain parameter" | ||
| 333 | input Expression exp; | ||
| 334 | output Boolean b; | ||
| 335 | algorithm | ||
| 336 | b := match exp | ||
| 337 | case Expression.INTEGER() then false; | ||
| 338 | case Expression.CREF() then false; | ||
| 339 | 105 | else not Expression.isLiteral(exp); | |
| 340 | end match; | ||
| 341 | end isDimensionExpression; | ||
| 342 | |||
| 343 | function orderFailed | ||
| 344 | input EvalOrder eo; | ||
| 345 | output Boolean b = eo == EvalOrder.FAILED; | ||
| 346 | end orderFailed; | ||
| 347 | |||
| 348 | function orderString | ||
| 349 | input EvalOrder eo; | ||
| 350 | output String str; | ||
| 351 | algorithm | ||
| 352 | str := match eo | ||
| 353 | case EvalOrder.INDEPENDENT then "INDEPENDENT"; | ||
| 354 | case EvalOrder.FORWARD then "FORWARD"; | ||
| 355 | case EvalOrder.BACKWARD then "BACKWARD"; | ||
| 356 | else "FAILED"; | ||
| 357 | end match; | ||
| 358 | end orderString; | ||
| 359 | |||
| 360 | protected | ||
| 361 | type ParameterList = list<ComponentRef>; | ||
| 362 | type ConstraintList = list<Expression>; | ||
| 363 | type Occurences = UnorderedSet<Expression>; | ||
| 364 | constant tuple<ComponentRef, Expression> END_TPL = (ComponentRef.EMPTY(), Expression.END()); | ||
| 365 | |||
| 366 | function findOptimalResizableValues | ||
| 367 | input output Equation eqn; | ||
| 368 | input UnorderedSet<ComponentRef> parameters; | ||
| 369 | input UnorderedSet<ComponentRef> min_parameters; | ||
| 370 | input UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 371 | input UnorderedMap<Expression, ParameterList> c2pi; | ||
| 372 | input UnorderedMap<Expression, ParameterList> c2pe; | ||
| 373 | protected | ||
| 374 | UnorderedMap<ComponentRef, Expression> resizables, replacements; | ||
| 375 | UnorderedMap<ComponentRef, Occurences> occs; | ||
| 376 | UnorderedSet<ComponentRef> constrained_vars = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | ||
| 377 | Dimension lhs_dim, rhs_dim; | ||
| 378 | Expression const; | ||
| 379 | algorithm | ||
| 380 | if debug then | ||
| 381 | print("[debug] checking equation:\n" + Equation.toString(eqn) + "\n"); | ||
| 382 | end if; | ||
| 383 | |||
| 384 | () := match eqn | ||
| 385 | // Main Routine: collect iterators and resizable parameter constraints and target equations | ||
| 386 | case Equation.FOR_EQUATION() algorithm | ||
| 387 | 55 | resizables := getResizableIterators(eqn.iter); | |
| 388 | 55 | replacements := getVarReplacements(eqn.iter); | |
| 389 | |||
| 390 | // add all resizable iterators with empty occurence sets to intialize | ||
| 391 | 55 | occs := UnorderedMap.new<Occurences>(ComponentRef.hash, ComponentRef.isEqual); | |
| 392 |
2/2✓ Branch 1 taken 59 times.
✓ Branch 2 taken 55 times.
|
169 | for res in UnorderedMap.keyList(resizables) loop |
| 393 | 59 | UnorderedMap.add(res, UnorderedSet.new(Expression.hash, Expression.isEqual), occs); | |
| 394 | end for; | ||
| 395 | |||
| 396 | // fill the occurence sets traversing the body of the equation | ||
| 397 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 55 times.
|
110 | for body in eqn.body loop |
| 398 | 55 | Equation.map(body, function collectOccurences(occs = occs)); | |
| 399 | 55 | Equation.map(body, function collectVars(func = BVariable.isArray, collector = constrained_vars)); | |
| 400 | end for; | ||
| 401 | 55 | findOptimalValue(eqn, occs, resizables, parameters, min_parameters, optimal_values, c2pi); | |
| 402 | 55 | UnorderedSet.fold(constrained_vars, function addVariableConstraint(eqn = eqn, replacements = SOME(replacements)), c2pi); | |
| 403 | then (); | ||
| 404 | |||
| 405 | case Equation.ARRAY_EQUATION() algorithm | ||
| 406 | 10 | Equation.map(eqn, function collectVars(func = BVariable.isResizable, collector = constrained_vars)); | |
| 407 | 10 | UnorderedSet.fold(constrained_vars, function addVariableConstraint(eqn = eqn, replacements = NONE()), c2pi); | |
| 408 |
2/2✓ Branch 5 taken 11 times.
✓ Branch 6 taken 10 times.
|
21 | for tpl in List.zip(Type.arrayDims(Expression.typeOf(eqn.lhs)), Type.arrayDims(Expression.typeOf(eqn.rhs))) loop |
| 409 | 11 | (lhs_dim, rhs_dim) := tpl; | |
| 410 |
3/4✓ Branch 1 taken 9 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
|
11 | if Dimension.isResizable(lhs_dim) or Dimension.isResizable(rhs_dim) then |
| 411 | 6 | const := Expression.MULTARY({Dimension.sizeExp(lhs_dim)}, {Dimension.sizeExp(rhs_dim)}, Operator.makeAdd(Type.INTEGER())); | |
| 412 | try | ||
| 413 | 2 | addConstraint(const, NONE(), c2pe, Expression.isZero, "array dimension", "="); | |
| 414 | 2 | Expression.map(const, function collectResizables(collector = parameters)); | |
| 415 | else | ||
| 416 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed.\nViolation of implicit constraint `" + Dimension.toString(lhs_dim) + " = " + Dimension.toString(rhs_dim) | |
| 417 | + "` for LHS and RHS type dimensions in equation:\n" + Equation.toString(eqn)}); | ||
| 418 | ✗ | fail(); | |
| 419 | end try; | ||
| 420 | end if; | ||
| 421 | end for; | ||
| 422 | then (); | ||
| 423 | |||
| 424 | else algorithm | ||
| 425 | // create dummy replacements (no iterators to replace) | ||
| 426 | 43 | Equation.map(eqn, function collectVars(func = BVariable.isResizable, collector = constrained_vars)); | |
| 427 | // subs: [n] dim [m] --> m >= n --> implication on split? | ||
| 428 | // subs: [10] dim [m] --> m >= 10 also implication on split values | ||
| 429 | 43 | UnorderedSet.fold(constrained_vars, function addVariableConstraint(eqn = eqn, replacements = NONE()), c2pi); | |
| 430 | then (); | ||
| 431 | end match; | ||
| 432 | |||
| 433 | if debug then | ||
| 434 | print("\n"); | ||
| 435 | end if; | ||
| 436 | end findOptimalResizableValues; | ||
| 437 | |||
| 438 | function getResizableIterators | ||
| 439 | input Iterator iter; | ||
| 440 | output UnorderedMap<ComponentRef, Expression> resizables = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 441 | protected | ||
| 442 | list<ComponentRef> names; | ||
| 443 | list<Expression> ranges; | ||
| 444 | algorithm | ||
| 445 | 55 | (names, ranges) := Iterator.getFrames(iter); | |
| 446 |
2/2✓ Branch 1 taken 60 times.
✓ Branch 2 taken 55 times.
|
115 | for tpl in List.zip(names, ranges) loop |
| 447 |
2/2✓ Branch 2 taken 59 times.
✓ Branch 3 taken 1 time.
|
60 | if iteratorIsResizable(Util.tuple22(tpl)) then |
| 448 | 59 | UnorderedMap.add(Util.tuple21(tpl), Util.tuple22(tpl), resizables); | |
| 449 | end if; | ||
| 450 | end for; | ||
| 451 | end getResizableIterators; | ||
| 452 | |||
| 453 | function getVarReplacements | ||
| 454 | input Iterator iter; | ||
| 455 | output UnorderedMap<ComponentRef, Expression> replacements = UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 456 | protected | ||
| 457 | list<ComponentRef> names; | ||
| 458 | list<Expression> ranges; | ||
| 459 | ComponentRef name; | ||
| 460 | Expression range, max_call; | ||
| 461 | algorithm | ||
| 462 | 55 | (names, ranges) := Iterator.getFrames(iter); | |
| 463 |
2/2✓ Branch 1 taken 60 times.
✓ Branch 2 taken 55 times.
|
115 | for tpl in List.zip(names, ranges) loop |
| 464 | 60 | (name, range) := tpl; | |
| 465 | () := match range | ||
| 466 | case Expression.RANGE() algorithm | ||
| 467 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
60 | if isSome(range.step) and Expression.isNegative(Util.getOption(range.step)) then |
| 468 | ✗ | UnorderedMap.add(name, range.start, replacements); | |
| 469 | elseif isNone(range.step) or Expression.isPositive(Util.getOption(range.step)) then | ||
| 470 | 60 | UnorderedMap.add(name, range.stop, replacements); | |
| 471 | else | ||
| 472 | ✗ | max_call := Expression.CALL(Call.makeTypedCall( | |
| 473 | fn = NFBuiltinFuncs.MAX_INT, | ||
| 474 | args = {range.start, range.stop}, | ||
| 475 | variability = Expression.variability(range.start), | ||
| 476 | purity = NFPrefixes.Purity.PURE | ||
| 477 | )); | ||
| 478 | ✗ | UnorderedMap.add(name, max_call, replacements); | |
| 479 | end if; | ||
| 480 | then (); | ||
| 481 | else (); | ||
| 482 | end match; | ||
| 483 | end for; | ||
| 484 | end getVarReplacements; | ||
| 485 | |||
| 486 | public | ||
| 487 | function restrictIterator | ||
| 488 | "The iterator restricted to the box of iterations given by flat slice indices | ||
| 489 | at the analysis sizes (zero based, last frame fastest). Positions near the | ||
| 490 | start of a range are counted from its start, positions near its end from | ||
| 491 | its stop, so the restriction holds for every value of the resizable | ||
| 492 | parameters. NONE() if the indices are no box or a bound is ambiguous." | ||
| 493 | input Iterator iter; | ||
| 494 | input list<Integer> indices; | ||
| 495 | output Option<Iterator> res = NONE(); | ||
| 496 | protected | ||
| 497 | list<ComponentRef> names; | ||
| 498 | list<Expression> ranges, new_ranges = {}; | ||
| 499 | list<Option<Iterator>> maps; | ||
| 500 | array<Integer> sizes, lo, hi; | ||
| 501 | list<Integer> uniq; | ||
| 502 | Integer n, tmp, p, count = 1; | ||
| 503 | Option<Expression> range; | ||
| 504 | algorithm | ||
| 505 | 130 | (names, ranges, maps) := Iterator.getFrames(iter); | |
| 506 |
2/4✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 130 times.
|
130 | if listEmpty(indices) or List.any(maps, isSome) then |
| 507 | ✗ | return; | |
| 508 | end if; | ||
| 509 |
4/4✓ Branch 0 taken 171 times.
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 171 times.
✓ Branch 3 taken 130 times.
|
301 | sizes := listArray(list(Expression.rangeSize(r, true) for r in ranges)); |
| 510 | n := arrayLength(sizes); | ||
| 511 | 130 | lo := arrayCopy(sizes); | |
| 512 | 130 | hi := arrayCreate(n, -1); | |
| 513 | 130 | uniq := UnorderedSet.toList(UnorderedSet.fromList(indices, Util.id, intEq)); | |
| 514 |
2/2✓ Branch 0 taken 460 times.
✓ Branch 1 taken 98 times.
|
558 | for idx in uniq loop |
| 515 | 460 | tmp := idx; | |
| 516 |
1/2✓ Branch 0 taken 460 times.
✗ Branch 1 not taken.
|
1205 | for d in n:-1:1 loop |
| 517 |
1/2✓ Branch 1 taken 745 times.
✗ Branch 2 not taken.
|
745 | p := mod(tmp, sizes[d]); |
| 518 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 745 times.
|
745 | tmp := intDiv(tmp, sizes[d]); |
| 519 | 745 | lo[d] := intMin(lo[d], p); | |
| 520 | 745 | hi[d] := intMax(hi[d], p); | |
| 521 | end for; | ||
| 522 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 428 times.
|
460 | if tmp <> 0 then |
| 523 | 32 | return; | |
| 524 | end if; | ||
| 525 | end for; | ||
| 526 |
1/2✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
|
98 | for d in 1:n loop |
| 527 | 139 | count := count * (hi[d] - lo[d] + 1); | |
| 528 | end for; | ||
| 529 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
|
98 | if count <> listLength(uniq) then |
| 530 | ✗ | return; | |
| 531 | end if; | ||
| 532 |
1/2✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
|
237 | for d in 1:n loop |
| 533 | 139 | range := restrictedRange(listGet(ranges, d), lo[d], hi[d], sizes[d]); | |
| 534 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
|
139 | if isNone(range) then |
| 535 | ✗ | return; | |
| 536 | end if; | ||
| 537 | 139 | new_ranges := Util.getOption(range) :: new_ranges; | |
| 538 | end for; | ||
| 539 | 98 | res := SOME(Iterator.fromFrames(List.zip3(names, listReverse(new_ranges), maps))); | |
| 540 | end restrictIterator; | ||
| 541 | |||
| 542 | function boxes | ||
| 543 | "splits flat indices (zero based, last dimension fastest) of an array with | ||
| 544 | the given sizes into boxes, ordered by their first index" | ||
| 545 | input list<Integer> indices; | ||
| 546 | input list<Integer> sizes; | ||
| 547 | output list<list<Integer>> parts = {}; | ||
| 548 | protected | ||
| 549 | list<list<Integer>> locs; | ||
| 550 | algorithm | ||
| 551 | ✗ | locs := list(indexLocation(i, sizes) for i in List.sort(UnorderedSet.toList(UnorderedSet.fromList(indices, Util.id, intEq)), intGt)); | |
| 552 | ✗ | for spec in boxSpecs(locs) loop | |
| 553 | ✗ | parts := boxIndices(spec, sizes) :: parts; | |
| 554 | end for; | ||
| 555 | ✗ | parts := List.sort(parts, function boxGreater()); | |
| 556 | end boxes; | ||
| 557 | |||
| 558 | function boxGreater | ||
| 559 | input list<Integer> a; | ||
| 560 | input list<Integer> b; | ||
| 561 | output Boolean res = listHead(a) > listHead(b); | ||
| 562 | end boxGreater; | ||
| 563 | |||
| 564 | function indexLocation | ||
| 565 | "zero based location of a flat index, last dimension fastest" | ||
| 566 | input Integer index; | ||
| 567 | input list<Integer> sizes; | ||
| 568 | output list<Integer> loc = {}; | ||
| 569 | protected | ||
| 570 | Integer tmp = index; | ||
| 571 | algorithm | ||
| 572 | ✗ | for s in listReverse(sizes) loop | |
| 573 | ✗ | loc := mod(tmp, s) :: loc; | |
| 574 | ✗ | tmp := intDiv(tmp, s); | |
| 575 | end for; | ||
| 576 | end indexLocation; | ||
| 577 | |||
| 578 | function boxSpecs | ||
| 579 | "the locations as boxes of (first, last) per dimension: groups of the first | ||
| 580 | coordinate with equal boxes of the others are merged" | ||
| 581 | input list<list<Integer>> locs; | ||
| 582 | output list<list<tuple<Integer, Integer>>> specs = {}; | ||
| 583 | protected | ||
| 584 | type Locations = list<list<Integer>>; | ||
| 585 | UnorderedMap<Integer, Locations> groups = UnorderedMap.new<Locations>(Util.id, intEq); | ||
| 586 | list<Integer> values; | ||
| 587 | list<list<tuple<Integer, Integer>>> sub, prev_sub = {}; | ||
| 588 | Integer lo = -1, hi = -1; | ||
| 589 | String key, prev_key = "#none"; | ||
| 590 | algorithm | ||
| 591 | ✗ | if listEmpty(locs) then | |
| 592 | ✗ | return; | |
| 593 | elseif listEmpty(listHead(locs)) then | ||
| 594 | specs := {{}}; | ||
| 595 | ✗ | return; | |
| 596 | end if; | ||
| 597 | ✗ | for loc in locs loop | |
| 598 | ✗ | UnorderedMap.add(listHead(loc), listRest(loc) :: UnorderedMap.getOrDefault(listHead(loc), groups, {}), groups); | |
| 599 | end for; | ||
| 600 | ✗ | values := List.sort(UnorderedMap.keyList(groups), intGt); | |
| 601 | ✗ | for v in values loop | |
| 602 | ✗ | sub := boxSpecs(listReverse(UnorderedMap.getOrFail(v, groups))); | |
| 603 | ✗ | key := specString(sub); | |
| 604 | ✗ | if v == hi + 1 and key == prev_key then | |
| 605 | hi := v; | ||
| 606 | else | ||
| 607 | ✗ | specs := addSpecs(lo, hi, prev_sub, specs); | |
| 608 | ✗ | (lo, hi, prev_sub, prev_key) := (v, v, sub, key); | |
| 609 | end if; | ||
| 610 | end for; | ||
| 611 | ✗ | specs := listReverse(addSpecs(lo, hi, prev_sub, specs)); | |
| 612 | end boxSpecs; | ||
| 613 | |||
| 614 | function addSpecs | ||
| 615 | input Integer lo; | ||
| 616 | input Integer hi; | ||
| 617 | input list<list<tuple<Integer, Integer>>> sub; | ||
| 618 | input output list<list<tuple<Integer, Integer>>> specs; | ||
| 619 | algorithm | ||
| 620 | ✗ | if lo >= 0 then | |
| 621 | ✗ | for s in sub loop | |
| 622 | ✗ | specs := ((lo, hi) :: s) :: specs; | |
| 623 | end for; | ||
| 624 | end if; | ||
| 625 | end addSpecs; | ||
| 626 | |||
| 627 | function specString | ||
| 628 | input list<list<tuple<Integer, Integer>>> specs; | ||
| 629 | output String str = stringDelimitList(list(stringDelimitList(list(intString(Util.tuple21(t)) + ":" + intString(Util.tuple22(t)) for t in s), ",") for s in specs), ";"); | ||
| 630 | end specString; | ||
| 631 | |||
| 632 | function boxIndices | ||
| 633 | "the flat indices of a box" | ||
| 634 | input list<tuple<Integer, Integer>> spec; | ||
| 635 | input list<Integer> sizes; | ||
| 636 | output list<Integer> indices = {0}; | ||
| 637 | protected | ||
| 638 | Integer lo, hi; | ||
| 639 | algorithm | ||
| 640 | ✗ | for tpl in List.zip(spec, sizes) loop | |
| 641 | ✗ | ((lo, hi), _) := tpl; | |
| 642 | ✗ | indices := List.flatten(list(list(i * Util.tuple22(tpl) + p for p in lo:hi) for i in indices)); | |
| 643 | end for; | ||
| 644 | end boxIndices; | ||
| 645 | |||
| 646 | function restrictedRange | ||
| 647 | "the positions lo..hi (zero based) of a range with n elements at the analysis sizes" | ||
| 648 | input Expression range; | ||
| 649 | input Integer lo; | ||
| 650 | input Integer hi; | ||
| 651 | input Integer n; | ||
| 652 | output Option<Expression> res = NONE(); | ||
| 653 | protected | ||
| 654 | Option<Expression> start, stop; | ||
| 655 | Expression size_exp; | ||
| 656 | Dimension dim; | ||
| 657 | algorithm | ||
| 658 | () := match range | ||
| 659 | case Expression.RANGE() guard isNone(range.step) or Expression.isOne(Util.getOption(range.step)) algorithm | ||
| 660 |
4/4✓ Branch 0 taken 103 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 46 times.
|
139 | if lo == 0 and hi == n - 1 then |
| 661 | res := SOME(range); | ||
| 662 | 57 | return; | |
| 663 | end if; | ||
| 664 | 82 | start := rangeBound(lo, n, range.start, range.stop); | |
| 665 | 82 | stop := rangeBound(hi, n, range.start, range.stop); | |
| 666 |
4/12✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 82 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 82 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 82 times.
|
82 | if isNone(start) or isNone(stop) then |
| 667 | ✗ | return; | |
| 668 | end if; | ||
| 669 | 246 | size_exp := SimplifyExp.simplify(Expression.MULTARY({Util.getOption(stop), Expression.INTEGER(1)}, {Util.getOption(start)}, Operator.makeAdd(Type.INTEGER()))); | |
| 670 | dim := match Type.nthDimension(range.ty, 1) | ||
| 671 | 82 | case dim as Dimension.RESIZABLE() then Dimension.RESIZABLE(dim.size - (n - (hi - lo + 1)), SOME(hi - lo + 1), size_exp, dim.var); | |
| 672 | ✗ | else Dimension.fromInteger(hi - lo + 1); | |
| 673 | end match; | ||
| 674 | 82 | res := SOME(Expression.RANGE(Type.ARRAY(Type.INTEGER(), {dim}), Util.getOption(start), NONE(), Util.getOption(stop))); | |
| 675 | then (); | ||
| 676 | else (); | ||
| 677 | end match; | ||
| 678 | end restrictedRange; | ||
| 679 | |||
| 680 | function rangeBound | ||
| 681 | "position p (zero based) of a range with n elements, counted from the nearer end" | ||
| 682 | input Integer p; | ||
| 683 | input Integer n; | ||
| 684 | input Expression start; | ||
| 685 | input Expression stop; | ||
| 686 | output Option<Expression> bound; | ||
| 687 | algorithm | ||
| 688 |
2/4✓ Branch 1 taken 164 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 164 times.
|
164 | if Expression.isInteger(start) and Expression.isInteger(stop) then |
| 689 | ✗ | bound := SOME(Expression.INTEGER(Expression.integerValue(start) + p)); | |
| 690 | elseif p < n - 1 - p then | ||
| 691 | 164 | bound := SOME(SimplifyExp.simplify(Expression.MULTARY({start, Expression.INTEGER(p)}, {}, Operator.makeAdd(Type.INTEGER())))); | |
| 692 | elseif p > n - 1 - p then | ||
| 693 | 164 | bound := SOME(SimplifyExp.simplify(Expression.MULTARY({stop}, {Expression.INTEGER(n - 1 - p)}, Operator.makeAdd(Type.INTEGER())))); | |
| 694 | else | ||
| 695 | bound := NONE(); | ||
| 696 | end if; | ||
| 697 | end rangeBound; | ||
| 698 | |||
| 699 | protected | ||
| 700 | |||
| 701 | function iteratorIsResizable | ||
| 702 | input Expression range; | ||
| 703 | output Boolean b = Expression.fold(range, expContainsResizable, false); | ||
| 704 | end iteratorIsResizable; | ||
| 705 | |||
| 706 | function expContainsResizable | ||
| 707 | "needs to be mapped with Expression.fold()" | ||
| 708 | input Expression exp; | ||
| 709 | input output Boolean b; | ||
| 710 | algorithm | ||
| 711 |
2/2✓ Branch 0 taken 147 times.
✓ Branch 1 taken 85 times.
|
232 | if not b then |
| 712 | b := match exp | ||
| 713 | 59 | case Expression.CREF() then BVariable.checkCref(exp.cref, BVariable.isResizableParameter, sourceInfo()); | |
| 714 | else false; | ||
| 715 | end match; | ||
| 716 | end if; | ||
| 717 | end expContainsResizable; | ||
| 718 | |||
| 719 | function collectResizables | ||
| 720 | "needs to be mapped with Expression.map()" | ||
| 721 | input output Expression exp; | ||
| 722 | input UnorderedSet<ComponentRef> collector; | ||
| 723 | algorithm | ||
| 724 | () := match exp | ||
| 725 | case Expression.CREF() guard(BVariable.checkCref(exp.cref, BVariable.isResizableParameter, sourceInfo())) algorithm | ||
| 726 | 694 | UnorderedSet.add(exp.cref, collector); | |
| 727 | then (); | ||
| 728 | else (); | ||
| 729 | end match; | ||
| 730 | end collectResizables; | ||
| 731 | |||
| 732 | function collectOccurences | ||
| 733 | input output Expression exp; | ||
| 734 | input UnorderedMap<ComponentRef, Occurences> occs; | ||
| 735 | algorithm | ||
| 736 | () := match exp | ||
| 737 | case Expression.CREF() algorithm | ||
| 738 | 282 | ComponentRef.mapSubscripts(exp.cref, function collectOccurencesSubscript(occs = occs)); | |
| 739 | then (); | ||
| 740 | else (); | ||
| 741 | end match; | ||
| 742 | end collectOccurences; | ||
| 743 | |||
| 744 | function collectOccurencesSubscript | ||
| 745 | input output Subscript sub; | ||
| 746 | input UnorderedMap<ComponentRef, Occurences> occs; | ||
| 747 | protected | ||
| 748 | UnorderedSet<ComponentRef> acc = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | ||
| 749 | Expression subExp; | ||
| 750 | algorithm | ||
| 751 | 72 | Subscript.mapExp(sub, function collectOccurencesSubscriptExp(occs = occs, acc = acc)); | |
| 752 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 65 times.
|
72 | if not UnorderedSet.isEmpty(acc) then |
| 753 | 65 | subExp := Subscript.toExp(sub); | |
| 754 | 65 | acc := UnorderedSet.selfMap(acc, function addOccurence(subExp = subExp, occs = occs)); | |
| 755 | end if; | ||
| 756 | end collectOccurencesSubscript; | ||
| 757 | |||
| 758 | function collectOccurencesSubscriptExp | ||
| 759 | input output Expression exp; | ||
| 760 | input UnorderedMap<ComponentRef, Occurences> occs; | ||
| 761 | input UnorderedSet<ComponentRef> acc; | ||
| 762 | algorithm | ||
| 763 | () := match exp | ||
| 764 | case Expression.CREF() guard(UnorderedMap.contains(exp.cref, occs)) algorithm | ||
| 765 | 65 | UnorderedSet.add(exp.cref, acc); | |
| 766 | then (); | ||
| 767 | else (); | ||
| 768 | end match; | ||
| 769 | end collectOccurencesSubscriptExp; | ||
| 770 | |||
| 771 | function addOccurence | ||
| 772 | input output ComponentRef iter; | ||
| 773 | input Expression subExp; | ||
| 774 | input UnorderedMap<ComponentRef, Occurences> occs; | ||
| 775 | protected | ||
| 776 | UnorderedSet<Expression> local_occ = UnorderedMap.getSafe(iter, occs, sourceInfo()); | ||
| 777 | algorithm | ||
| 778 | 65 | UnorderedSet.add(subExp, local_occ); | |
| 779 | end addOccurence; | ||
| 780 | |||
| 781 | function collectVars | ||
| 782 | input output Expression exp; | ||
| 783 | input BVariable.checkVar func; | ||
| 784 | input UnorderedSet<ComponentRef> collector; | ||
| 785 | algorithm | ||
| 786 | () := match exp | ||
| 787 | case Expression.CREF() guard(func(BVariable.getVarPointer(exp.cref, sourceInfo()))) algorithm | ||
| 788 | 853 | UnorderedSet.add(exp.cref, collector); | |
| 789 | then (); | ||
| 790 | else(); | ||
| 791 | end match; | ||
| 792 | end collectVars; | ||
| 793 | |||
| 794 | function findOptimalValue | ||
| 795 | input Equation eqn; | ||
| 796 | input UnorderedMap<ComponentRef, Occurences> occs; | ||
| 797 | input UnorderedMap<ComponentRef, Expression> resizables; | ||
| 798 | input UnorderedSet<ComponentRef> parameters; | ||
| 799 | input UnorderedSet<ComponentRef> min_parameters; | ||
| 800 | input UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 801 | input UnorderedMap<Expression, ParameterList> c2pi; | ||
| 802 | protected | ||
| 803 | Expression range, target; | ||
| 804 | UnorderedSet<ComponentRef> local_parameters; | ||
| 805 | DifferentiationArguments args; | ||
| 806 | algorithm | ||
| 807 |
2/2✓ Branch 1 taken 59 times.
✓ Branch 2 taken 55 times.
|
114 | for cref in UnorderedMap.keyList(occs) loop |
| 808 | 59 | range := UnorderedMap.getSafe(cref, resizables, sourceInfo()); | |
| 809 | 59 | Expression.map(range, function collectResizables(collector = parameters)); | |
| 810 | () := match range | ||
| 811 | case Expression.RANGE() algorithm | ||
| 812 | // optimization target function (minimum) | ||
| 813 | // min! f(x) = stop - start | ||
| 814 | 59 | target := Expression.MULTARY({range.stop}, {range.start}, Operator.makeAdd(Type.INTEGER())); | |
| 815 | 59 | target := SimplifyExp.simplify(target); | |
| 816 | |||
| 817 | // collect local parameters and merge with global parameters | ||
| 818 | 59 | local_parameters := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 819 | 59 | Expression.map(range, function collectResizables(collector = local_parameters)); | |
| 820 | 59 | UnorderedSet.merge(parameters, local_parameters); | |
| 821 | |||
| 822 | // differentiate the target by all contained parameters to determine initial values | ||
| 823 | 59 | args := DifferentiationArguments.simpleCref(cref); | |
| 824 | 59 | local_parameters := UnorderedSet.selfMap(local_parameters, function getInitialValues(target = target, args = args, min_parameters = min_parameters, optimal_values = optimal_values)); | |
| 825 | |||
| 826 | 59 | getRangeConstraint(range.start, range.step, range.stop, local_parameters, c2pi, "equation"); | |
| 827 | then (); | ||
| 828 | else (); | ||
| 829 | end match; | ||
| 830 | end for; | ||
| 831 | end findOptimalValue; | ||
| 832 | |||
| 833 | function getRangeConstraint | ||
| 834 | input Expression start; | ||
| 835 | input Option<Expression> step_opt; | ||
| 836 | input Expression stop; | ||
| 837 | input UnorderedSet<ComponentRef> parameters; | ||
| 838 | input UnorderedMap<Expression, ParameterList> c2pi; | ||
| 839 | input String const_kind; | ||
| 840 | protected | ||
| 841 | Expression step, target, distance_const; | ||
| 842 | algorithm | ||
| 843 | 82 | step := Util.getOptionOrDefault(step_opt, Expression.INTEGER(1)); | |
| 844 | 82 | target := Expression.MULTARY({stop}, {start}, Operator.makeAdd(Type.INTEGER())); | |
| 845 | |||
| 846 | // the optimal distance constraint | ||
| 847 | // 2 - (stop - start)/start <= 0 | ||
| 848 | // ToDo: reduce the constant to 1. current structures do not support size 1 for loops well | ||
| 849 | 164 | distance_const := Expression.MULTARY({Expression.INTEGER(2)}, {Expression.MULTARY({target}, {step}, Operator.makeMul(Type.INTEGER()))}, Operator.makeAdd(Type.INTEGER())); | |
| 850 | 82 | distance_const := SimplifyExp.simplify(distance_const); | |
| 851 | 82 | distance_const := SimplifyExp.combineBinaries(distance_const); | |
| 852 | 82 | distance_const := SimplifyExp.simplify(distance_const); | |
| 853 | 82 | UnorderedMap.add(distance_const, UnorderedSet.toList(parameters), c2pi); | |
| 854 | if debug then | ||
| 855 | print("[debug] adding " + const_kind + " constraint: 0 >= " + Expression.toString(distance_const) + "\n"); | ||
| 856 | end if; | ||
| 857 | end getRangeConstraint; | ||
| 858 | |||
| 859 | function getFactor | ||
| 860 | input Expression exp; | ||
| 861 | input DifferentiationArguments args; | ||
| 862 | input Option<Integer> opt_factor; | ||
| 863 | output Integer factor; | ||
| 864 | protected | ||
| 865 | Expression diff; | ||
| 866 | algorithm | ||
| 867 | 54 | diff := Differentiate.differentiateExpression(exp, args); | |
| 868 | 54 | diff := SimplifyExp.simplify(diff); | |
| 869 | 54 | factor := Expression.integerValueOrDefault(diff, 0); | |
| 870 | |||
| 871 |
4/6✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 27 times.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
|
54 | if isSome(opt_factor) and factor <> Util.getOption(opt_factor) then |
| 872 | factor := 0; | ||
| 873 | end if; | ||
| 874 | end getFactor; | ||
| 875 | |||
| 876 | function getShift | ||
| 877 | input Expression exp; | ||
| 878 | input ComponentRef cref; | ||
| 879 | output Expression shift; | ||
| 880 | algorithm | ||
| 881 | 81 | shift := Replacements.single(exp, Expression.CREF(Type.INTEGER(), cref), Expression.INTEGER(0)); | |
| 882 | 81 | shift := SimplifyExp.simplify(shift); | |
| 883 | end getShift; | ||
| 884 | |||
| 885 | function getDistance | ||
| 886 | input ComponentRef cref; | ||
| 887 | input Expression exp; | ||
| 888 | input DifferentiationArguments args; | ||
| 889 | input output Option<Integer> opt_factor; | ||
| 890 | input output Integer min_distance; | ||
| 891 | input output Integer max_distance; | ||
| 892 | protected | ||
| 893 | Expression shift; | ||
| 894 | Integer factor, distance; | ||
| 895 | algorithm | ||
| 896 | ✗ | if isNone(opt_factor) or Util.getOption(opt_factor) <> 0 then | |
| 897 | ✗ | factor := getFactor(exp, args, opt_factor); | |
| 898 | |||
| 899 | ✗ | if factor <> 0 then | |
| 900 | // if the factor checks out, get shift and update min and max | ||
| 901 | ✗ | shift := getShift(exp, cref); | |
| 902 | try | ||
| 903 | // the shift has to be a single integer value | ||
| 904 | ✗ | Expression.INTEGER(distance) := shift; | |
| 905 | ✗ | if isNone(opt_factor) then | |
| 906 | ✗ | min_distance := distance; | |
| 907 | ✗ | max_distance := distance; | |
| 908 | opt_factor := SOME(factor); | ||
| 909 | else | ||
| 910 | ✗ | min_distance := intMin(distance, min_distance); | |
| 911 | max_distance := intMax(distance, max_distance); | ||
| 912 | end if; | ||
| 913 | else | ||
| 914 | // failed | ||
| 915 | min_distance := 0; | ||
| 916 | max_distance := 0; | ||
| 917 | opt_factor := SOME(0); | ||
| 918 | end try; | ||
| 919 | else | ||
| 920 | // failed | ||
| 921 | min_distance := 0; | ||
| 922 | max_distance := 0; | ||
| 923 | opt_factor := SOME(0); | ||
| 924 | end if; | ||
| 925 | end if; | ||
| 926 | end getDistance; | ||
| 927 | |||
| 928 | function addVariableConstraint | ||
| 929 | input ComponentRef cref; | ||
| 930 | input Equation eqn "for debugging only"; | ||
| 931 | input Option<UnorderedMap<ComponentRef, Expression>> replacements; | ||
| 932 | input output UnorderedMap<Expression, ParameterList> c2pi; | ||
| 933 | protected | ||
| 934 | Variable var = Pointer.access(BVariable.getVarPointer(cref, sourceInfo())); | ||
| 935 | list<Dimension> dims = Type.arrayDims(var.ty); | ||
| 936 | list<Subscript> subs = ComponentRef.subscriptsAllWithWholeFlat(cref); // needs list reverse? | ||
| 937 | Dimension dim; | ||
| 938 | Subscript sub; | ||
| 939 | Expression sub_exp, const; | ||
| 940 | Operator op = Operator.makeAdd(Type.INTEGER()); | ||
| 941 | algorithm | ||
| 942 |
2/2✓ Branch 1 taken 214 times.
✓ Branch 2 taken 178 times.
|
392 | for tpl in List.zip(dims, subs) loop |
| 943 | 214 | (dim, sub) := tpl; | |
| 944 | 214 | sub_exp := Subscript.toExp(sub); | |
| 945 | 428 | const := Expression.MULTARY({sub_exp}, {Dimension.sizeExp(dim)}, op); | |
| 946 | try | ||
| 947 | 214 | addConstraint(const, replacements, c2pi, Expression.isNonPositive, ComponentRef.toString(cref) + " (variable)", ">="); | |
| 948 | else | ||
| 949 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed.\nViolation of implicit constraint `" + Dimension.toString(dim) + " >= " + Subscript.toString(sub) | |
| 950 | + "` for component reference `" + ComponentRef.toString(cref) + "` of variable `" + Variable.toString(Pointer.access(BVariable.getVarPointer(cref, sourceInfo()))) + "`\nin equation:\n" + Equation.toString(eqn)}); | ||
| 951 | ✗ | fail(); | |
| 952 | end try; | ||
| 953 | 428 | const := Expression.MULTARY({Expression.INTEGER(1)}, {Dimension.sizeExp(dim)}, op); | |
| 954 | try | ||
| 955 | 214 | addConstraint(const, replacements, c2pi, Expression.isNonPositive, ComponentRef.toString(cref) + " (variable)", ">="); | |
| 956 | else | ||
| 957 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed.\nViolation of implicit constraint `" + Dimension.toString(dim) + " >= 1" | |
| 958 | + "` for component reference `" + ComponentRef.toString(cref) + "` of variable `" + Variable.toString(Pointer.access(BVariable.getVarPointer(cref, sourceInfo()))) + "`\nin equation:\n" + Equation.toString(eqn)}); | ||
| 959 | ✗ | fail(); | |
| 960 | end try; | ||
| 961 | end for; | ||
| 962 | end addVariableConstraint; | ||
| 963 | |||
| 964 | function addConstraint | ||
| 965 | input Expression old_const; | ||
| 966 | input Option<UnorderedMap<ComponentRef, Expression>> replacements; | ||
| 967 | input UnorderedMap<Expression, ParameterList> c2p; | ||
| 968 | input checkFunc func "checks validity of redundant constraints"; | ||
| 969 | input String const_kind "only for debugging: words to describe the kind of constraint"; | ||
| 970 | input String eq_kind "only for debugging: in/equality symbols (=, >=, <=, >, <)"; | ||
| 971 | partial function checkFunc | ||
| 972 | input Expression exp; | ||
| 973 | output Boolean b; | ||
| 974 | end checkFunc; | ||
| 975 | protected | ||
| 976 | Expression const, diff; | ||
| 977 | UnorderedSet<ComponentRef> parameters; | ||
| 978 | list<ComponentRef> params; | ||
| 979 | Boolean redundant; | ||
| 980 | DifferentiationArguments args; | ||
| 981 | UnorderedMap<ComponentRef, Expression> zero_replacements; | ||
| 982 | algorithm | ||
| 983 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 430 times.
✓ Branch 2 taken 314 times.
✓ Branch 3 taken 116 times.
|
430 | if isSome(replacements) then |
| 984 | 314 | const := Expression.map(old_const, function Replacements.applySimpleExp(replacements = Util.getOption(replacements))); | |
| 985 | else | ||
| 986 | const := old_const; | ||
| 987 | end if; | ||
| 988 | |||
| 989 | 430 | const := Expression.map(const, function addRangeConstraints(replacements = replacements, c2p = c2p, func = func, const_kind = const_kind, eq_kind = eq_kind)); | |
| 990 | |||
| 991 | 430 | parameters := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 992 | 430 | Expression.map(const, function collectResizables(collector = parameters)); | |
| 993 | 430 | params := UnorderedSet.toList(parameters); | |
| 994 | |||
| 995 | redundant := true; | ||
| 996 |
2/2✓ Branch 0 taken 388 times.
✓ Branch 1 taken 219 times.
|
607 | for p in params loop |
| 997 | 388 | args := DifferentiationArguments.simpleCref(p); | |
| 998 | 388 | diff := Differentiate.differentiateExpression(const, args); | |
| 999 | 388 | diff := SimplifyExp.simplify(diff); | |
| 1000 |
2/2✓ Branch 1 taken 177 times.
✓ Branch 2 taken 211 times.
|
388 | if not Expression.isZero(diff) then |
| 1001 | redundant := false; break; | ||
| 1002 | end if; | ||
| 1003 | end for; | ||
| 1004 | |||
| 1005 |
2/2✓ Branch 0 taken 211 times.
✓ Branch 1 taken 219 times.
|
430 | if not redundant then |
| 1006 | 211 | UnorderedMap.add(const, params, c2p); | |
| 1007 | else | ||
| 1008 | 219 | zero_replacements := UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | |
| 1009 |
2/2✓ Branch 0 taken 177 times.
✓ Branch 1 taken 219 times.
|
396 | for p in params loop |
| 1010 | 177 | UnorderedMap.add(p, Expression.INTEGER(0), zero_replacements); | |
| 1011 | end for; | ||
| 1012 | 219 | const := Expression.map(const, function Replacements.applySimpleExp(replacements = zero_replacements)); | |
| 1013 | 219 | const := SimplifyExp.simplify(const); | |
| 1014 | // Only fail for literals: symbolic CREFs remaining after replacement are inner iterators | ||
| 1015 | // (e.g. sum/product) whose bounds are guaranteed by their own range expression. | ||
| 1016 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 219 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
219 | if not func(const) and Expression.isLiteral(const) then fail(); end if; |
| 1017 | end if; | ||
| 1018 | |||
| 1019 | if debug then | ||
| 1020 | if redundant then | ||
| 1021 | print("[debug] not adding redundant " + const_kind + " constraint: 0 " + eq_kind + " " + Expression.toString(old_const) + " simplified to: 0 " + eq_kind + " " + Expression.toString(const) + "\n"); | ||
| 1022 | else | ||
| 1023 | print("[debug] adding " + const_kind + " constraint: 0 " + eq_kind + " " + Expression.toString(old_const) + " simplified to: 0 " + eq_kind + " " + Expression.toString(const) + "\n"); | ||
| 1024 | end if; | ||
| 1025 | end if; | ||
| 1026 | end addConstraint; | ||
| 1027 | |||
| 1028 | function addRangeConstraints | ||
| 1029 | input output Expression exp; | ||
| 1030 | input Option<UnorderedMap<ComponentRef, Expression>> replacements; | ||
| 1031 | input UnorderedMap<Expression, ParameterList> c2p; | ||
| 1032 | input checkFunc func "checks validity of redundant constraints"; | ||
| 1033 | input String const_kind "only for debugging: words to describe the kind of constraint"; | ||
| 1034 | input String eq_kind "only for debugging: in/equality symbols (=, >=, <=, >, <)"; | ||
| 1035 | partial function checkFunc | ||
| 1036 | input Expression exp; | ||
| 1037 | output Boolean b; | ||
| 1038 | end checkFunc; | ||
| 1039 | protected | ||
| 1040 | UnorderedSet<ComponentRef> parameters; | ||
| 1041 | algorithm | ||
| 1042 | exp := match exp | ||
| 1043 | case Expression.RANGE() algorithm | ||
| 1044 | // collect local parameters | ||
| 1045 | 23 | parameters := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 1046 | 23 | Expression.map(exp, function collectResizables(collector = parameters)); | |
| 1047 | 23 | getRangeConstraint(exp.start, exp.step, exp.stop, parameters, c2p, "variable"); | |
| 1048 | 23 | then Expression.rangeSizeExp(exp); | |
| 1049 | else exp; | ||
| 1050 | end match; | ||
| 1051 | end addRangeConstraints; | ||
| 1052 | |||
| 1053 | function getInitialValues | ||
| 1054 | input output ComponentRef cref; | ||
| 1055 | input Expression target; | ||
| 1056 | input DifferentiationArguments args; | ||
| 1057 | input UnorderedSet<ComponentRef> min_parameters; | ||
| 1058 | input UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 1059 | protected | ||
| 1060 | Expression diff, binding; | ||
| 1061 | Variable var; | ||
| 1062 | algorithm | ||
| 1063 | 59 | args.diffCref := cref; | |
| 1064 | 59 | diff := Differentiate.differentiateExpression(target, args); | |
| 1065 | 59 | diff := SimplifyExp.simplify(diff); | |
| 1066 | |||
| 1067 |
1/2✓ Branch 1 taken 59 times.
✗ Branch 2 not taken.
|
59 | if Expression.isPositive(diff) then |
| 1068 | // use min value as initial guess | ||
| 1069 | 59 | UnorderedSet.add(cref, min_parameters); | |
| 1070 | elseif Expression.isNegative(diff) then | ||
| 1071 | // use max value as initial guess | ||
| 1072 | else | ||
| 1073 | // cannot be determined -> use actual binding value | ||
| 1074 | ✗ | var := Pointer.access(BVariable.getVarPointer(cref, sourceInfo())); | |
| 1075 | ✗ | binding := Binding.getExp(var.binding); | |
| 1076 | ✗ | UnorderedMap.add(cref, binding, optimal_values); | |
| 1077 | end if; | ||
| 1078 | end getInitialValues; | ||
| 1079 | |||
| 1080 | function setInitialValues | ||
| 1081 | input output ComponentRef cref; | ||
| 1082 | input UnorderedSet<ComponentRef> min_parameters; | ||
| 1083 | input UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 1084 | protected | ||
| 1085 | Variable var; | ||
| 1086 | VariableAttributes attributes; | ||
| 1087 | Expression value; | ||
| 1088 | algorithm | ||
| 1089 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
|
14 | if not UnorderedMap.contains(cref, optimal_values) then |
| 1090 | 14 | var := Pointer.access(BVariable.getVarPointer(cref, sourceInfo())); | |
| 1091 | value := match var | ||
| 1092 | case Variable.VARIABLE(backendinfo = BackendInfo.BACKEND_INFO(attributes = attributes as VariableAttributes.VAR_ATTR_INT())) algorithm | ||
| 1093 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 2 times.
|
14 | if UnorderedSet.contains(cref, min_parameters) then |
| 1094 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | if isSome(attributes.min) then |
| 1095 | ✗ | value := Binding.getTypedExp(Util.getOption(attributes.min)); | |
| 1096 | else | ||
| 1097 | value := Expression.INTEGER(0); | ||
| 1098 | end if; | ||
| 1099 | elseif isSome(attributes.max) then | ||
| 1100 | ✗ | value := Binding.getTypedExp(Util.getOption(attributes.max)); | |
| 1101 | else | ||
| 1102 | value := Expression.INTEGER(0); | ||
| 1103 | end if; | ||
| 1104 | then value; | ||
| 1105 | else Expression.INTEGER(0); | ||
| 1106 | end match; | ||
| 1107 | 14 | UnorderedMap.add(cref, value, optimal_values); | |
| 1108 | end if; | ||
| 1109 | end setInitialValues; | ||
| 1110 | |||
| 1111 | function invertConstraintParameterMap | ||
| 1112 | input UnorderedMap<Expression, ParameterList> c2p; | ||
| 1113 | input UnorderedSet<ComponentRef> parameters; | ||
| 1114 | output UnorderedMap<ComponentRef, ConstraintList> p2c = UnorderedMap.new<ConstraintList>(ComponentRef.hash, ComponentRef.isEqual); | ||
| 1115 | protected | ||
| 1116 | Expression const; | ||
| 1117 | list<ComponentRef> params; | ||
| 1118 | algorithm | ||
| 1119 | // initializing map | ||
| 1120 |
2/2✓ Branch 1 taken 28 times.
✓ Branch 2 taken 30 times.
|
58 | for param in UnorderedSet.toList(parameters) loop |
| 1121 | 28 | UnorderedMap.add(param, {}, p2c); | |
| 1122 | end for; | ||
| 1123 | |||
| 1124 | // inverting map | ||
| 1125 |
2/2✓ Branch 1 taken 35 times.
✓ Branch 2 taken 30 times.
|
65 | for tpl in UnorderedMap.toList(c2p) loop |
| 1126 | 35 | (const, params) := tpl; | |
| 1127 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 35 times.
|
69 | for param in params loop |
| 1128 | // constraints of single elements (e.g. from expanded connections) may contain parameters that were not collected | ||
| 1129 | 68 | UnorderedMap.add(param, const :: UnorderedMap.getOrDefault(param, p2c, {}), p2c); | |
| 1130 | end for; | ||
| 1131 | end for; | ||
| 1132 | end invertConstraintParameterMap; | ||
| 1133 | |||
| 1134 | function computeOptimalValues | ||
| 1135 | input UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 1136 | input UnorderedMap<Expression, ParameterList> c2pi; | ||
| 1137 | input UnorderedMap<ComponentRef, ConstraintList> p2ci; | ||
| 1138 | input UnorderedMap<Expression, ParameterList> c2pe; | ||
| 1139 | input UnorderedMap<ComponentRef, ConstraintList> p2ce; | ||
| 1140 | protected | ||
| 1141 | UnorderedSet<ComponentRef> failed_parameters = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | ||
| 1142 | algorithm | ||
| 1143 | if debug then | ||
| 1144 | print("FIXING CONSTRAINTS\n\n"); | ||
| 1145 | end if; | ||
| 1146 | 15 | fixConstraints(optimal_values, c2pi, p2ci, failed_parameters, function intLe(i2 = 0)); | |
| 1147 | 15 | fixConstraints(optimal_values, c2pe, p2ce, failed_parameters, function intEq(i2 = 0)); | |
| 1148 | |||
| 1149 | if debug then | ||
| 1150 | print("\n"); | ||
| 1151 | end if; | ||
| 1152 | end computeOptimalValues; | ||
| 1153 | |||
| 1154 | function fixConstraints | ||
| 1155 | input UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 1156 | input UnorderedMap<Expression, ParameterList> c2p; | ||
| 1157 | input UnorderedMap<ComponentRef, ConstraintList> p2c; | ||
| 1158 | input UnorderedSet<ComponentRef> failed_parameters; | ||
| 1159 | input checkVal func "function to check if constraint is complied with"; | ||
| 1160 | partial function checkVal | ||
| 1161 | input Integer i; | ||
| 1162 | output Boolean b; | ||
| 1163 | end checkVal; | ||
| 1164 | protected | ||
| 1165 | UnorderedSet<Expression> parsed_constraints = UnorderedSet.new(Expression.hash, Expression.isEqual); | ||
| 1166 | Expression constraint, old_optimal_value; | ||
| 1167 | list<ComponentRef> crefs; | ||
| 1168 | Equation eqn, solved_eqn; | ||
| 1169 | Solve.Status status; | ||
| 1170 | Integer value; | ||
| 1171 | Boolean failed; | ||
| 1172 | algorithm | ||
| 1173 | // traversing constraints | ||
| 1174 |
2/2✓ Branch 1 taken 35 times.
✓ Branch 2 taken 30 times.
|
65 | for tpl in UnorderedMap.toList(c2p) loop |
| 1175 | 35 | (constraint, crefs) := tpl; | |
| 1176 | failed := false; | ||
| 1177 | () := match checkConstraint(constraint, optimal_values) | ||
| 1178 | // this constraint is not violated | ||
| 1179 | case SOME(value) guard(func(value)) algorithm | ||
| 1180 | if debug then | ||
| 1181 | print(Expression.toString(constraint) + " || is not violated " + intString(value) + "\n"); | ||
| 1182 | end if; | ||
| 1183 | then (); | ||
| 1184 | |||
| 1185 | // this constraint is violated | ||
| 1186 | case SOME(value) algorithm | ||
| 1187 | if debug then | ||
| 1188 | print(Expression.toString(constraint) + " || is violated by " + intString(value) + "\n"); | ||
| 1189 | end if; | ||
| 1190 | // create artificial equation | ||
| 1191 | 20 | eqn := Equation.makeAssignmentEqn(constraint, Expression.INTEGER(0), Iterator.EMPTY(), EquationAttributes.default(EquationKind.DISCRETE, false)); | |
| 1192 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | for cref in crefs loop |
| 1193 | failed := false; | ||
| 1194 | // solve the artificial equation for cref | ||
| 1195 | 20 | (solved_eqn, status, _) := Solve.solveBody(eqn, cref); | |
| 1196 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if status == NBSolve.Status.EXPLICIT then |
| 1197 | // try to used solved value as new parameter value to fulfill constraint | ||
| 1198 | () := match checkConstraint(Util.getOption(Equation.getRHS(solved_eqn)), optimal_values) | ||
| 1199 | case SOME(value) algorithm | ||
| 1200 | // saving previous optimal value and checking new one | ||
| 1201 | 20 | old_optimal_value := UnorderedMap.getSafe(cref, optimal_values, sourceInfo()); | |
| 1202 | 20 | UnorderedMap.add(cref, Expression.INTEGER(value), optimal_values); | |
| 1203 | |||
| 1204 | // check all constraints of this parameter | ||
| 1205 |
2/2✓ Branch 1 taken 52 times.
✓ Branch 2 taken 20 times.
|
72 | for cons in UnorderedMap.getSafe(cref, p2c, sourceInfo()) loop |
| 1206 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
52 | if UnorderedSet.contains(constraint, parsed_constraints) and not func(Util.getOptionOrDefault(checkConstraint(cons, optimal_values), 1)) then |
| 1207 | failed := true; | ||
| 1208 | break; | ||
| 1209 | end if; | ||
| 1210 | end for; | ||
| 1211 | |||
| 1212 | // if this parameter would violate any old constraint, use old value and check next parameter | ||
| 1213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if failed then |
| 1214 | ✗ | UnorderedMap.add(cref, old_optimal_value, optimal_values); | |
| 1215 | end if; | ||
| 1216 | then (); | ||
| 1217 | else (); | ||
| 1218 | end match; | ||
| 1219 | else | ||
| 1220 | // if the equation could not be solved, fail | ||
| 1221 | failed := true; | ||
| 1222 | end if; | ||
| 1223 | |||
| 1224 | // this constraint has been resolved if one parameter could be adjusted to fulfill it | ||
| 1225 | // without breaking other constraints | ||
| 1226 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if not failed then |
| 1227 | 20 | UnorderedSet.add(constraint, parsed_constraints); break; | |
| 1228 | end if; | ||
| 1229 | end for; | ||
| 1230 | then (); | ||
| 1231 | |||
| 1232 | // this constraint cannot be determined | ||
| 1233 | else algorithm | ||
| 1234 | ✗ | for cref in crefs loop | |
| 1235 | ✗ | UnorderedSet.add(cref, failed_parameters); | |
| 1236 | end for; | ||
| 1237 | then (); | ||
| 1238 | end match; | ||
| 1239 | |||
| 1240 | // this constraint cannot be fixed | ||
| 1241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if failed then |
| 1242 | ✗ | for cref in crefs loop | |
| 1243 | ✗ | UnorderedSet.add(cref, failed_parameters); | |
| 1244 | end for; | ||
| 1245 | end if; | ||
| 1246 | end for; | ||
| 1247 | end fixConstraints; | ||
| 1248 | |||
| 1249 | function checkConstraint | ||
| 1250 | input Expression constraint; | ||
| 1251 | input UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 1252 | output Option<Integer> value; | ||
| 1253 | protected | ||
| 1254 | Expression replaced; | ||
| 1255 | algorithm | ||
| 1256 | 632 | replaced := Expression.map(constraint, function Replacements.applySimpleExp(replacements = optimal_values)); | |
| 1257 | 632 | replaced := SimplifyExp.simplify(replaced); | |
| 1258 | value := match replaced | ||
| 1259 | 632 | case Expression.INTEGER() then SOME(replaced.value); | |
| 1260 | else NONE(); | ||
| 1261 | end match; | ||
| 1262 | end checkConstraint; | ||
| 1263 | |||
| 1264 | function updateDimension | ||
| 1265 | input output Dimension dim; | ||
| 1266 | input UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 1267 | algorithm | ||
| 1268 | dim := match dim | ||
| 1269 | case Dimension.RESIZABLE() algorithm | ||
| 1270 | 577 | dim.opt_size := checkConstraint(dim.exp, optimal_values); | |
| 1271 | then dim; | ||
| 1272 | |||
| 1273 | else dim; | ||
| 1274 | end match; | ||
| 1275 | end updateDimension; | ||
| 1276 | |||
| 1277 | // ***************************** | ||
| 1278 | // DEBUGGING TOSTRING FUNCTIONS | ||
| 1279 | // ***************************** | ||
| 1280 | |||
| 1281 | function optimalValuesToString | ||
| 1282 | "called using -d=dumpResizable" | ||
| 1283 | input UnorderedMap<ComponentRef, Expression> optimal_values; | ||
| 1284 | input output String str = StringUtil.headline_2("[dumpResizable] Evaluated Optimal Resizable Parameter Values:") + "\n"; | ||
| 1285 | protected | ||
| 1286 | ComponentRef param; | ||
| 1287 | Expression value; | ||
| 1288 | Variable var; | ||
| 1289 | list<String> names = {}, old_vals = {}, new_vals = {}; | ||
| 1290 | String name, old, new; | ||
| 1291 | Integer names_len; | ||
| 1292 | algorithm | ||
| 1293 | ✗ | for tpl in UnorderedMap.toList(optimal_values) loop | |
| 1294 | ✗ | (param, value) := tpl; | |
| 1295 | ✗ | var := Pointer.access(BVariable.getVarPointer(param, sourceInfo())); | |
| 1296 | ✗ | names := ComponentRef.toString(param) :: names; | |
| 1297 | ✗ | new_vals := Expression.toString(value) :: new_vals; | |
| 1298 | ✗ | old_vals := Binding.toString(var.binding) :: old_vals; | |
| 1299 | end for; | ||
| 1300 | |||
| 1301 | ✗ | names_len := max(stringLength(n) for n in names); | |
| 1302 | |||
| 1303 | ✗ | while not listEmpty(names) loop | |
| 1304 | ✗ | name :: names := names; | |
| 1305 | ✗ | new :: new_vals := new_vals; | |
| 1306 | ✗ | old :: old_vals := old_vals; | |
| 1307 | ✗ | str := str + " " + name + " " + StringUtil.repeat(".", names_len + 5 - stringLength(name)) + " OPTIMAL: " + new + " (ORIGINAL: " + old + ")\n"; | |
| 1308 | end while; | ||
| 1309 | ✗ | str := str + "\n"; | |
| 1310 | end optimalValuesToString; | ||
| 1311 | |||
| 1312 | function occurencesToString | ||
| 1313 | "helper function for debugging" | ||
| 1314 | input UnorderedMap<ComponentRef, Occurences> occs; | ||
| 1315 | output String str = ""; | ||
| 1316 | algorithm | ||
| 1317 | ✗ | for tpl in UnorderedMap.toList(occs) loop | |
| 1318 | ✗ | str := ComponentRef.toString(Util.tuple21(tpl)) + ": {" + UnorderedSet.toString(Util.tuple22(tpl), Expression.toString, ", ") + "}\n"; | |
| 1319 | end for; | ||
| 1320 | end occurencesToString; | ||
| 1321 | |||
| 1322 | function distancesToString | ||
| 1323 | "helper function for debugging" | ||
| 1324 | input tuple<ComponentRef, Integer> tpl; | ||
| 1325 | output String str = ComponentRef.toString(Util.tuple21(tpl)) + ":" + intString(Util.tuple22(tpl)); | ||
| 1326 | end distancesToString; | ||
| 1327 | |||
| 1328 | function parametersToString | ||
| 1329 | "helper function for debugging" | ||
| 1330 | input list<ComponentRef> parameters; | ||
| 1331 | output String str = List.toString(parameters, ComponentRef.toString); | ||
| 1332 | end parametersToString; | ||
| 1333 | |||
| 1334 | function constraintsToString | ||
| 1335 | "helper function for debugging" | ||
| 1336 | input list<Expression> constraints; | ||
| 1337 | output String str = List.toString(constraints, Expression.toString); | ||
| 1338 | end constraintsToString; | ||
| 1339 | |||
| 1340 | annotation(__OpenModelica_Interface="nbackend"); | ||
| 1341 | end NBResizable; | ||
| 1342 |