Skip to content

Commit

Permalink
[NB] Fix differentiation of functions (#8681)
Browse files Browse the repository at this point in the history
- don't skip discrete Reals when removing inputs from interface
- add unique index for generated derivaties
- append generated derivatives after user derivatives
- fix printing order of derivative and inverse annotation
- extend testsuite
  • Loading branch information
phannebohm committed Mar 14, 2022
1 parent cbb0199 commit de7d751
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 37 deletions.
14 changes: 8 additions & 6 deletions OMCompiler/Compiler/NBackEnd/Util/NBDifferentiate.mo
Expand Up @@ -689,8 +689,8 @@ public
isCont := (diffArguments.diffType == DifferentiationType.FUNCTION) or BackendUtil.isContinuous(arg);
isReal := Type.isRealRecursive(Expression.typeOf(arg)); // ToDo also records
if not (isCont and isReal) then
// add to map; if it is not continuous also already set to true (always removed from interface)
UnorderedMap.add(InstNode.name(inp), not isCont, interface_map);
// add to map; if it is not Real also already set to true (always removed from interface)
UnorderedMap.add(InstNode.name(inp), not isReal, interface_map);
end if;
end for;

Expand Down Expand Up @@ -1016,6 +1016,7 @@ public
FunctionDerivative funcDer;
Function dummy_func;
CachedData cachedData;
String der_func_name;

case der_func as Function.FUNCTION(node = node as InstNode.CLASS_NODE(cls = cls)) algorithm
new_cls := match Pointer.access(cls)
Expand All @@ -1037,9 +1038,10 @@ public
// in the case of recursive differentiation (e.g. function calls itself)
dummy_func := func;
node.cls := Pointer.create(new_cls);
node.name := NBVariable.FUNCTION_DERIVATIVE_STR + "." + node.name;
der_func_name := NBVariable.FUNCTION_DERIVATIVE_STR + intString(listLength(func.derivatives));
node.name := der_func_name + "." + node.name;
// create "fake" function from new node (update cache to get correct derivative name)
der_func.path := AbsynUtil.prefixPath(NBVariable.FUNCTION_DERIVATIVE_STR, der_func.path);
der_func.path := AbsynUtil.prefixPath(der_func_name, der_func.path);
cachedData := CachedData.FUNCTION({der_func}, true, false);
der_func.node := InstNode.setFuncCache(node, cachedData);

Expand Down Expand Up @@ -1083,7 +1085,7 @@ public
conditions = {}, // possibly needs updating
lowerOrderDerivatives = {} // possibly needs updating
);
func.derivatives := funcDer :: func.derivatives;
func.derivatives := List.appendElt(funcDer, func.derivatives);
diffArguments.funcTree := FunctionTreeImpl.add(diffArguments.funcTree, func.path, func, FunctionTreeImpl.addConflictReplace);
then der_func;

Expand All @@ -1093,7 +1095,7 @@ public
end match;
if Flags.isSet(Flags.DEBUG_DIFFERENTIATION) then
print("\n[BEFORE] " + Function.toFlatString(func) + "\n");
print("\n[AFTER] " + Function.toFlatString(der_func) + "\n\n");
print("\n[AFTER ] " + Function.toFlatString(der_func) + "\n\n");
end if;
end differentiateFunction;

Expand Down
6 changes: 3 additions & 3 deletions OMCompiler/Compiler/NFFrontEnd/NFFunction.mo
Expand Up @@ -775,12 +775,12 @@ uniontype Function
annMod := SCodeUtil.filterSubMods(annMod,
function SCodeUtil.removeGivenSubModNames(namesToRemove={"derivative", "inverse"}));

for derivative in fn.derivatives loop
for derivative in listReverse(fn.derivatives) loop
annMod := SCodeUtil.prependSubModToMod(FunctionDerivative.toSubMod(derivative), annMod);
end for;

for inverse in fn.inverses loop
annMod := SCodeUtil.prependSubModToMod(FunctionInverse.toSubMod(inverse), annMod);
for i in arrayLength(fn.inverses):-1:1 loop
annMod := SCodeUtil.prependSubModToMod(FunctionInverse.toSubMod(fn.inverses[i]), annMod);
end for;

if not SCodeUtil.emptyModOrEquality(annMod) then
Expand Down
Expand Up @@ -7,33 +7,44 @@ model function_annotation_der
Real a;
Real b(start=0.0, fixed=true);
Real c(start=0.0, fixed=true);
Real d(start=0.0, fixed=true);
discrete Real k(start=1.0, fixed=true);
Integer n;
equation
n = 0;
when a > 0 then
k = pre(k) + 1;
end when;
a = sin(b);
der(b) = f(a, k);
der(c) = f(a, b);
der(b) = f(a, n, k, k);
der(c) = f(a, n, k, b);
der(d) = f(a, n, b, b);
end function_annotation_der;

function f
input Real x;
input Integer n;
input Real k;
input Real m;
output Real y;
algorithm
y := k*x^2;
annotation(derivative(zeroDerivative=k)=df,Inline=false);
y := k*x^2 + m;
annotation(derivative(zeroDerivative=k)=df, Inline=false);
end f;

function df
input Real x;
input Integer n;
input Real k;
input Real m;
input Real der_x;
input Real der_m;
output Real der_y;
protected
Real y;
algorithm
der_y := k*2*x*der_x;
annotation(Inline=false);
der_y := k*2*x*der_x + der_m;
annotation(Inline = false);
end df;
"); getErrorString();

