Skip to content

Commit

Permalink
Fix unbound constant bindings in initialization system (#9247)
Browse files Browse the repository at this point in the history
* Find record types from globalKnownVars
* Initial system constant record bindings fixed
* Test case added
* Sort constant arrays/matrices in collapseArrayBindings
* Better error messages and debug prints
  • Loading branch information
AnHeuermann committed Jul 19, 2022
1 parent cdafba5 commit f2e0b81
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 76 deletions.
231 changes: 158 additions & 73 deletions OMCompiler/Compiler/BackEnd/BackendDAECreate.mo
Expand Up @@ -85,28 +85,6 @@ import VarTransform;
import Vectorization;
import ZeroCrossings;

protected type Functiontuple = tuple<Option<DAE.FunctionTree>,list<DAE.InlineType>>;

protected type ArrayBindingList = list<tuple<list<Integer>,DAE.Exp>>;

function printArrayBindingList
input ArrayBindingList arrayBindingList;
output String str = "";
protected
list<Integer> subscriptLst;
DAE.Exp bindingExp;
algorithm
for tpl in arrayBindingList loop
(subscriptLst, bindingExp) := tpl;
str := str + "[";
for subscript in subscriptLst loop
str := str + intString(subscript) + " ";
end for;
str := str + "]";
str := str + " : " + ExpressionDump.dumpExpStr(bindingExp, 0);
end for;
end printArrayBindingList;

public function lower "This function translates a DAE, which is the result from instantiating a
class, into a more precise form, called BackendDAE.BackendDAE defined in this module.
The BackendDAE.BackendDAE representation splits the DAE into equations and variables
Expand Down Expand Up @@ -139,9 +117,6 @@ protected
String neqStr, nvarStr;
Integer varSize, eqnSize, numCheckpoints;
BackendDAE.EqSystem syst;
UnorderedMap<DAE.ComponentRef, DAE.Type> map;
UnorderedMap<DAE.ComponentRef, ArrayBindingList> arrayMap;
Boolean debug = false;
algorithm
numCheckpoints:=ErrorExt.getNumCheckpoints();
try
Expand All @@ -156,44 +131,6 @@ algorithm
(varlst, globalKnownVarLst, extvarlst, eqns, reqns, ieqns, constrs, clsAttrs, extObjCls, aliaseqns, _) :=
lower2(listReverse(elems), functionTree, HashTableExpToExp.emptyHashTable());

// ticket #9036
// propagate record bindings from attributes to their parent record types in all crefs of all equations O(n)

// 1. collect all possible record types from eqns
// (the frontend does not keep correct types at the variables so they have to be grabbed from eqns beforehand
// i don't like it but thats how it is).
map := UnorderedMap.new<DAE.Type>(ComponentReference.hashComponentRefMod, ComponentReference.crefEqual);
eqns := List.map(eqns, function collectRecordTypesEqn(map = map));
reqns := List.map(reqns, function collectRecordTypesEqn(map = map));
ieqns := List.map(ieqns, function collectRecordTypesEqn(map = map));

if (debug) then
print(UnorderedMap.toString(map, ComponentReference.printComponentRefStr, Types.printTypeStr) + "\n");
print("-------------------\n\n");
end if;

// 2. collect bindings from variables and update in types
// (ToDo: update the types?)
arrayMap := UnorderedMap.new<ArrayBindingList>(ComponentReference.hashComponentRefMod, ComponentReference.crefEqual);

_ := List.map(varlst, function collectRecordElementBindings(map = map, arrayMap = arrayMap));
_ := List.map(globalKnownVarLst, function collectRecordElementBindings(map = map, arrayMap = arrayMap));
_ := List.map(extvarlst, function collectRecordElementBindings(map = map, arrayMap = arrayMap));

map := collapseArrayBindings(arrayMap, map);

if (debug) then
print("----------arrayMap--\n\n");
print(UnorderedMap.toString(arrayMap, ComponentReference.printComponentRefStr, printArrayBindingList) + "\n");
print("----arrayMap-----\n\n");
print(UnorderedMap.toString(map, ComponentReference.printComponentRefStr, Types.printTypeStr) + "\n");
end if;

// 3. replace the types in eqns
eqns := List.map(eqns, function updateRecordTypesEqn(map = map));
reqns := List.map(reqns, function updateRecordTypesEqn(map = map));
ieqns := List.map(ieqns, function updateRecordTypesEqn(map = map));

vars := BackendVariable.listVar(varlst);
globalKnownVars := BackendVariable.listVar(globalKnownVarLst);
localKnownVars := BackendVariable.emptyVars();
Expand All @@ -208,6 +145,8 @@ algorithm
(ieqns, eqns, reqns, extAliasVars, globalKnownVars, extVars) := getExternalObjectAlias(ieqns, eqns, reqns, globalKnownVars, extVars);
aliasVars := BackendVariable.addVariables(extAliasVars,aliasVars);

(globalKnownVarLst, eqns, reqns, ieqns) := patchRecordBindings(varlst, extvarlst, globalKnownVarLst, eqns, reqns, ieqns);

vars_1 := detectImplicitDiscrete(vars, globalKnownVars, eqns);
eqnarr := BackendEquation.listEquation(eqns);
reqnarr := BackendEquation.listEquation(reqns);
Expand Down Expand Up @@ -253,6 +192,74 @@ algorithm
fail();
end lower;

protected type Functiontuple = tuple<Option<DAE.FunctionTree>,list<DAE.InlineType>>;

protected type ArrayBindingList = list<tuple<list<Integer>,DAE.Exp>>;

function printArrayBindingList
input ArrayBindingList arrayBindingList;
output String str = "";
protected
list<Integer> subscriptLst;
DAE.Exp bindingExp;
algorithm
for tpl in arrayBindingList loop
(subscriptLst, bindingExp) := tpl;
str := str + "[";
for subscript in subscriptLst loop
str := str + intString(subscript) + " ";
end for;
str := str + "]";
str := str + " : " + ExpressionDump.dumpExpStr(bindingExp, 0);
end for;
end printArrayBindingList;

public function patchRecordBindings
"Propagate record bindings from attributes to their parent record types in all crefs of all equations O(n) (?)
For ticket #9036."
input list<BackendDAE.Var> varlst;
input list<BackendDAE.Var> extvarlst;
input output list<BackendDAE.Var> globalKnownVarLst;
input output list<BackendDAE.Equation> eqns;
input output list<BackendDAE.Equation> reqns;
input output list<BackendDAE.Equation> ieqns;
protected
UnorderedMap<DAE.ComponentRef, DAE.Type> map;
UnorderedMap<DAE.ComponentRef, ArrayBindingList> arrayMap;
Boolean debug = false;
algorithm
// 1. Collect all possible record types from equations and globalKnownVars
// (the frontend does not keep correct types at the variables so they have to be grabbed from eqns beforehand
// I don't like it but thats how it is).
map := UnorderedMap.new<DAE.Type>(ComponentReference.hashComponentRefMod, ComponentReference.crefEqual);
collectRecordTypesVarLst(map, globalKnownVarLst);
eqns := List.map(eqns, function collectRecordTypesEqn(map = map));
reqns := List.map(reqns, function collectRecordTypesEqn(map = map));
ieqns := List.map(ieqns, function collectRecordTypesEqn(map = map));

// 2. Collect bindings from variables and update in types
arrayMap := UnorderedMap.new<ArrayBindingList>(ComponentReference.hashComponentRefMod, ComponentReference.crefEqual);

_ := List.map(varlst, function collectRecordElementBindings(map = map, arrayMap = arrayMap));
_ := List.map(globalKnownVarLst, function collectRecordElementBindings(map = map, arrayMap = arrayMap));
_ := List.map(extvarlst, function collectRecordElementBindings(map = map, arrayMap = arrayMap));

map := collapseArrayBindings(arrayMap, map);

if (debug) then
print("patchRecordBindings arrayMap:\n");
print(UnorderedMap.toString(arrayMap, ComponentReference.printComponentRefStr, printArrayBindingList) + "\n");
print("\npatchRecordBindings map\n");
print(UnorderedMap.toString(map, ComponentReference.printComponentRefStr, Types.printTypeStr) + "\n\n");
end if;

// 3. Replace the types in equations and globalKnownVars
globalKnownVarLst := updateRecordTypesVarLst(map, globalKnownVarLst);
eqns := List.map(eqns, function updateRecordTypesEqn(map = map));
reqns := List.map(reqns, function updateRecordTypesEqn(map = map));
ieqns := List.map(ieqns, function updateRecordTypesEqn(map = map));
end patchRecordBindings;

protected function collectRecordElementBindings
input BackendDAE.Var var;
input UnorderedMap<DAE.ComponentRef, DAE.Type> map;
Expand Down Expand Up @@ -319,22 +326,41 @@ algorithm
end if;
end updateConstantRecordElementBinding;

protected function collectRecordTypesEqn
input output BackendDAE.Equation eqn;
protected function collectRecordTypesVarLst
input UnorderedMap<DAE.ComponentRef, DAE.Type> map;
input list<BackendDAE.Var> varLst;
algorithm
(eqn, _) := BackendEquation.traverseExpsOfEquation(eqn, function Expression.traverseExpTopDown(func=collectRecordTypesExp), map);
end collectRecordTypesEqn;
for var in varLst loop
collectRecordTypesVar(map, var);
end for;
end collectRecordTypesVarLst;

protected function updateRecordTypesEqn
protected function collectRecordTypesVar
"Collect record types from variable binding.
Add record tpye to map."
input UnorderedMap<DAE.ComponentRef, DAE.Type> map;
input BackendDAE.Var var;
algorithm
() := match var.bindExp
local
DAE.Exp exp;
case SOME(exp) algorithm
_ := Expression.traverseExpTopDown(exp, collectRecordTypesExp, map);
then();
else();
end match;
end collectRecordTypesVar;

protected function collectRecordTypesEqn
input output BackendDAE.Equation eqn;
input UnorderedMap<DAE.ComponentRef, DAE.Type> map;
algorithm
(eqn, _) := BackendEquation.traverseExpsOfEquation(eqn, function Expression.traverseExpTopDown(func=updateRecordTypesExp), map);
end updateRecordTypesEqn;
(eqn, _) := BackendEquation.traverseExpsOfEquation(eqn, function Expression.traverseExpTopDown(func=collectRecordTypesExp), map);
end collectRecordTypesEqn;

protected function collectRecordTypesExp
"Collect all crefs with record type anda t least one constant record component."
"Collect all crefs with record type and at least one constant record component.
Add them to map."
input output DAE.Exp exp;
output Boolean cont;
input output UnorderedMap<DAE.ComponentRef, DAE.Type> map;
Expand All @@ -349,6 +375,13 @@ algorithm
end match;
end collectRecordTypesExp;

protected function updateRecordTypesEqn
input output BackendDAE.Equation eqn;
input UnorderedMap<DAE.ComponentRef, DAE.Type> map;
algorithm
(eqn, _) := BackendEquation.traverseExpsOfEquation(eqn, function Expression.traverseExpTopDown(func=updateRecordTypesExp), map);
end updateRecordTypesEqn;

protected function updateRecordTypesExp
input output DAE.Exp exp;
output Boolean cont;
Expand All @@ -364,6 +397,40 @@ algorithm
end match;
end updateRecordTypesExp;

protected function compareArrayBindingExp
input tuple<list<Integer>,DAE.Exp> inElement1;
input tuple<list<Integer>,DAE.Exp> inElement2;
output Boolean inRes=false "True if left element is smaller or equal";
protected
list<Integer> indiceLstElem1, indiceLstElem2;
list<Integer> rest_e2;
Integer e2;
algorithm
(indiceLstElem1, _) := inElement1;
(indiceLstElem2, _) := inElement2;

if listLength(indiceLstElem1) <> listLength(indiceLstElem2) then
Error.addInternalError(getInstanceName() + " failed because lists have different lengths.", sourceInfo());
fail();
end if;

rest_e2 := indiceLstElem2;
for e1 in indiceLstElem1 loop
e2 :: rest_e2 := rest_e2;
if e1 < e2 then
inRes := true;
return;
elseif e1 > e2 then
inRes := false;
return;
end if;
end for;

// Lists are equal
inRes := true;
return;
end compareArrayBindingExp;

protected function collapseArrayBindings
input UnorderedMap<DAE.ComponentRef, ArrayBindingList> arrayMap;
input output UnorderedMap<DAE.ComponentRef, DAE.Type> map;
Expand All @@ -381,9 +448,9 @@ protected
algorithm
for pair in UnorderedMap.toList(arrayMap) loop
(cref, arrayBindingExpList) := pair;
arrayBindingExpList := List.sort(arrayBindingExpList, compareArrayBindingExp);

expLst := {};
// TODO: Sort by subscript (should be unnecessary since they are generated in order, but who knows)
for scalBind in arrayBindingExpList loop
(subscriptLst, scalarBinding) := scalBind;
expLst := scalarBinding :: expLst;
Expand All @@ -405,7 +472,9 @@ algorithm
fail();
end try;
then DAE.MATRIX(ComponentReference.crefTypeFull(cref), firstDim, matLst);
else fail();
else algorithm
Error.addInternalError(getInstanceName() + "failed. Array of dimension greater 2 not yet supported. Open a ticket about it.", sourceInfo());
then fail();
end match;

// Update binding in map
Expand All @@ -422,6 +491,22 @@ algorithm
end for;
end collapseArrayBindings;

protected function updateRecordTypesVarLst
input UnorderedMap<DAE.ComponentRef, DAE.Type> map;
input output list<BackendDAE.Var> varLst;
algorithm
varLst := list(match var.bindExp
local
DAE.Exp exp;
case SOME(exp) algorithm
(exp, _) := Expression.traverseExpTopDown(exp, updateRecordTypesExp, map);
var.bindExp := SOME(exp);
then(var);
else(var);
end match
for var in varLst);
end updateRecordTypesVarLst;

protected function getExternalObjectAlias "Checks equations if there is an alias equation for external objects.
If yes, assign alias var, replace equations, remove alias equation.
author: waurich TUD 2016-10"
Expand Down
11 changes: 10 additions & 1 deletion OMCompiler/Compiler/BackEnd/Initialization.mo
Expand Up @@ -46,13 +46,14 @@ import Util;

protected
import Array;
import BackendDAECreate;
import BackendDAEEXT;
import BackendDAEOptimize;
import BackendDAEUtil;
import BackendDump;
import BackendEquation;
import BackendVarTransform;
import BackendVariable;
import BackendVarTransform;
import BaseHashSet;
import CheckModel;
import ComponentReference;
Expand Down Expand Up @@ -94,6 +95,7 @@ protected
BackendDAE.EqSystem initsyst;
BackendDAE.EqSystems systs;
BackendDAE.EquationArray eqns, reeqns;
list<BackendDAE.Equation> eqnsLst, reeqnsLst;
BackendDAE.Shared shared;
BackendDAE.Variables initVars;
BackendDAE.Variables vars, fixvars;
Expand Down Expand Up @@ -165,6 +167,13 @@ algorithm
((eqns, reeqns)) := BackendVariable.traverseBackendDAEVars(vars, collectInitialBindings, (eqns, reeqns));
execStat("collectInitialBindings (initialization)");

// Fix types of constant components in record bindings
eqnsLst := BackendEquation.equationList(eqns);
reeqnsLst := BackendEquation.equationList(reeqns);
(_, eqnsLst, reeqnsLst, _) := BackendDAECreate.patchRecordBindings({}, {}, BackendVariable.varList(dae.shared.globalKnownVars), eqnsLst, reeqnsLst, {});
eqns := BackendEquation.listEquation(eqnsLst);
reeqns := BackendEquation.listEquation(reeqnsLst);

// scalarize variables after collecting bindings
if Flags.isSet(Flags.NF_SCALARIZE) then
vars := BackendVariable.scalarizeVariables(vars);
Expand Down
4 changes: 2 additions & 2 deletions OMCompiler/Compiler/Template/CodegenCFunctions.tpl
Expand Up @@ -5230,9 +5230,9 @@ template constVarOrDaeExp(DAE.Var var, DAE.ComponentRef cr, Context context, Tex
case DAE.TYPES_VAR(attributes = DAE.ATTR(variability = CONST()), binding = DAE.EQBOUND()) then
daeExp(binding.exp, context, &preExp, &varDecls, &auxFunction)
case DAE.TYPES_VAR(attributes = DAE.ATTR(variability = CONST()), binding = DAE.VALBOUND()) then
error(sourceInfo(), 'constVarOrDaeExp failed; Constant variable <%name%> is value bound. Not yet implemented.')
error(sourceInfo(), 'constVarOrDaeExp failed; Constant variable <%name%> is value bound. Not yet implemented')
case DAE.TYPES_VAR(attributes = DAE.ATTR(variability = CONST()), binding = DAE.UNBOUND()) then
error(sourceInfo(), 'constVarOrDaeExp failed; Constant variable <%name%> has no binding. This indicates a problem in the lowering from Frontend to old Backend.')
error(sourceInfo(), 'constVarOrDaeExp failed; Constant variable <%name%> has no binding. This indicates a problem in the lowering from Frontend to old Backend')
else
daeExp(makeCrefRecordExp(cr,var), context, &preExp, &varDecls, &auxFunction)
end constVarOrDaeExp;
Expand Down
1 change: 1 addition & 0 deletions testsuite/simulation/modelica/records/Makefile
Expand Up @@ -4,6 +4,7 @@ TESTFILES = \
ATotal.mos \
constVar1.mos \
constVar2.mos \
constVar4.mos \
InOutRecord.mos \
RecordConstructor1.mos \
TestComplexSum1.mos \
Expand Down

0 comments on commit f2e0b81

Please sign in to comment.