Skip to content

Commit

Permalink
[BE] update binary differentiation
Browse files Browse the repository at this point in the history
 - fixes ticket #6068
 - add two exponential differentiation rules
 - x^p and p^x where p is a parameter (treat just like constants)
 - add local function constants and parameters to DifferentiateData
  • Loading branch information
kabdelhak authored and adrpo committed Jul 31, 2020
1 parent b11b7ec commit 8e70607
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 0 deletions.
36 changes: 36 additions & 0 deletions OMCompiler/Compiler/BackEnd/BackendDAECreate.mo
Expand Up @@ -940,6 +940,42 @@ algorithm
end matchcontinue;
end lowerKnownVar;

public function lowerKnownVarSingle
"author: kabdelhak
lowers a single known variable (used for function bodies)"
input DAE.Element element;
output Option<BackendDAE.Var> var_opt;
algorithm
var_opt := match element
local
DAE.Element elem;
Boolean visibility;
BackendDAE.Var var;
case elem as DAE.VAR() guard(DAEUtil.isParamOrConstVarKind(elem.kind))
algorithm
visibility := DAEUtil.boolVarVisibility(elem.protection);
var := BackendDAE.VAR(
varName = elem.componentRef,
varKind = lowerKnownVarkind(elem.kind, elem.componentRef, elem.direction, elem.connectorType, elem.protection),
varDirection = elem.direction,
varParallelism = elem.parallelism,
varType = lowerType(elem.ty),
bindExp = elem.binding,
tplExp = NONE(),
arryDim = element.dims,
source = element.source,
values = setMinMaxFromEnumeration(elem.ty, DAEUtil.setProtectedAttr(elem.variableAttributesOption, visibility)),
tearingSelectOption = NONE(),
hideResult = BackendDAEUtil.setHideResultAttribute(element.comment, visibility, elem.componentRef),
comment = element.comment,
connectorType = element.connectorType,
innerOuter = DAEUtil.toDAEInnerOuter(element.innerOuter),
unreplaceable = false
);
then SOME(var);
else NONE();
end match;
end lowerKnownVarSingle;

protected function buildAssertAlgorithms "builds BackendDAE.ALGORITHM out of the given assert statements
author:Waurich TUD 2013-10"
Expand Down
28 changes: 28 additions & 0 deletions OMCompiler/Compiler/BackEnd/BackendVariable.mo
Expand Up @@ -3245,6 +3245,34 @@ algorithm
end matchcontinue;
end getVarSingle;

public function getVarTryHard
"author: kabdelhak
This function tries to get a variable with from a given cref as hard as possible
by removing subscripts and considering array representations. Should be replaced
with proper array handling."
input DAE.ComponentRef cref;
input BackendDAE.Variables vars;
output Option<list<BackendDAE.Var>> var_lst_opt;
protected
BackendDAE.Var var;
list<BackendDAE.Var> var_lst;
DAE.ComponentRef strippedCref;
algorithm
try
(var, _) := getVarSingle(cref, vars);
var_lst_opt := SOME({var});
else try
(var_lst, _) := getVar(cref, vars);
var_lst_opt := SOME(var_lst);
else try
strippedCref := ComponentReference.crefStripSubsExceptModelSubs(cref);
var := BackendVariable.getVarSingle(strippedCref, vars);
var_lst_opt := SOME({var});
else
var_lst_opt := NONE();
end try; end try; end try;
end getVarTryHard;