Expand All @@ -45,40 +56,49 @@ simulate(function_annotation_der); getErrorString();
// true
// ""
// ### debugDifferentiation | NBJacobian.jacobianSymbolic ###
// [BEFORE] [SCAL] (1) a = sin(b) ($RES_SIM_2)
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.a = cos(b) * $SEED_ODE_JAC.b ($RES_SIM_2)
//
// ### debugDifferentiation | NBJacobian.jacobianSymbolic ###
// [BEFORE] [SCAL] (1) $DER.b = f(a, k) ($RES_SIM_1)
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.$DER.b = df(a, k, $pDER_ODE_JAC.a) ($RES_SIM_1)
//
// ### debugDifferentiation | NBJacobian.jacobianSymbolic ###
// [BEFORE] [SCAL] (1) $DER.c = f(a, b) ($RES_SIM_0)
// [BEFORE] [SCAL] (1) $DER.d = f(a, 0, b, b) ($RES_SIM_0)
//
// [BEFORE] function 'f'
// input Real 'x';
// input Integer 'n';
// input Real 'k';
// input Real 'm';
// output Real 'y';
// algorithm
// 'y' := 'k' * 'x' ^ 2.0;
// annotation(derivative(order = 1, zeroDerivative = 'k') = 'df', derivative(order = 1) = '$fDER.f', Inline = false);
// 'y' := 'k' * 'x' ^ 2.0 + 'm';
// annotation(derivative(order = 1, zeroDerivative = 'k') = 'df', derivative(order = 1) = '$fDER1.f', Inline = false);
// end 'f'
//
// [AFTER] function '$fDER.f'
// [AFTER ] function '$fDER1.f'
// input Real 'x';
// input Integer 'n';
// input Real 'k';
// input Real 'm';
// input Real '$fDER_x';
// input Real '$fDER_k';
// input Real '$fDER_m';
// output Real '$fDER_y';
// protected
// Real 'y';
// algorithm
// '$fDER_y' := k * (2.0 * x * $fDER_x) + $fDER_k * x ^ 2.0;
// 'y' := 'k' * 'x' ^ 2.0;
// '$fDER_y' := k * (2.0 * x * $fDER_x) + $fDER_k * x ^ 2.0 + $fDER_m;
// 'y' := 'k' * 'x' ^ 2.0 + 'm';
// annotation(Inline = false);
// end '$fDER.f'
// end '$fDER1.f'
//
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.$DER.d = $fDER1.f(a, 0, b, b, $pDER_ODE_JAC.a, $SEED_ODE_JAC.b, $SEED_ODE_JAC.b) ($RES_SIM_0)
//
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.$DER.c = $fDER.f(a, b, $pDER_ODE_JAC.a, $SEED_ODE_JAC.b) ($RES_SIM_0)
// ### debugDifferentiation | NBJacobian.jacobianSymbolic ###
// [BEFORE] [SCAL] (1) a = sin(b) ($RES_SIM_3)
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.a = cos(b) * $SEED_ODE_JAC.b ($RES_SIM_3)
//
// ### debugDifferentiation | NBJacobian.jacobianSymbolic ###
// [BEFORE] [SCAL] (1) $DER.b = f(a, 0, k, k) ($RES_SIM_2)
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.$DER.b = df(a, 0, k, k, $pDER_ODE_JAC.a, 0.0) ($RES_SIM_2)
//
// ### debugDifferentiation | NBJacobian.jacobianSymbolic ###
// [BEFORE] [SCAL] (1) $DER.c = f(a, 0, k, b) ($RES_SIM_1)
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.$DER.c = df(a, 0, k, b, $pDER_ODE_JAC.a, $SEED_ODE_JAC.b) ($RES_SIM_1)
//
// record SimulationResult
// resultFile = "function_annotation_der_res.mat",
Expand Down
Expand Up @@ -49,10 +49,10 @@ simulate(function_diff); getErrorString();
// elseif true then
// 'b' := 'f'(-'a');
// end if;
// annotation(derivative(order = 1) = '$fDER.f', Inline = false);
// annotation(derivative(order = 1) = '$fDER0.f', Inline = false);
// end 'f'
//
// [AFTER] function '$fDER.f'
// [AFTER ] function '$fDER0.f'
// input Real 'a';
// input Real '$fDER_a';
// output Real '$fDER_b';
Expand All @@ -63,17 +63,17 @@ simulate(function_diff); getErrorString();
// '$fDER_b' := 2.0 * a * $fDER_a;
// 'b' := 'a' ^ 2.0;
// elseif true then
// '$fDER_b' := '$fDER.f'(-'a', -'$fDER_a');
// '$fDER_b' := '$fDER0.f'(-'a', -'$fDER_a');
// 'b' := 'f'(-'a');
// end if;
// annotation(Inline = false);
// end '$fDER.f'
// end '$fDER0.f'
//
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.$DER.x = $fDER.f(y, $pDER_ODE_JAC.y) ($RES_SIM_1)
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.$DER.x = $fDER0.f(y, $pDER_ODE_JAC.y) ($RES_SIM_1)
//
// ### debugDifferentiation | NBJacobian.jacobianSymbolic ###
// [BEFORE] [SCAL] (1) $DER.z = f(x) ($RES_SIM_0)
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.$DER.z = $fDER.f(x, $SEED_ODE_JAC.x) ($RES_SIM_0)
// [AFTER ] [SCAL] (1) $pDER_ODE_JAC.$DER.z = $fDER0.f(x, $SEED_ODE_JAC.x) ($RES_SIM_0)
//
// record SimulationResult
// resultFile = "function_diff_res.mat",
Expand Down

0 comments on commit de7d751

Please sign in to comment.