Skip to content

Commit fae4e48

Browse files
authored
[NB] Check for compatible variability (#11047)
* [NB] Check for compatible variability MLS section 3.8 forbids to solve an equation for a variable with lower variability. TODO - alias removal doesn't check and removes eagerly. - Types are not checked, so `/*Integer*/ n = 3.14` is not found.
1 parent 259a951 commit fae4e48

File tree

8 files changed

+140
-44
lines changed

8 files changed

+140
-44
lines changed

OMCompiler/Compiler/NBackEnd/Classes/NBVariable.mo

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ public
135135

136136
function fromCref
137137
input ComponentRef cref;
138+
input Attributes attr = NFAttributes.DEFAULT_ATTR;
138139
input Binding binding = NFBinding.EMPTY_BINDING;
139140
output Variable variable;
140141
protected
@@ -144,10 +145,10 @@ public
144145
SourceInfo info;
145146
algorithm
146147
node := ComponentRef.node(cref);
147-
ty := ComponentRef.getSubscriptedType(cref, true);
148-
vis := InstNode.visibility(node);
148+
ty := ComponentRef.getSubscriptedType(cref, true);
149+
vis := InstNode.visibility(node);
149150
info := InstNode.info(node);
150-
variable := Variable.VARIABLE(cref, ty, binding, vis, NFAttributes.DEFAULT_ATTR, {}, {}, NONE(), info, NFBackendExtension.DUMMY_BACKEND_INFO);
151+
variable := Variable.VARIABLE(cref, ty, binding, vis, attr, {}, {}, NONE(), info, NFBackendExtension.DUMMY_BACKEND_INFO);
151152
end fromCref;
152153

153154
function makeVarPtrCyclic
@@ -533,7 +534,7 @@ public
533534
state := getVarPointer(cref);
534535
derNode := InstNode.VAR_NODE(DERIVATIVE_STR, dummy_ptr);
535536
der_cref := ComponentRef.append(cref, ComponentRef.fromNode(derNode, ComponentRef.scalarType(cref)));
536-
var := fromCref(der_cref);
537+
var := fromCref(der_cref, Variable.attributes(Pointer.access(state)));
537538
var.backendinfo := BackendExtension.BackendInfo.setVarKind(var.backendinfo, BackendExtension.STATE_DER(state, NONE()));
538539
(var_ptr, der_cref) := makeVarPtrCyclic(var, der_cref);
539540
then ();
@@ -740,7 +741,8 @@ public
740741
function makePreVar
741742
"Creates a previous variable pointer from the discrete variable cref.
742743
e.g. isOpen -> $PRE.isOpen"
743-
input output ComponentRef cref "old component reference to new component reference";
744+
input ComponentRef cref "old component reference";
745+
output ComponentRef pre_cref "new component reference";
744746
output Pointer<Variable> var_ptr "pointer to new variable";
745747
algorithm
746748
() := match ComponentRef.node(cref)
@@ -752,10 +754,10 @@ public
752754
algorithm
753755
disc := BVariable.getVarPointer(cref);
754756
qual.name := PREVIOUS_STR;
755-
cref := ComponentRef.append(cref, ComponentRef.fromNode(qual, ComponentRef.scalarType(cref)));
756-
var := fromCref(cref);
757+
pre_cref := ComponentRef.append(cref, ComponentRef.fromNode(qual, ComponentRef.scalarType(cref)));
758+
var := fromCref(pre_cref, Variable.attributes(Pointer.access(disc)));
757759
var.backendinfo := BackendExtension.BackendInfo.setVarKind(var.backendinfo, BackendExtension.PREVIOUS(disc));
758-
(var_ptr, cref) := makeVarPtrCyclic(var, cref);
760+
(var_ptr, pre_cref) := makeVarPtrCyclic(var, pre_cref);
759761
then ();
760762

761763
else algorithm
@@ -808,7 +810,7 @@ public
808810
// prepend the seed str and the matrix name and create the new cref
809811
qual.name := SEED_STR + "_" + name;
810812
cref := ComponentRef.append(cref, ComponentRef.fromNode(qual, ComponentRef.scalarType(cref)));
811-
var := fromCref(cref);
813+
var := fromCref(cref, NFAttributes.IMPL_DISCRETE_ATTR);
812814
// update the variable to be a seed and pass the pointer to the original variable
813815
var.backendinfo := BackendExtension.BackendInfo.setVarKind(var.backendinfo, BackendExtension.SEED_VAR(old_var_ptr));
814816
// create the new variable pointer and safe it to the component reference
@@ -825,9 +827,10 @@ public
825827
"Creates a partial derivative variable pointer from a cref. Used in NBJacobian and NBHessian
826828
to represent generic gradient equations.
827829
e.g: (speed, 'Jac') -> $pDer_Jac.speed"
828-
input output ComponentRef cref "old component reference to new component reference";
830+
input ComponentRef cref "old component reference";
829831
input String name "name of the matrix this partial derivative belongs to";
830832
input Boolean isTmp "sets variable kind for tmpVar or resultVar accordingly";
833+
output ComponentRef pder_cref "new component reference";
831834
output Pointer<Variable> var_ptr "pointer to new variable";
832835
protected
833836
VariableKind varKind = if isTmp then BackendExtension.JAC_TMP_VAR() else BackendExtension.JAC_VAR();
@@ -841,12 +844,12 @@ public
841844
case qual as InstNode.VAR_NODE() algorithm
842845
// prepend the seed str and the matrix name and create the new cref_DIFF_DIFF
843846
qual.name := PARTIAL_DERIVATIVE_STR + "_" + name;
844-
cref := ComponentRef.append(cref, ComponentRef.fromNode(qual, ComponentRef.scalarType(cref)));
845-
var := fromCref(cref);
847+
pder_cref := ComponentRef.append(cref, ComponentRef.fromNode(qual, ComponentRef.scalarType(cref)));
848+
var := fromCref(pder_cref, Variable.attributes(getVar(cref)));
846849
// update the variable kind and pass the pointer to the original variable
847850
var.backendinfo := BackendExtension.BackendInfo.setVarKind(var.backendinfo, varKind);
848851
// create the new variable pointer and safe it to the component reference
849-
(var_ptr, cref) := makeVarPtrCyclic(var, cref);
852+
(var_ptr, pder_cref) := makeVarPtrCyclic(var, pder_cref);
850853
then ();
851854

852855
else algorithm
@@ -880,7 +883,8 @@ public
880883
function makeStartVar
881884
"Creates a start variable pointer from a cref. Used in NBInitialization.
882885
e.g: angle -> $START.angle"
883-
input output ComponentRef cref "old component reference to new component reference";
886+
input ComponentRef cref "old component reference";
887+
output ComponentRef start_cref "new component reference";
884888
output Pointer<Variable> var_ptr "pointer to new variable";
885889
algorithm
886890
() := match ComponentRef.node(cref)
@@ -894,13 +898,13 @@ public
894898
old_var_ptr := BVariable.getVarPointer(cref);
895899
// prepend the seed str and the matrix name and create the new cref
896900
qual.name := START_STR;
897-
cref := ComponentRef.append(cref, ComponentRef.fromNode(qual, ComponentRef.scalarType(cref)));
898-
var := fromCref(cref);
901+
start_cref := ComponentRef.append(cref, ComponentRef.fromNode(qual, ComponentRef.scalarType(cref)));
902+
var := fromCref(start_cref, Variable.attributes(getVar(cref)));
899903
// update the variable to be a seed and pass the pointer to the original variable
900904
var.backendinfo := BackendExtension.BackendInfo.setVarKind(var.backendinfo, BackendExtension.START(old_var_ptr));
901905
// create the new variable pointer and safe it to the component reference
902906
var_ptr := Pointer.create(var);
903-
cref := BackendDAE.lowerComponentReferenceInstNode(cref, var_ptr);
907+
start_cref := BackendDAE.lowerComponentReferenceInstNode(start_cref, var_ptr);
904908
then ();
905909

906910
else algorithm
@@ -966,16 +970,16 @@ public
966970
cref := ComponentRef.CREF(node, iter_subs, ty, NFComponentRef.Origin.CREF, ComponentRef.EMPTY());
967971
var_cref := ComponentRef.CREF(node, {}, ty, NFComponentRef.Origin.CREF, ComponentRef.EMPTY());
968972
// create variable
969-
var := fromCref(var_cref);
973+
var := fromCref(var_cref, NFAttributes.IMPL_DISCRETE_ATTR);
970974
// update the variable to be discrete and pass the pointer to the original variable
971975
var.backendinfo := BackendExtension.BackendInfo.setVarKind(var.backendinfo, BackendExtension.DISCRETE());
972976
// create the new variable pointer and safe it to the component reference
973977
(var_ptr, cref) := makeVarPtrCyclic(var, cref);
974978
end makeEventVar;
975979

976980
function makeAuxStateVar
977-
"Creates a generic boolean variable pointer from a unique index and context name.
978-
e.g. (\"$WHEN\", 4) --> $WHEN_4"
981+
"Creates a auxiliary state variable from an expression.
982+
e.g. der(x^2 + y) --> der(aux)"
979983
input Integer uniqueIndex "unique identifier index";
980984
input Option<Expression> binding "optional binding expression";
981985
output Pointer<Variable> var_ptr "pointer to new variable";
@@ -993,7 +997,7 @@ public
993997
// create variable and add optional binding
994998
if isSome(binding) then
995999
bnd := Util.getOption(binding);
996-
var := fromCref(cref, Binding.FLAT_BINDING(bnd, Expression.variability(bnd), NFBinding.Source.BINDING));
1000+
var := fromCref(cref, NFAttributes.DEFAULT_ATTR, Binding.FLAT_BINDING(bnd, Expression.variability(bnd), NFBinding.Source.BINDING));
9971001
else
9981002
var := fromCref(cref);
9991003
end if;

OMCompiler/Compiler/NBackEnd/Modules/1_Main/NBCausalize.mo

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ protected
4444
import Expression = NFExpression;
4545
import NFFlatten.{FunctionTree, FunctionTreeImpl};
4646
import InstNode = NFInstNode.InstNode;
47+
import Prefixes = NFPrefixes;
4748
import SBGraphUtil = NFSBGraphUtil;
4849
import Subscript = NFSubscript;
4950
import Type = NFType;
@@ -100,7 +101,7 @@ public
100101

101102
case (System.SystemType.ODE, BackendDAE.MAIN(ode = systems, varData = varData, eqData = eqData, funcTree = funcTree))
102103
algorithm
103-
(systems, varData, eqData, funcTree) := applyModule(systems, varData, eqData, funcTree, func);
104+
(systems, varData, eqData, funcTree) := applyModule(systems, systemType, varData, eqData, funcTree, func);
104105
bdae.ode := systems;
105106
bdae.varData := varData;
106107
bdae.eqData := eqData;
@@ -112,10 +113,10 @@ public
112113
if Flags.isSet(Flags.INITIALIZATION) then
113114
print(StringUtil.headline_1("Balance Initialization") + "\n");
114115
end if;
115-
(systems, varData, eqData, funcTree) := applyModule(systems, varData, eqData, funcTree, func);
116+
(systems, varData, eqData, funcTree) := applyModule(systems, systemType, varData, eqData, funcTree, func);
116117
bdae.init := systems;
117118
if Util.isSome(bdae.init_0) then
118-
(systems, varData, eqData, funcTree) := applyModule(Util.getOption(bdae.init_0), varData, eqData, funcTree, func);
119+
(systems, varData, eqData, funcTree) := applyModule(Util.getOption(bdae.init_0), systemType, varData, eqData, funcTree, func);
119120
bdae.init_0 := SOME(systems);
120121
end if;
121122
bdae.varData := varData;
@@ -125,7 +126,7 @@ public
125126

126127
case (System.SystemType.DAE, BackendDAE.MAIN(dae = SOME(systems), varData = varData, eqData = eqData, funcTree = funcTree))
127128
algorithm
128-
(systems, varData, eqData, funcTree) := applyModule(systems, varData, eqData, funcTree, causalizeDAEMode);
129+
(systems, varData, eqData, funcTree) := applyModule(systems, systemType, varData, eqData, funcTree, causalizeDAEMode);
129130
bdae.dae := SOME(systems);
130131
bdae.varData := varData;
131132
bdae.eqData := eqData;
@@ -140,21 +141,64 @@ public
140141

141142
function applyModule
142143
input list<System.System> systems;
144+
input System.SystemType systemType;
143145
output list<System.System> new_systems = {};
144146
input output VarData varData;
145147
input output EqData eqData;
146148
input output FunctionTree funcTree;
147149
input Module.causalizeInterface func;
148150
protected
149151
System.System new_system;
152+
Boolean violated = false "true if any system violated variability consistency";
150153
algorithm
151154
for system in systems loop
152155
(new_system, varData, eqData, funcTree) := func(system, varData, eqData, funcTree);
153156
new_systems := new_system :: new_systems;
154157
end for;
155158
new_systems := listReverse(new_systems);
159+
160+
if systemType <> System.SystemType.INI then
161+
for system in new_systems loop
162+
violated := checkSystemVariabilities(system) or violated;
163+
end for;
164+
if violated then fail(); end if;
165+
end if;
156166
end applyModule;
157167

168+
function checkSystemVariabilities
169+
"checks whether variability is valid. Prevents things like `Integer i = time;`"
170+
input System.System system;
171+
output Boolean violated = false;
172+
algorithm
173+
if isSome(system.strongComponents) then
174+
for scc in Util.getOption(system.strongComponents) loop
175+
() := match scc
176+
case StrongComponent.SINGLE_COMPONENT() algorithm
177+
if Variable.variability(Pointer.access(scc.var)) <
178+
Prefixes.variabilityMax(
179+
Expression.variability(Equation.getLHS(Pointer.access(scc.eqn))),
180+
Expression.variability(Equation.getRHS(Pointer.access(scc.eqn)))
181+
)
182+
then
183+
// The variability of the equation must be greater or equal to that of the variable it solves.
184+
// See MLS section 3.8 Variability of Expressions
185+
Error.addMessage(Error.COMPILER_ERROR, {"The following strong component has conflicting variabilities: "
186+
+ Prefixes.variabilityString(Variable.variability(Pointer.access(scc.var))) + " != "
187+
+ Prefixes.variabilityString(Prefixes.variabilityMax(
188+
Expression.variability(Equation.getLHS(Pointer.access(scc.eqn))),
189+
Expression.variability(Equation.getRHS(Pointer.access(scc.eqn)))
190+
))
191+
+ "\n" + StrongComponent.toString(scc)});
192+
violated := true;
193+
end if;
194+
then ();
195+
/* TODO case StrongComponent.MULTI_COMPONENT() */
196+
else ();
197+
end match;
198+
end for;
199+
end if;
200+
end checkSystemVariabilities;
201+
158202
function simple
159203
input VariablePointers vars;
160204
input EquationPointers eqs;

OMCompiler/Compiler/NBackEnd/Modules/1_Main/NBPartitioning.mo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ protected
362362
single_vars := VariablePointers.getMarkedVars(variables, marked_vars);
363363

364364
if not listEmpty(single_vars) then
365-
Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " (" + System.System.systemTypeString(systemType)
365+
Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " (" + System.System.systemTypeString(systemType)
366366
+ ") failed because the following variables could not be assigned to a partition:\n {"
367367
+ stringDelimitList(list(BVariable.toString(Pointer.access(var)) for var in single_vars), "\n") + "}"});
368368
fail();