protected function replaceVarWithWholeDim
"Helper function to traverseExp. Traverses any expressions in a
component reference (i.e. in it's subscripts)."
Expand Down
93 changes: 93 additions & 0 deletions OMCompiler/Compiler/BackEnd/Differentiate.mo
Expand Up @@ -2060,13 +2060,48 @@ algorithm
then
(e, funcs);

// added for ticket #6068
// (p is a parameter)
// x^p
case DAE.BINARY(exp1 = e1,operator = DAE.POW(tp),exp2 = (e2 as DAE.CREF(componentRef = cr)))
guard(isParamOrConstant(cr, inInputData))
equation
etmp = match tp
case DAE.T_INTEGER() then DAE.BINARY(e2, DAE.SUB(tp), DAE.ICONST(1));
else DAE.BINARY(e2, DAE.SUB(tp), DAE.RCONST(1.0));
end match;
(de1, funcs) = differentiateExp(e1, inDiffwrtCref, inInputData, inDiffType, inFunctionTree, maxIter);
e = DAE.BINARY(DAE.BINARY(e2,DAE.MUL(tp),
DAE.BINARY(e1,DAE.POW(tp),etmp)),
DAE.MUL(tp),de1);
then
(e, funcs);

// added for ticket #6068
// (p is a parameter)
// der(p^x) = p^x*ln(p)*der(x)
// if p == 0 then 0;
case e0 as DAE.BINARY(exp1 = e1 as DAE.CREF(componentRef = cr), operator = DAE.POW(tp), exp2 = e2)
guard(isParamOrConstant(cr, inInputData))
equation
(de2, funcs) = differentiateExp(e2, inDiffwrtCref, inInputData, inDiffType, inFunctionTree, maxIter);
etmp = Expression.makePureBuiltinCall("log", {e1}, tp);
// if p is equal to zero, then return zero (do not search for event)
e = Expression.addNoEventToRelations(
DAE.IFEXP(DAE.RELATION(e1, DAE.EQUAL(tp), DAE.RCONST(0.0), -1, NONE()), DAE.RCONST(0.0),
DAE.BINARY(DAE.BINARY(e0,DAE.MUL(tp),etmp),DAE.MUL(tp),de2)));
then
(e, funcs);


// der(x^y) = x^(y-1) * ( x*ln(x)*der(y)+(y*der(x)))
// if x == 0 then 0;
case DAE.BINARY(exp1 = e1,operator = DAE.POW(tp), exp2 = e2)
equation
(de1, funcs) = differentiateExp(e1, inDiffwrtCref, inInputData, inDiffType, inFunctionTree, maxIter);
(de2, funcs) = differentiateExp(e2, inDiffwrtCref, inInputData, inDiffType, inFunctionTree, maxIter);
etmp = Expression.makePureBuiltinCall("log", {e1}, tp);
// if x is equal to zero, then return zero (do not search for event)
e = Expression.addNoEventToRelations(DAE.IFEXP(DAE.RELATION(e1, DAE.EQUAL(tp), DAE.RCONST(0.0), -1, NONE()),
DAE.RCONST(0.0), DAE.BINARY(DAE.BINARY(e1, DAE.POW(tp), DAE.BINARY(e2, DAE.SUB(tp), DAE.RCONST(1.0))),
DAE.MUL(tp), DAE.BINARY(DAE.BINARY(DAE.BINARY(e1, DAE.MUL(tp), etmp), DAE.MUL(tp), de2),
Expand Down Expand Up @@ -2420,6 +2455,40 @@ algorithm
end matchcontinue;
end differentiateFunctionCallPartial;

function addFunctionConstantsAndParameters
input output Option<BackendDAE.Variables> knownVars_opt;
input DAE.Function func;
algorithm
knownVars_opt := match func
local
list<DAE.Element> body;
Option<BackendDAE.Var> var_opt;
list<BackendDAE.Var> body_knowns = {};

case DAE.FUNCTION(functions = DAE.FUNCTION_DEF(body = body)::_)
algorithm
for element in body loop
var_opt := BackendDAECreate.lowerKnownVarSingle(element);
if isSome(var_opt) then
body_knowns := Util.getOption(var_opt) :: body_knowns;
end if;
end for;
if listEmpty(body_knowns) then
// basically do nothing, just for visualization
knownVars_opt := knownVars_opt;
elseif isSome(knownVars_opt) then
// add to current variable vector
knownVars_opt := SOME(BackendVariable.addVars(body_knowns, Util.getOption(knownVars_opt)));
else
// create new variable vector
knownVars_opt := SOME(BackendVariable.listVar(body_knowns));
end if;
then knownVars_opt;

else knownVars_opt;
end match;
end addFunctionConstantsAndParameters;

function tryZeroDiff
input output list<DAE.Exp> explist;
input output DAE.FunctionTree functions;
Expand Down Expand Up @@ -2709,6 +2778,7 @@ algorithm
dumpInputData(inputData);
end if;

inputData.knownVars = addFunctionConstantsAndParameters(inputData.knownVars, func);

// differentiate algorithm statemeants
//print("Function diff: statemeants");
Expand Down Expand Up @@ -3248,5 +3318,28 @@ algorithm
end if;
end dumpInputData;

protected function isParamOrConstant
input DAE.ComponentRef cref;
input BackendDAE.DifferentiateInputData diffData;
output Boolean b;
algorithm
b := match diffData
local
BackendDAE.Variables knownVars;
Option<list<BackendDAE.Var>> var_lst;
BackendDAE.Var var;
case BackendDAE.DIFFINPUTDATA(knownVars = SOME(knownVars)) algorithm
var_lst := BackendVariable.getVarTryHard(cref, knownVars);
if isSome(var_lst) then
var :: _ := Util.getOption(var_lst);
b := BackendVariable.isParamOrConstant(var);
else
b := false;
end if;
then b;
else false;
end match;
end isParamOrConstant;

annotation(__OpenModelica_Interface="backend");
end Differentiate;

0 comments on commit 8e70607

Please sign in to comment.