OMCompiler/Compiler/NBackEnd/Util/NBBackendUtil.mo
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of OpenModelica. | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), | ||
| 5 | * c/o Linköpings universitet, Department of Computer and Information Science, | ||
| 6 | * SE-58183 Linköping, Sweden. | ||
| 7 | * | ||
| 8 | * All rights reserved. | ||
| 9 | * | ||
| 10 | * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR | ||
| 11 | * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. | ||
| 12 | * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES | ||
| 13 | * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL | ||
| 14 | * VERSION 3, ACCORDING TO RECIPIENTS CHOICE. | ||
| 15 | * | ||
| 16 | * The OpenModelica software and the OSMC (Open Source Modelica Consortium) | ||
| 17 | * Public License (OSMC-PL) are obtained from OSMC, either from the above | ||
| 18 | * address, from the URLs: | ||
| 19 | * http://www.openmodelica.org or | ||
| 20 | * https://github.com/OpenModelica/ or | ||
| 21 | * http://www.ida.liu.se/projects/OpenModelica, | ||
| 22 | * and in the OpenModelica distribution. | ||
| 23 | * | ||
| 24 | * GNU AGPL version 3 is obtained from: | ||
| 25 | * https://www.gnu.org/licenses/licenses.html#GPL | ||
| 26 | * | ||
| 27 | * This program is distributed WITHOUT ANY WARRANTY; without | ||
| 28 | * even the implied warranty of MERCHANTABILITY or FITNESS | ||
| 29 | * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH | ||
| 30 | * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. | ||
| 31 | * | ||
| 32 | * See the full OSMC Public License conditions for more details. | ||
| 33 | * | ||
| 34 | */ | ||
| 35 | |||
| 36 | encapsulated package NBBackendUtil | ||
| 37 | " file: NBBackendUtil.mo | ||
| 38 | package: NBBackendUtil | ||
| 39 | description: This file contains util functions for the backend. | ||
| 40 | " | ||
| 41 | |||
| 42 | public | ||
| 43 | // NF imports | ||
| 44 | import NFBackendExtension.BackendInfo; | ||
| 45 | import ComponentRef = NFComponentRef; | ||
| 46 | import Expression = NFExpression; | ||
| 47 | import Operator = NFOperator; | ||
| 48 | import Type = NFType; | ||
| 49 | import Variable = NFVariable; | ||
| 50 | |||
| 51 | // backend imports | ||
| 52 | import BEquation = NBEquation; | ||
| 53 | import NBEquation.{Equation, Frame, FrameLocation}; | ||
| 54 | import BVariable = NBVariable; | ||
| 55 | |||
| 56 | // Util imports | ||
| 57 | import Util; | ||
| 58 | |||
| 59 | // old imports | ||
| 60 | import MMath; | ||
| 61 | import Rational; | ||
| 62 | |||
| 63 | function convertRational | ||
| 64 | input Rational r; | ||
| 65 | output MMath.Rational oldR = MMath.RATIONAL(r.n, r.d); | ||
| 66 | end convertRational; | ||
| 67 | |||
| 68 | function findTrueIndices | ||
| 69 | "returns all indices of elements that are true" | ||
| 70 | input array<Boolean> arr; | ||
| 71 | output list<Integer> indices = list(i for i guard arr[i] in arrayLength(arr):-1:1); | ||
| 72 | end findTrueIndices; | ||
| 73 | |||
| 74 | function indexTplGt<T> | ||
| 75 | "use with List.sort() and a rating function to sort any list" | ||
| 76 | input tuple<Integer, T> tpl1; | ||
| 77 | input tuple<Integer, T> tpl2; | ||
| 78 | output Boolean gt; | ||
| 79 | protected | ||
| 80 | Integer i1, i2; | ||
| 81 | algorithm | ||
| 82 | ✗ | (i1, _) := tpl1; | |
| 83 | ✗ | (i2, _) := tpl2; | |
| 84 | ✗ | gt := i1 > i2; | |
| 85 | end indexTplGt; | ||
| 86 | |||
| 87 | public function noNameHashEq | ||
| 88 | input BEquation.Equation eq; | ||
| 89 | input Integer mod; | ||
| 90 | output Integer hash; | ||
| 91 | algorithm | ||
| 92 | ✗ | hash := noNameHashExp(BEquation.Equation.getResidualExp(eq), mod); | |
| 93 | end noNameHashEq; | ||
| 94 | |||
| 95 | function noNameHashExp | ||
| 96 | "ToDo: is this mod safe? (missing intMod!)" | ||
| 97 | input Expression exp; | ||
| 98 | input Integer mod; | ||
| 99 | output Integer hash = 0; | ||
| 100 | algorithm | ||
| 101 | hash := match exp | ||
| 102 | local | ||
| 103 | Variable var; | ||
| 104 | Integer hash1, hash2; | ||
| 105 | ✗ | case Expression.INTEGER() then exp.value; | |
| 106 | ✗ | case Expression.REAL() then realInt(exp.value); | |
| 107 | ✗ | case Expression.STRING() then stringHashDjb2Mod(exp.value, mod); | |
| 108 | ✗ | case Expression.BOOLEAN() then Util.boolInt(exp.value); | |
| 109 | ✗ | case Expression.ENUM_LITERAL() then exp.index; // ty !! | |
| 110 | case Expression.CLKCONST() then 0; // clk !! | ||
| 111 | case Expression.CREF() algorithm | ||
| 112 | ✗ | var := BVariable.getVar(exp.cref, sourceInfo()); | |
| 113 | ✗ | then stringHashDjb2Mod(BackendInfo.toString(var.backendinfo), mod); | |
| 114 | case Expression.TYPENAME() then 1; // ty !! | ||
| 115 | case Expression.ARRAY() algorithm // ty !! | ||
| 116 | ✗ | for elem in exp.elements loop | |
| 117 | ✗ | hash := hash + noNameHashExp(elem, mod); | |
| 118 | end for; | ||
| 119 | ✗ | hash := hash + Util.boolInt(exp.literal); | |
| 120 | then hash; | ||
| 121 | case Expression.MATRIX() algorithm | ||
| 122 | ✗ | for lst in exp.elements loop | |
| 123 | ✗ | for elem in lst loop | |
| 124 | ✗ | hash := hash + noNameHashExp(elem, mod); | |
| 125 | end for; | ||
| 126 | end for; | ||
| 127 | then hash; | ||
| 128 | case Expression.RANGE() algorithm | ||
| 129 | ✗ | if isSome(exp.step) then | |
| 130 | ✗ | hash := noNameHashExp(Util.getOption(exp.step), mod); | |
| 131 | end if; | ||
| 132 | ✗ | then hash + noNameHashExp(exp.start, mod) + noNameHashExp(exp.stop, mod); | |
| 133 | case Expression.TUPLE() algorithm // ty !! | ||
| 134 | ✗ | for elem in exp.elements loop | |
| 135 | ✗ | hash := hash + noNameHashExp(elem, mod); | |
| 136 | end for; | ||
| 137 | then hash; | ||
| 138 | case Expression.RECORD() algorithm // path, ty !! | ||
| 139 | ✗ | for elem in exp.elements loop | |
| 140 | ✗ | hash := hash + noNameHashExp(elem, mod); | |
| 141 | end for; | ||
| 142 | then hash; | ||
| 143 | case Expression.CALL() then 2; // call!! | ||
| 144 | case Expression.SIZE() algorithm | ||
| 145 | ✗ | if isSome(exp.dimIndex) then | |
| 146 | ✗ | hash := noNameHashExp(Util.getOption(exp.dimIndex), mod); | |
| 147 | end if; | ||
| 148 | ✗ | then hash + noNameHashExp(exp.exp, mod); | |
| 149 | ✗ | case Expression.END() then stringHashDjb2Mod("end", mod); | |
| 150 | case Expression.BINARY() algorithm | ||
| 151 | ✗ | hash1 := noNameHashExp(exp.exp1, mod); | |
| 152 | ✗ | hash2 := noNameHashExp(exp.exp2, mod); | |
| 153 | hash := match Operator.classify(exp.operator) | ||
| 154 | ✗ | case (NFOperator.MathClassification.ADDITION, _) then hash1 + hash2; | |
| 155 | ✗ | case (NFOperator.MathClassification.SUBTRACTION, _) then hash1 - hash2; | |
| 156 | ✗ | case (NFOperator.MathClassification.MULTIPLICATION, _) then hash1 * hash2; | |
| 157 | ✗ | case (NFOperator.MathClassification.DIVISION, _) then realInt(hash1 / hash2); | |
| 158 | ✗ | case (NFOperator.MathClassification.POWER, _) then realInt(hash1 ^ hash2); | |
| 159 | ✗ | case (NFOperator.MathClassification.LOGICAL, _) then -(hash1 + hash2); | |
| 160 | ✗ | case (NFOperator.MathClassification.RELATION, _) then hash2 - hash1; | |
| 161 | ✗ | else hash2 - hash1; | |
| 162 | end match; | ||
| 163 | then hash; | ||
| 164 | ✗ | case Expression.UNARY() then -noNameHashExp(exp.exp, mod); | |
| 165 | case Expression.LBINARY() algorithm | ||
| 166 | ✗ | hash1 := noNameHashExp(exp.exp1, mod); | |
| 167 | ✗ | hash2 := noNameHashExp(exp.exp2, mod); | |
| 168 | hash := match exp.operator.op | ||
| 169 | ✗ | case NFOperator.Op.AND then hash1 + hash2; | |
| 170 | ✗ | case NFOperator.Op.OR then hash1 - hash2; | |
| 171 | ✗ | else hash2 - hash1; | |
| 172 | end match; | ||
| 173 | then hash; | ||
| 174 | ✗ | case Expression.LUNARY() then -noNameHashExp(exp.exp, mod); | |
| 175 | case Expression.RELATION() algorithm | ||
| 176 | ✗ | hash1 := noNameHashExp(exp.exp1, mod); | |
| 177 | ✗ | hash2 := noNameHashExp(exp.exp2, mod); | |
| 178 | hash := match exp.operator.op | ||
| 179 | ✗ | case NFOperator.Op.LESS then hash1 + hash2; | |
| 180 | ✗ | case NFOperator.Op.LESSEQ then -(hash1 + hash2); | |
| 181 | ✗ | case NFOperator.Op.GREATER then hash1 - hash2; | |
| 182 | ✗ | case NFOperator.Op.GREATEREQ then hash2 - hash1; | |
| 183 | ✗ | case NFOperator.Op.EQUAL then hash1 * hash2; | |
| 184 | ✗ | case NFOperator.Op.NEQUAL then realInt(hash1 ^ hash2); | |
| 185 | ✗ | else hash2 - hash1; | |
| 186 | end match; | ||
| 187 | then hash; | ||
| 188 | ✗ | case Expression.IF() then noNameHashExp(exp.condition, mod) + | |
| 189 | noNameHashExp(exp.trueBranch, mod) + | ||
| 190 | noNameHashExp(exp.falseBranch, mod); | ||
| 191 | ✗ | case Expression.CAST() then noNameHashExp(exp.exp, mod); | |
| 192 | ✗ | case Expression.BOX() then noNameHashExp(exp.exp, mod); | |
| 193 | ✗ | case Expression.UNBOX() then noNameHashExp(exp.exp, mod); | |
| 194 | ✗ | case Expression.SUBSCRIPTED_EXP() then noNameHashExp(exp.exp, mod); // subscripts! | |
| 195 | ✗ | case Expression.TUPLE_ELEMENT() then noNameHashExp(exp.tupleExp, mod) + exp.index; | |
| 196 | ✗ | case Expression.RECORD_ELEMENT() then noNameHashExp(exp.recordExp, mod) + exp.index; | |
| 197 | ✗ | case Expression.MUTABLE() then noNameHashExp(Mutable.access(exp.exp), mod); | |
| 198 | ✗ | case Expression.EMPTY() then stringHashDjb2Mod("empty", mod); | |
| 199 | case Expression.PARTIAL_FUNCTION_APPLICATION() algorithm | ||
| 200 | //should we hash function names here? | ||
| 201 | ✗ | for arg in exp.args loop | |
| 202 | ✗ | hash := hash + noNameHashExp(arg, mod); | |
| 203 | end for; | ||
| 204 | then hash; | ||
| 205 | else 0; | ||
| 206 | end match; | ||
| 207 | ✗ | hash := intMod(intAbs(hash), mod); | |
| 208 | end noNameHashExp; | ||
| 209 | |||
| 210 | function isOnlyTimeDependent | ||
| 211 | input Expression exp; | ||
| 212 | output Boolean b; | ||
| 213 | algorithm | ||
| 214 | 186 | b := Expression.fold(exp, isOnlyTimeDependentFold, true); | |
| 215 | end isOnlyTimeDependent; | ||
| 216 | |||
| 217 | function isOnlyTimeDependentFold | ||
| 218 | input Expression exp; | ||
| 219 | input output Boolean b; | ||
| 220 | algorithm | ||
| 221 |
2/2✓ Branch 0 taken 349 times.
✓ Branch 1 taken 413 times.
|
762 | if b then |
| 222 | b := match exp | ||
| 223 |
4/4✓ Branch 1 taken 184 times.
✓ Branch 2 taken 44 times.
✓ Branch 4 taken 55 times.
✓ Branch 5 taken 129 times.
|
228 | case Expression.CREF() then ComponentRef.isTime(exp.cref) or BVariable.checkCref(exp.cref, BVariable.isParamOrConst, sourceInfo()); |
| 224 | else true; | ||
| 225 | end match; | ||
| 226 | end if; | ||
| 227 | end isOnlyTimeDependentFold; | ||
| 228 | |||
| 229 | function isContinuous | ||
| 230 | input Expression exp; | ||
| 231 | input Boolean staticAsContinuous; | ||
| 232 | output Boolean b; | ||
| 233 | algorithm | ||
| 234 | ✗ | b := Expression.fold(exp, function isContinuousFold(staticAsContinuous = staticAsContinuous), true); | |
| 235 | end isContinuous; | ||
| 236 | |||
| 237 | function isContinuousFold | ||
| 238 | input Expression exp; | ||
| 239 | input Boolean staticAsContinuous; | ||
| 240 | input output Boolean b; | ||
| 241 | algorithm | ||
| 242 | ✗ | if b then | |
| 243 | b := match exp | ||
| 244 | ✗ | case Expression.CREF() then BVariable.checkCref(exp.cref, function BVariable.isContinuous(staticAsContinuous = staticAsContinuous), sourceInfo()); | |
| 245 | else true; | ||
| 246 | end match; | ||
| 247 | end if; | ||
| 248 | end isContinuousFold; | ||
| 249 | |||
| 250 | function containsContinuousVar | ||
| 251 | "Returns true if the expression contains at least one continuous variable. | ||
| 252 | Unlike isContinuous (ALL-fold), this is an OR-fold: any single continuous | ||
| 253 | variable makes the whole expression 'continuous' for event purposes." | ||
| 254 | input Expression exp; | ||
| 255 | output Boolean b; | ||
| 256 | algorithm | ||
| 257 | 374 | b := Expression.fold(exp, containsContinuousVarFold, false); | |
| 258 | end containsContinuousVar; | ||
| 259 | |||
| 260 | function containsContinuousVarFold | ||
| 261 | input Expression exp; | ||
| 262 | input output Boolean b; | ||
| 263 | algorithm | ||
| 264 |
2/2✓ Branch 0 taken 789 times.
✓ Branch 1 taken 376 times.
|
1165 | if not b then |
| 265 | b := match exp | ||
| 266 | 457 | case Expression.CREF() then BVariable.checkCref(exp.cref, function BVariable.isContinuous(staticAsContinuous = false), sourceInfo()); | |
| 267 | else false; | ||
| 268 | end match; | ||
| 269 | end if; | ||
| 270 | end containsContinuousVarFold; | ||
| 271 | |||
| 272 | public function makeFDerString | ||
| 273 | input output String str; | ||
| 274 | input Option<Integer> i_opt = NONE(); | ||
| 275 | protected | ||
| 276 | String i = if isSome(i_opt) then intString(Util.getOption(i_opt)) else ""; | ||
| 277 | algorithm | ||
| 278 | 291 | str := NBVariable.FUNCTION_DERIVATIVE_STR + i + "_" + str; | |
| 279 | end makeFDerString; | ||
| 280 | annotation(__OpenModelica_Interface="nbackend"); | ||
| 281 | end NBBackendUtil; | ||
| 282 |