Evaluates function value. It is shortcut for getDerivative of zero order.
User-defined attribute that can be applied on struct member definition along with Derivative to denote that the member holds a negative value of the partial derivative. This attribute is useful for financial code where verbal definitions may denote negative partial derivatives.
Constructs the natural exponent of the expression.
Constructs the natural logarithm of the expression.
Constructs the cumulative normal distribution function of the expression
Constructs of the expression raised to the specified (positive or negative) compile-time integral power.
Evaluates partial derivatives and function value, if any, for a user-provided set of partial derivatives. The derivative set can be defined with Derivative and Minus UDAs.
Constructs the square root of the expression.
A double precision constant with an immidiate value
User defined attribute that should applied on struct definition of a user-defined expression function.
User defined attribute that should applied on a struct member definition of a user-defined set of derivatives. The attribute holds an unordered set with duplicates of variables names to reflect which partial derivative this member contains.
Fetchs a set of variables the expression is depends on. First, it checks if the expression has DependsOn UDA ; otherwise, iterates over members with Derivative UDA and collects variable names.
A double precision named variable with an immidiate value
Given a compiletime variable name v and two expressions F(v, U) and G(Y), constructs a composition F ∘ G (U, Y) as v = G.
Constructs a partial derivative of one order. The function can be applied in any stage any number of times. The function does NOT evaluate the expression.
Evaluates partial derivative for user-defined compiletime set of variables. First, it checks if the expression has .getDerivative methods and uses it, otherwise iterates over members with Derivative UDA and tries to find a member that holds the required partial derivative.
Evaluates partial derivatives and function value, if any, for a user-provided set of partial derivatives. The derivative set can be defined with Derivative and Minus UDAs.
/// static struct D { @Derivative() double _; @Derivative("a") double a; @Derivative("b") double b; @Minus @Derivative("a", "b") double mab; } auto d = D(3, 4, 5, -6); assert(d.powi!2.setDerivatives!D == D(9, 24, 30, -76));
/// static struct Greeks { @Derivative("spot") double delta; @Derivative("spot", "spot") double gamma; @Minus @Derivative("time", "spot") double charm; } auto greeks = Greeks(2, 3, 4); auto dspot = derivativeOf!"spot"(&greeks); assert(greeks.delta is dspot.getFunctionValue); assert(greeks.gamma is dspot.getDerivative!(["spot"])); assert(greeks.charm is -dspot.getDerivative!(["time"]));
import mir.test; import mir.math; // Test Const static assert(Dependencies!Const == [].DependsOn); auto c = 5.Const; static assert(c.getDerivative!(["any"]) == 0); assert(c.getFunctionValue == 5); // Test Var auto spot = 7.Var!"spot"; static assert(Dependencies!(Var!"spot") == ["spot"].DependsOn); static assert(spot.getDerivative!(["spot"]) == 1); static assert(spot.getDerivative!(["other"]) == 0); assert(spot.getFunctionValue == 7); // Test integer power and exponent auto f1 = exp(3.Const * spot.powi!(-2)); static assert(Dependencies!(typeof(f1)) == ["spot"].DependsOn); assert(f1.getFunctionValue == mir.math.exp(3 * 7.0 ^^ -2)); assert(f1.getDerivative!(["spot"]).approxEqual(3 * -2 * 7.0 ^^ -3 * mir.math.exp(3 * 7.0 ^^ -2))); // Test DerivativeOf assert(f1.derivativeOf!"spot".getFunctionValue == f1.getDerivative!(["spot"])); // Test product and sum assert(f1.derivativeOf!"spot".derivativeOf!"spot".getFunctionValue.approxEqual((3 * (-2 * 7.0 ^^ -3)) ^^ 2 * mir.math.exp(3 * 7.0 ^^ -2) + 3 * (6 * 7.0 ^^ -4)* mir.math.exp(3 * 7.0 ^^ -2))); auto strike = 9.Var!"strike"; auto f2 = strike * f1 + strike; assert(f2.getDerivative!(["strike"]).approxEqual(1 + f1.getFunctionValue)); // Test log assert(f2.log.getFunctionValue == mir.math.log(f2.getFunctionValue)); assert(f2.log.getDerivative!(["strike"]) == getFunctionValue(f2.powi!(-1) * (1.Const + f1))); assert(f2.sqrt.getFunctionValue == mir.math.sqrt(f2.getFunctionValue)); assert(f2.sqrt.getDerivative!(["strike"]) == getFunctionValue(f2.sqrt.powi!(-1) * 0.5.Const * (1.Const + f1))); // Compose auto barrier = 13.Var!"barrier"; auto fc = barrier.powi!2 / strike; auto f3 = f2.composeAt!"strike"(fc); assert(f3.getFunctionValue == f2.getFunctionValue); assert(f3.getDerivative!(["vol"]) == f2.getDerivative!(["vol"])); assert(f3.getDerivative!(["strike"]) == f2.getDerivative!(["strike"]) * fc.getDerivative!(["strike"])); f3.getDerivative!(["barrier"]).shouldApprox == f2.getDerivative!(["strike"]) * fc.getDerivative!(["barrier"]); getDerivative!(["barrier"])(f3 + barrier).shouldApprox == f2.getDerivative!(["strike"]) * fc.getDerivative!(["barrier"]) + 1; f3.getDerivative!(["strike", "barrier"]).shouldApprox == f2.getDerivative!(["strike", "strike"]) * fc.getDerivative!(["strike"]) * fc.getDerivative!(["barrier"]) + f2.getDerivative!(["strike"]) * fc.getDerivative!(["strike", "barrier"]); /// normalDistribution import mir.math.func.normal: constantNormalCDF = normalCDF, normalPDF; barrier.powi!2.normalCDF.getFunctionValue.shouldApprox == constantNormalCDF(13.0 ^^ 2); barrier.powi!2.normalCDF.getDerivative!(["barrier"]).shouldApprox == normalPDF(13.0 ^^ 2) * (2 * 13);
Expression differentiation
The module provides API for rapid evaluation of a user-requested set of partial derivatives of any order.
The implementation operates with double precision numbers.
Expression construction
Expression composition
Derivative set definition
Function definition
Expression evaluation
Optimization note
During function differentiation, the resulting set of expressions likely contains a lot of identical calls of elementary functions. LLVM efficiently eliminates equivalent calls of intrinsic functions such as powi, log, exp, and sqrt. On the other hand, it can't eliminate identical calls of complex functions. It is highly recommended to evaluate a set of partial derivatives immediately after constructing a complex expression such as normalDistribution.