OMCompiler/Compiler/NFFrontEnd/NFAttributes.mo

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public
141141
finalPrefix = SCode.Final.NOT_FINAL(),
142142
innerOuter = Absyn.InnerOuter.NOT_INNER_OUTER(),
143143
replaceablePrefix = SCode.Replaceable.NOT_REPLACEABLE()))
144-
then NFAttributes.DEFAULT_ATTR;
144+
then DEFAULT_ATTR;
145145

146146
else
147147
algorithm
@@ -199,9 +199,9 @@ public
199199
Boolean fin, redecl;
200200
Replaceable repl;
201201
algorithm
202-
if referenceEq(outerAttr, NFAttributes.DEFAULT_ATTR) and innerAttr.connectorType == 0 then
202+
if referenceEq(outerAttr, DEFAULT_ATTR) and innerAttr.connectorType == 0 then
203203
attr := innerAttr;
204-
elseif referenceEq(innerAttr, NFAttributes.DEFAULT_ATTR) then
204+
elseif referenceEq(innerAttr, DEFAULT_ATTR) then
205205
cty := ConnectorType.merge(outerAttr.connectorType, innerAttr.connectorType, node);
206206
attr := Attributes.ATTRIBUTES(cty, outerAttr.parallelism,
207207
outerAttr.variability, outerAttr.direction, innerAttr.innerOuter, outerAttr.isFinal,
@@ -238,9 +238,9 @@ public
238238
Boolean fin, redecl;
239239
Replaceable repl;
240240
algorithm
241-
if referenceEq(innerAttr, NFAttributes.DEFAULT_ATTR) and outerAttr.connectorType == 0 then
241+
if referenceEq(innerAttr, DEFAULT_ATTR) and outerAttr.connectorType == 0 then
242242
attr := outerAttr;
243-
elseif referenceEq(outerAttr, NFAttributes.DEFAULT_ATTR) and innerAttr.connectorType == 0 then
243+
elseif referenceEq(outerAttr, DEFAULT_ATTR) and innerAttr.connectorType == 0 then
244244
attr := innerAttr;
245245
else
246246
Attributes.ATTRIBUTES(cty, par, var, dir, io, fin, redecl, repl) := outerAttr;
@@ -266,9 +266,9 @@ public
266266
Boolean redecl;
267267
Replaceable repl;
268268
algorithm
269-
if referenceEq(origAttr, NFAttributes.DEFAULT_ATTR) then
269+
if referenceEq(origAttr, DEFAULT_ATTR) then
270270
attr := redeclAttr;
271-
elseif referenceEq(redeclAttr, NFAttributes.DEFAULT_ATTR) then
271+
elseif referenceEq(redeclAttr, DEFAULT_ATTR) then
272272
attr := origAttr;
273273
else
274274
Attributes.ATTRIBUTES(cty, par, var, dir, io, _, _, _) := origAttr;
@@ -514,7 +514,7 @@ public
514514
protected
515515
Variability var = attr.variability;
516516
algorithm
517-
if referenceEq(attr, NFAttributes.DEFAULT_ATTR) and InstNode.isDiscreteClass(clsNode) then
517+
if referenceEq(attr, DEFAULT_ATTR) and InstNode.isDiscreteClass(clsNode) then
518518
attr := NFAttributes.IMPL_DISCRETE_ATTR;
519519
elseif var == Variability.CONTINUOUS and InstNode.isDiscreteClass(clsNode) then
520520
attr.variability := Variability.IMPLICITLY_DISCRETE;

OMCompiler/Compiler/NFFrontEnd/NFComponentRef.mo

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ protected
4747
import Prefixes = NFPrefixes;
4848
import MetaModelica.Dangerous.*;
4949
import JSON;
50+
import Variable = NFVariable;
5051

5152
import ComponentRef = NFComponentRef;
5253

@@ -453,9 +454,12 @@ public
453454
output Variability var;
454455
algorithm
455456
var := match cref
457+
local
458+
Pointer<Variable> v;
456459
case CREF(node = InstNode.COMPONENT_NODE())
457460
then Component.variability(InstNode.component(cref.node));
458461
case CREF(node = InstNode.CLASS_NODE()) then Variability.CONSTANT;
462+
case CREF(node = InstNode.VAR_NODE(varPointer = v)) then Variable.variability(Pointer.access(v));
459463
else Variability.CONTINUOUS;
460464
end match;
461465
end nodeVariability;

OMCompiler/Compiler/NFFrontEnd/NFVariable.mo

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,26 @@ public
191191
else {var};
192192
end expandChildren;
193193

194+
function typeOf
195+
input Variable var;
196+
output Type ty = var.ty;
197+
end typeOf;
198+
199+
function attributes
200+
input Variable variable;
201+
output Attributes attributes = variable.attributes;
202+
end attributes;
203+
204+
function variability
205+
input Variable variable;
206+
output Variability variability = variable.attributes.variability;
207+
end variability;
208+
209+
function visibility
210+
input Variable variable;
211+
output Visibility visibility = variable.visibility;
212+
end visibility;
213+
194214
function isComplex
195215
input Variable var;
196216
output Boolean b = Type.isComplex(var.ty);
@@ -207,16 +227,6 @@ public
207227
variable.attributes.variability <= Variability.STRUCTURAL_PARAMETER;
208228
end isStructural;
209229

210-
function variability
211-
input Variable variable;
212-
output Variability variability = variable.attributes.variability;
213-
end variability;
214-
215-
function visibility
216-
input Variable variable;
217-
output Visibility visibility = variable.visibility;
218-
end visibility;
219-
220230
function isEmptyArray
221231
input Variable variable;
222232
output Boolean isEmpty = Type.isEmptyArray(variable.ty);

testsuite/simulation/modelica/NBackend/basics/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ simpleNonlinearLoop.mos \
1111
implicitEquation.mos \
1212
underdetermined_init.mos \
1313
partitioning.mos \
14+
variability.mos \
1415

1516
# test that currently fail. Move up when fixed.
1617
# Run make failingtest

0 commit comments

Comments
 (0)