Skip to content

Commit

Permalink
[NB] inline tuple equations (#11470)
Browse files Browse the repository at this point in the history
* [NB] inline tuple equations

 - update lowering of tuple equations
 - inline tuple equations created by function alias module or similar

* [NB] update tuple handling to handle wild cards

* [testsuite] added new tuple test to new backend
  • Loading branch information
kabdelhak committed Oct 27, 2023
1 parent b34014d commit 4d4dbc7
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 32 deletions.
24 changes: 6 additions & 18 deletions OMCompiler/Compiler/NBackEnd/Classes/NBackendDAE.mo
Original file line number Diff line number Diff line change
Expand Up @@ -730,26 +730,14 @@ protected
attr := lowerEquationAttributes(ty, init);
then {Pointer.create(BEquation.ARRAY_EQUATION(ty, lhs, rhs, source, attr, Type.complexSize(ty)))};

// sometimes regular equalities are array equations aswell. Need to update frontend?
case FEquation.EQUALITY(lhs = lhs, rhs = rhs, ty = ty, source = source)
guard(Type.isArray(ty)) algorithm
attr := lowerEquationAttributes(ty, init);
then {Pointer.create(BEquation.ARRAY_EQUATION(ty, lhs, rhs, source, attr, Type.complexSize(ty)))};

case FEquation.EQUALITY(lhs = lhs, rhs = rhs, ty = ty, source = source) algorithm
attr := lowerEquationAttributes(ty, init);
if Type.isComplex(ty) then
try
SOME(rec_size) := Type.complexSize(ty);
else
Error.addMessage(Error.COMPILER_WARNING,{getInstanceName()
+ ": could not determine complex type size of \n" + FEquation.toString(frontend_equation)});
fail();
end try;
result := {Pointer.create(BEquation.RECORD_EQUATION(ty, lhs, rhs, source, attr, rec_size))};
else
result := {Pointer.create(BEquation.SCALAR_EQUATION(ty, lhs, rhs, source, attr))};
end if;
result := match ty
case Type.ARRAY() then {Pointer.create(BEquation.ARRAY_EQUATION(ty, lhs, rhs, source, attr, Type.complexSize(ty)))};
case Type.COMPLEX() then {Pointer.create(BEquation.RECORD_EQUATION(ty, lhs, rhs, source, attr, Type.sizeOf(ty)))};
case Type.TUPLE() then {Pointer.create(BEquation.RECORD_EQUATION(ty, lhs, rhs, source, attr, Type.sizeOf(ty)))};
else {Pointer.create(BEquation.SCALAR_EQUATION(ty, lhs, rhs, source, attr))};
end match;
then result;

case FEquation.FOR(range = SOME(range)) algorithm
Expand Down
14 changes: 10 additions & 4 deletions OMCompiler/Compiler/NBackEnd/Modules/2_Pre/NBFunctionAlias.mo
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ protected
Type ty;
Call_Aux aux;
Option<Call_Aux> aux_opt;
Expression new_exp, elem;
Expression new_exp, sub_exp;
list<ComponentRef> names;

case Expression.CALL() guard(checkCallReplacement(exp.call)) algorithm
Expand Down Expand Up @@ -381,11 +381,17 @@ protected
UnorderedMap.add(id, aux, map);
then new_exp;

// remove tuple expressions that occur when using a function only for its first output
// remove tuple expressions that occur when using a function only for one output
// y = fun(x)[1] where fun() has multiple outputs
// we create y = ($FUN1, $FUN2)[1] and simplify to y = $FUN1
case Expression.TUPLE_ELEMENT(tupleExp = Expression.TUPLE(elements = elem :: _), index = 1)
then elem;
case Expression.TUPLE_ELEMENT(tupleExp = sub_exp as Expression.TUPLE()) algorithm
if exp.index > listLength(sub_exp.elements) then
Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to get subscripted tuple element: " + Expression.toString(exp)});
fail();
else
new_exp := listGet(sub_exp.elements, exp.index);
end if;
then new_exp;

// do nothing if not function call or inlineable
else exp;
Expand Down
87 changes: 77 additions & 10 deletions OMCompiler/Compiler/NBackEnd/Modules/2_Pre/NBInline.mo
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ protected
import NFFunction.Function;
import NFFlatten.FunctionTree;
import Statement = NFStatement;
import Type = NFType;

// NB imports
import Module = NBModule;
Expand Down Expand Up @@ -154,7 +155,7 @@ protected
eqData := Replacements.replaceFunctions(eqData, replacements);
// replace record constucters after functions because record operator
// functions will produce record constructors once inlined
eqData := inlineRecords(eqData, VarData.getVariables(varData));
eqData := inlineRecordsTuples(eqData, VarData.getVariables(varData));
end inline;

function collectInlineFunctions
Expand All @@ -171,16 +172,18 @@ protected
end if;
end collectInlineFunctions;

function inlineRecords
function inlineRecordsTuples
input output EqData eqData;
input VariablePointers variables;
protected
Pointer<list<Pointer<Equation>>> record_eqns = Pointer.create({});
Pointer<Integer> index = EqData.getUniqueIndex(eqData);
Pointer<list<Pointer<Equation>>> new_eqns = Pointer.create({});
algorithm
eqData := EqData.map(eqData, function inlineRecordEquation(variables = variables, record_eqns = record_eqns, index = EqData.getUniqueIndex(eqData)));
eqData := EqData.addUntypedList(eqData, Pointer.access(record_eqns), false);
eqData := EqData.map(eqData, function inlineRecordEquation(variables = variables, record_eqns = new_eqns, index = index));
eqData := EqData.map(eqData, function inlineTupleEquation(tuple_eqns = new_eqns, index = index));
eqData := EqData.addUntypedList(eqData, Pointer.access(new_eqns), false);
eqData := EqData.compress(eqData);
end inlineRecords;
end inlineRecordsTuples;

function inlineRecordEquation
"tries to inline a record equation. Removes the old equation by making it a dummy
Expand All @@ -201,7 +204,7 @@ protected
case Equation.ARRAY_EQUATION(lhs = Expression.CREF(), rhs = Expression.CREF()) then eqn;

// try to inline other record equations. try catch to be sure to not discard
case Equation.RECORD_EQUATION() algorithm
case Equation.RECORD_EQUATION(ty = Type.COMPLEX()) algorithm
try
if Flags.isSet(Flags.DUMPBACKENDINLINE) then print("[" + getInstanceName() + "] Inlining: " + Equation.toString(eqn) + "\n"); end if;
new_eqn := inlineRecordEquationWork(eqn.lhs, eqn.rhs, eqn.attr, eqn.source, eqn.recordSize, variables, record_eqns, index);
Expand All @@ -215,9 +218,7 @@ protected
// only if record size is not NONE()
case Equation.ARRAY_EQUATION(recordSize = SOME(size)) algorithm
try
if Flags.isSet(Flags.DUMPBACKENDINLINE) then
print("[" + getInstanceName() + "] Inlining: " + Equation.toString(eqn) + "\n");
end if;
if Flags.isSet(Flags.DUMPBACKENDINLINE) then print("[" + getInstanceName() + "] Inlining: " + Equation.toString(eqn) + "\n"); end if;
new_eqn := inlineRecordEquationWork(eqn.lhs, eqn.rhs, eqn.attr, eqn.source, size, variables, record_eqns, index);
else
// inlining failed, keep old equation
Expand Down Expand Up @@ -309,6 +310,72 @@ protected
end match;
end inlineRecordConstructorElements;

function inlineTupleEquation
"inlines equations of the form TPL1 = TPL2 which is not modelica standard but can be created
by the function alias module and need to be removed afterwards"
input output Equation eqn;
input Pointer<Integer> index;
input Pointer<list<Pointer<Equation>>> tuple_eqns;
algorithm
eqn := match eqn
local
list<Pointer<Equation>> eqns;
list<Expression> lhs_elems, rhs_elems;
Expression lhs, rhs;
Pointer<Equation> tmp_eqn;
Equation new_eqn;

case Equation.RECORD_EQUATION() algorithm
lhs_elems := getElementList(eqn.lhs);
rhs_elems := getElementList(eqn.rhs);
if not listEmpty(lhs_elems) and listLength(lhs_elems) == listLength(rhs_elems) then
if Flags.isSet(Flags.DUMPBACKENDINLINE) then
print("[" + getInstanceName() + "] Inlining: " + Equation.toString(eqn) + "\n");
end if;
eqns := Pointer.access(tuple_eqns);
for tpl in List.zip(lhs_elems, rhs_elems) loop
(lhs, rhs) := tpl;
if not (Expression.isWildCref(lhs) or Expression.isWildCref(rhs)) then
tmp_eqn := Equation.makeAssignment(lhs, rhs, index, NBVariable.AUXILIARY_STR, Iterator.EMPTY(), eqn.attr);
if Flags.isSet(Flags.DUMPBACKENDINLINE) then
print("-- Result: " + Equation.toString(Pointer.access(tmp_eqn)) + "\n");
end if;
eqns := tmp_eqn :: eqns;
end if;
end for;
Pointer.update(tuple_eqns, eqns);
new_eqn := Equation.DUMMY_EQUATION();
else
new_eqn := eqn;
end if;
then new_eqn;
else eqn;
end match;
end inlineTupleEquation;

function getElementList
input Expression exp;
output list<Expression> elements;
algorithm
elements := match exp
local
Expression sub_exp, elem;

case Expression.TUPLE() then exp.elements;

case Expression.TUPLE_ELEMENT(tupleExp = sub_exp as Expression.TUPLE()) algorithm
if exp.index > listLength(sub_exp.elements) then
Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed to get subscripted tuple element: " + Expression.toString(exp)});
fail();
else
elem := listGet(sub_exp.elements, exp.index);
end if;
then {elem};

else {};
end match;
end getElementList;


annotation(__OpenModelica_Interface="backend");
end NBInline;
1 change: 1 addition & 0 deletions testsuite/simulation/modelica/NBackend/records/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ TEST = ../../../../rtest -v
TESTFILES = \
simple_record.mos \
record_inlining.mos \
simple_tuple.mos \

# test that currently fail. Move up when fixed.
# Run make failingtest
Expand Down
124 changes: 124 additions & 0 deletions testsuite/simulation/modelica/NBackend/records/simple_tuple.mos
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// name: simple_tuple
// keywords: NewBackend
// status: correct

loadString("
function some_func
input Real a;
input Real b;
output Real x;
output Real y;
algorithm
x := a+b;
y := a*b;
end some_func;

model simple_tuple
Real a, b, x, y, z1, z2, z3;
equation
a = sin(time);
b = cos(time);
(x, y) = some_func(a, b);
z1 = some_func(x, y);
(z2, ) = some_func(x, y);
(, z3) = some_func(x, y);
end simple_tuple;
"); getErrorString();

setCommandLineOptions("--newBackend -d=dumpBackendInline,dumprepl,dumpCSE"); getErrorString();

simulate(simple_tuple); getErrorString();

// Result:
// true
// ""
// true
// ""
// Simulation Function Alias
// ---------------------------
// sin(time) ......... $FUN_1
// cos(time) ......... $FUN_2
// some_func(a, b) ... ($FUN_3, $FUN_4)
// some_func(x, y) ... ($FUN_5, $FUN_6)
//
// Initial Function Alias
// ------------------------
//
//
// [dumpBackendInline] Inlining operatations for: {NORMAL, BUILTIN_EARLY, EARLY, DEFAULT}
// ****************************************************************************************
// [NBInline.inlineTupleEquation] Inlining: [TUPL] (2) (x, y) = ($FUN_3, $FUN_4) ($RES_SIM_3)
// -- Result: [SCAL] (1) x = $FUN_3 ($RES_$AUX_10)
// -- Result: [SCAL] (1) y = $FUN_4 ($RES_$AUX_11)
// [NBInline.inlineTupleEquation] Inlining: [TUPL] (2) (z2, _) = ($FUN_5, $FUN_6) ($RES_SIM_1)
// -- Result: [SCAL] (1) z2 = $FUN_5 ($RES_$AUX_12)
// [NBInline.inlineTupleEquation] Inlining: [TUPL] (2) (_, z3) = ($FUN_5, $FUN_6) ($RES_SIM_0)
// -- Result: [SCAL] (1) z3 = $FUN_6 ($RES_$AUX_13)
//
// ==========================
// [dumprepl] Alias Sets:
// ==========================
//
// Alias Set 1:
// **************
// <No Constant/Parameter Binding>
// ### Set Equations:
// [SCAL] (1) z3 = $FUN_6 ($RES_$AUX_13)
//
// Alias Set 2:
// **************
// <No Constant/Parameter Binding>
// ### Set Equations:
// [SCAL] (1) y = $FUN_4 ($RES_$AUX_11)
//
// Alias Set 3:
// **************
// <No Constant/Parameter Binding>
// ### Set Equations:
// [SCAL] (1) x = $FUN_3 ($RES_$AUX_10)
//
// Alias Set 4:
// **************
// <No Constant/Parameter Binding>
// ### Set Equations:
// [SCAL] (1) z2 = $FUN_5 ($RES_$AUX_12)
// [SCAL] (1) z1 = $FUN_5 ($RES_SIM_2)
//
// Alias Set 5:
// **************
// <No Constant/Parameter Binding>
// ### Set Equations:
// [SCAL] (1) b = $FUN_2 ($RES_SIM_4)
//
// Alias Set 6:
// **************
// <No Constant/Parameter Binding>
// ### Set Equations:
// [SCAL] (1) a = $FUN_1 ($RES_SIM_5)
//
// [dumprepl] Constant Replacements:
// ***********************************
// [dumprepl] Trivial Alias Replacements:
// ****************************************
// $FUN_6 ==> z3
// $FUN_4 ==> y
// $FUN_3 ==> x
// $FUN_5 ==> z2
// z1 ==> z2
// $FUN_2 ==> b
// $FUN_1 ==> a
// [dumprepl] Nontrivial Alias Replacements:
// *******************************************
//
// [dumpBackendInline] Inlining operatations for: {AFTER_INDEX_RED}
// ******************************************************************
//
// record SimulationResult
// resultFile = "simple_tuple_res.mat",
// simulationOptions = "startTime = 0.0, stopTime = 1.0, numberOfIntervals = 500, tolerance = 1e-6, method = 'dassl', fileNamePrefix = 'simple_tuple', options = '', outputFormat = 'mat', variableFilter = '.*', cflags = '', simflags = ''",
// messages = "LOG_SUCCESS | info | The initialization finished successfully without homotopy method.
// LOG_SUCCESS | info | The simulation finished successfully.
// "
// end SimulationResult;
// ""
// endResult

0 comments on commit 4d4dbc7

Please sign in to comment.