Skip to content

Commit

Permalink
[NF] prevent indexed functions as bindings (#7163)
Browse files Browse the repository at this point in the history
- fixes ticket #6267
 - if a scalarized binding would result in an indexed function -> don't do it!
  • Loading branch information
kabdelhak committed Mar 2, 2021
1 parent ed8ef0a commit b7f7e9d
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 36 deletions.
18 changes: 18 additions & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFBinding.mo
Expand Up @@ -726,5 +726,23 @@ public
end match;
end containsExp;

function setAttr
"sets a specific attribute value and adds it if it does not exist"
input output list<tuple<String, Binding>> ty_attr;
input String attr_name;
input Binding attr_value;
algorithm
ty_attr := match ty_attr
local
tuple<String, Binding> at;
list<tuple<String, Binding>> rest;
String name;
case (name, _ ) :: rest guard(name == attr_name) then (attr_name, attr_value) :: rest;
case at :: rest then at :: setAttr(rest, attr_name, attr_value);
case {} then {(attr_name, attr_value)};
end match;
end setAttr;


annotation(__OpenModelica_Interface="frontend");
end NFBinding;
18 changes: 18 additions & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFExpressionIterator.mo
Expand Up @@ -35,6 +35,7 @@ protected
import ComponentRef = NFComponentRef;
import NFInstNode.InstNode;
import ExpandExp = NFExpandExp;
import SimplifyExp = NFSimplifyExp;

public
import Expression = NFExpression;
Expand Down Expand Up @@ -228,6 +229,23 @@ public
expl := listReverse(expl);
end toList;

function isSubscriptedArrayCall
"only checks first slice for a subscripted call and assumes it holds for all of them"
input ExpressionIterator iterator;
input Boolean trySimplify = true;
output Boolean b;
algorithm
b := match iterator
local
Expression call;
case ARRAY_ITERATOR(slice = Expression.SUBSCRIPTED_EXP(exp = call as Expression.CALL())::_)
then (not trySimplify) or Expression.isCall(SimplifyExp.simplify(call));
case ARRAY_ITERATOR(slice = Expression.BINDING_EXP(exp = Expression.SUBSCRIPTED_EXP(exp = call as Expression.CALL()))::_)
then (not trySimplify) or Expression.isCall(SimplifyExp.simplify(call));
else false;
end match;
end isSubscriptedArrayCall;

protected
function nextArraySlice
input output list<Expression> array;
Expand Down
3 changes: 1 addition & 2 deletions OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo
Expand Up @@ -492,8 +492,7 @@ algorithm
// Set fixed = false for parameters that are part of a record instance whose
// binding couldn't be split and was moved to an initial equation.
if unfix then
ty_attrs := List.removeOnTrue("fixed", isTypeAttributeNamed, ty_attrs);
ty_attrs := ("fixed", Binding.FLAT_BINDING(Expression.BOOLEAN(false), Variability.CONSTANT)) :: ty_attrs;
ty_attrs := Binding.setAttr(ty_attrs, "fixed", Binding.FLAT_BINDING(Expression.BOOLEAN(false), Variability.CONSTANT));
end if;

vars := Variable.VARIABLE(name, ty, binding, visibility, comp_attr, ty_attrs, children, cmt, info) :: vars;
Expand Down
40 changes: 27 additions & 13 deletions OMCompiler/Compiler/NFFrontEnd/NFScalarize.mo
Expand Up @@ -61,17 +61,17 @@ function scalarize
input output FlatModel flatModel;
protected
list<Variable> vars = {};
list<Equation> eql = {}, ieql = {};
list<Equation> eql = {}, ieql = {}, neql = {};
list<Algorithm> alg = {}, ialg = {};
algorithm
for c in flatModel.variables loop
vars := scalarizeVariable(c, vars);
(vars, neql) := scalarizeVariable(c, vars, neql);
end for;

flatModel.variables := listReverseInPlace(vars);
flatModel.equations := Equation.mapExpList(flatModel.equations, expandComplexCref);
flatModel.equations := scalarizeEquations(flatModel.equations);
flatModel.initialEquations := Equation.mapExpList(flatModel.initialEquations, expandComplexCref);
flatModel.initialEquations := Equation.mapExpList(listAppend(flatModel.initialEquations, neql), expandComplexCref);
flatModel.initialEquations := scalarizeEquations(flatModel.initialEquations);
flatModel.algorithms := list(scalarizeAlgorithm(a) for a in flatModel.algorithms);
flatModel.initialAlgorithms := list(scalarizeAlgorithm(a) for a in flatModel.initialAlgorithms);
Expand All @@ -83,10 +83,11 @@ protected
function scalarizeVariable
input Variable var;
input output list<Variable> vars;
input output list<Equation> eqns;
protected
ComponentRef name;
Binding binding;
Type ty;
Type ty, elem_ty;
Visibility vis;
Component.Attributes attr;
list<tuple<String, Binding>> ty_attr;
Expand All @@ -109,23 +110,36 @@ algorithm
return;
end if;

ty := Type.arrayElementType(ty);
elem_ty := Type.arrayElementType(ty);
(ty_attr_names, ty_attr_iters) := scalarizeTypeAttributes(ty_attr);

if Binding.isBound(binding) then
binding_iter := ExpressionIterator.fromExp(expandComplexCref(Binding.getTypedExp(binding)));
bind_var := Binding.variability(binding);

for cr in crefs loop
(binding_iter, exp) := ExpressionIterator.next(binding_iter);
binding := Binding.FLAT_BINDING(exp, bind_var);
ty_attr := nextTypeAttributes(ty_attr_names, ty_attr_iters);
vars := Variable.VARIABLE(cr, ty, binding, vis, attr, ty_attr, {}, cmt, info) :: vars;
end for;
// if the scalarized binding would result in an indexed call e.g. f()[1] then don't do it!
// fixes ticket #6267
if ExpressionIterator.isSubscriptedArrayCall(binding_iter) then
// create an initial equation instead
eqns := Equation.ARRAY_EQUALITY(Expression.CREF(ty, var.name), Binding.getTypedExp(binding), ty,
ElementSource.createElementSource(info)) :: eqns;
for cr in crefs loop
// unfix all scalar variables because it has to be solved in the initial equation instead
ty_attr := nextTypeAttributes(ty_attr_names, ty_attr_iters);
ty_attr := Binding.setAttr(ty_attr, "fixed", Binding.FLAT_BINDING(Expression.BOOLEAN(false), Variability.CONSTANT));
vars := Variable.VARIABLE(cr, elem_ty, NFBinding.EMPTY_BINDING, vis, attr, ty_attr, {}, cmt, info) :: vars;
end for;
else
for cr in crefs loop
(binding_iter, exp) := ExpressionIterator.next(binding_iter);
binding := Binding.FLAT_BINDING(exp, bind_var);
ty_attr := nextTypeAttributes(ty_attr_names, ty_attr_iters);
vars := Variable.VARIABLE(cr, elem_ty, binding, vis, attr, ty_attr, {}, cmt, info) :: vars;
end for;
end if;
else
for cr in crefs loop
ty_attr := nextTypeAttributes(ty_attr_names, ty_attr_iters);
vars := Variable.VARIABLE(cr, ty, binding, vis, attr, ty_attr, {}, cmt, info) :: vars;
vars := Variable.VARIABLE(cr, elem_ty, binding, vis, attr, ty_attr, {}, cmt, info) :: vars;
end for;
end if;
else
Expand Down
56 changes: 35 additions & 21 deletions testsuite/openmodelica/xml/XmlDumpComment.mos
Expand Up @@ -13345,9 +13345,7 @@ readFile("Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.xml");
// </unit>
// </attributesValues>
// </variable>
// <variable id=\"595\" name=\"body.z_a_start[1]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"true\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Initial values of angular acceleration z_a = der(w_a), i.e., time derivative of angular velocity resolved in frame_a\">
// <bindExpression string=\"body.z_0_start[1]\">
// </bindExpression>
// <variable id=\"595\" name=\"body.z_a_start[1]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"false\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Initial values of angular acceleration z_a = der(w_a), i.e., time derivative of angular velocity resolved in frame_a\">
// <classesNames>
// <element>
// Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum
Expand All @@ -13361,11 +13359,11 @@ readFile("Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.xml");
// </quantity>
// <unit string=\"&quot;rad/s2&quot;\">
// </unit>
// <fixed string=\"false\">
// </fixed>
// </attributesValues>
// </variable>
// <variable id=\"596\" name=\"body.z_a_start[2]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"true\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Initial values of angular acceleration z_a = der(w_a), i.e., time derivative of angular velocity resolved in frame_a\">
// <bindExpression string=\"body.z_0_start[2]\">
// </bindExpression>
// <variable id=\"596\" name=\"body.z_a_start[2]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"false\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Initial values of angular acceleration z_a = der(w_a), i.e., time derivative of angular velocity resolved in frame_a\">
// <classesNames>
// <element>
// Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum
Expand All @@ -13379,11 +13377,11 @@ readFile("Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.xml");
// </quantity>
// <unit string=\"&quot;rad/s2&quot;\">
// </unit>
// <fixed string=\"false\">
// </fixed>
// </attributesValues>
// </variable>
// <variable id=\"597\" name=\"body.z_a_start[3]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"true\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Initial values of angular acceleration z_a = der(w_a), i.e., time derivative of angular velocity resolved in frame_a\">
// <bindExpression string=\"body.z_0_start[3]\">
// </bindExpression>
// <variable id=\"597\" name=\"body.z_a_start[3]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"false\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Initial values of angular acceleration z_a = der(w_a), i.e., time derivative of angular velocity resolved in frame_a\">
// <classesNames>
// <element>
// Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum
Expand All @@ -13397,11 +13395,11 @@ readFile("Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.xml");
// </quantity>
// <unit string=\"&quot;rad/s2&quot;\">
// </unit>
// <fixed string=\"false\">
// </fixed>
// </attributesValues>
// </variable>
// <variable id=\"598\" name=\"body.Q_start[1]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"true\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Quaternion orientation object from world frame to frame_a at initial time\">
// <bindExpression string=\"Modelica.Mechanics.MultiBody.Frames.Quaternions.from_T(body.R_start.T, {0.0, 0.0, 0.0, 1.0})[1]\">
// </bindExpression>
// <variable id=\"598\" name=\"body.Q_start[1]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"false\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Quaternion orientation object from world frame to frame_a at initial time\">
// <classesNames>
// <element>
// Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum
Expand All @@ -13410,10 +13408,12 @@ readFile("Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.xml");
// Modelica.Mechanics.MultiBody.Parts.Body
// </element>
// </classesNames>
// <attributesValues>
// <fixed string=\"false\">
// </fixed>
// </attributesValues>
// </variable>
// <variable id=\"599\" name=\"body.Q_start[2]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"true\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Quaternion orientation object from world frame to frame_a at initial time\">
// <bindExpression string=\"Modelica.Mechanics.MultiBody.Frames.Quaternions.from_T(body.R_start.T, {0.0, 0.0, 0.0, 1.0})[2]\">
// </bindExpression>
// <variable id=\"599\" name=\"body.Q_start[2]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"false\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Quaternion orientation object from world frame to frame_a at initial time\">
// <classesNames>
// <element>
// Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum
Expand All @@ -13422,10 +13422,12 @@ readFile("Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.xml");
// Modelica.Mechanics.MultiBody.Parts.Body
// </element>
// </classesNames>
// <attributesValues>
// <fixed string=\"false\">
// </fixed>
// </attributesValues>
// </variable>
// <variable id=\"600\" name=\"body.Q_start[3]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"true\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Quaternion orientation object from world frame to frame_a at initial time\">
// <bindExpression string=\"Modelica.Mechanics.MultiBody.Frames.Quaternions.from_T(body.R_start.T, {0.0, 0.0, 0.0, 1.0})[3]\">
// </bindExpression>
// <variable id=\"600\" name=\"body.Q_start[3]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"false\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Quaternion orientation object from world frame to frame_a at initial time\">
// <classesNames>
// <element>
// Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum
Expand All @@ -13434,10 +13436,12 @@ readFile("Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.xml");
// Modelica.Mechanics.MultiBody.Parts.Body
// </element>
// </classesNames>
// <attributesValues>
// <fixed string=\"false\">
// </fixed>
// </attributesValues>
// </variable>
// <variable id=\"601\" name=\"body.Q_start[4]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"true\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Quaternion orientation object from world frame to frame_a at initial time\">
// <bindExpression string=\"Modelica.Mechanics.MultiBody.Frames.Quaternions.from_T(body.R_start.T, {0.0, 0.0, 0.0, 1.0})[4]\">
// </bindExpression>
// <variable id=\"601\" name=\"body.Q_start[4]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"false\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Quaternion orientation object from world frame to frame_a at initial time\">
// <classesNames>
// <element>
// Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum
Expand All @@ -13446,6 +13450,10 @@ readFile("Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.xml");
// Modelica.Mechanics.MultiBody.Parts.Body
// </element>
// </classesNames>
// <attributesValues>
// <fixed string=\"false\">
// </fixed>
// </attributesValues>
// </variable>
// <variable id=\"602\" name=\"body.phi_start[1]\" variability=\"parameter\" direction=\"none\" type=\"Real\" fixed=\"true\" flow=\"NonConnector\" stream=\"NonStreamConnector\" comment=\"Potential angle states at initial time\">
// <bindExpression string=\"body.angles_start[1]\">
Expand Down Expand Up @@ -21540,6 +21548,12 @@ readFile("Modelica.Mechanics.MultiBody.Examples.Elementary.Pendulum.xml");
// <equation id=\"82\">damper.phi_rel = rev.phi - rev.fixed.phi0
// </equation>
// </equations>
// <initialEquations dimension=\"2\">
// <arrayOfEquations id=\"1\">body.Q_start = Modelica.Mechanics.MultiBody.Frames.Quaternions.from_T({{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}, {0.0, 0.0, 0.0, 1.0})
// </arrayOfEquations>
// <arrayOfEquations id=\"2\">body.z_a_start = {body.z_0_start[1], body.z_0_start[2], body.z_0_start[3]}
// </arrayOfEquations>
// </initialEquations>
// <functions>
// <function name=\"Modelica.Math.Vectors.length\">
// <ModelicaImplementation>function(v :: array(Real)[:]) =&gt; RealModelica.Math.Vectors.lengthfunction Modelica.Math.Vectors.length &quot;Inline before index reduction&quot; &quot;Return length of a vector (better as norm(), if further symbolic processing is performed)&quot;
Expand Down

0 comments on commit b7f7e9d

Please sign in to comment.