% diff.rb % % Purpose: (Partial) differentiation % Copyright: R.A. van Engelen, Leiden University, 1996 % Updates: 1996/01/15; 1996/02/08 % % Remarks: Only to be used in combination with diff script!include linear.default strategy diff(full).full strategy [linex, diff, opdiff, chint, fold].chain strategy [chdiff, opdiff, chint, fold].none strategy [nodiff].diff; use_module([depend]).(diff; diff(Var, X) => DYX <-

is_var(Var),

( (to_atom(X, D), D has dependency(Zs) ->

map(diff(Var, Zs), DVZs),

map(diff(Zs, X), DZsX),

map(DVZs * DZsX, DVZX),

DYX = (+ | DVZX)

)

; DYX = df(Var, X)

))

.diff; diff(Y1 + Y2, X) => diff(Y1, X) + diff(Y2, X).diff; diff(- Y, X) => - diff(Y, X).diff; diff(undefined,_G596) => {undefined}.diff; diff(1 / Y, X) => diff(Y, X) * Y ^ {- {2}}.diff; diff((* | [Y | Ys]), X) => ( (* | [diff(Y, X) | Ys])

+ Y * diff((* | Ys), X)

).diff; diff(Y ^ N, X) => ( N

* diff(Y, X)

* Y ^ (N - 1)

) <- is_number(N).diff; diff(Y ^ Z, X) => diff(exp(log(Y) * Z), X).diff; diff(prod(Y, D), X) => sum(diff(Y, X) / Y * prod(Y, D), D).diff; diff(X, X) => {1}.% d(if U then V else W ) = if U then d(V) else d(W).diff; diff(A if B, X) => diff(A, X) if B.diff; diff(A \\ B, X) => diff(A, X) \\ diff(B, X).% stencil activitiesdiff; diff(protect(A), X) => protect(diff(A, X)).diff; diff(protect(X, Y), Z) => protect(diff(X, Z), Y).diff; diff(varidx(X,_G596), X) => {1}.diff; diff(varidx(Var, Idx1), varidx(Var, Idx2)) => if((and | EqIdx), {1}, {0}) <- map(Idx1 == Idx2, EqIdx).(diff; diff(varidx(Var, Idx), X) => + | DUIdxX <-

X = {Y},

Y instance_of index_var,

Var has point(Pnt),

findall(diff(J, X) * df({varidx({Var}, IdxI)}, I), ( nth1(N, Pnt, I)

, nth1(N, Idx, J)

, replace_nth1(N, Idx, I, IdxI)

), DUIdxX))

.% independent variables behave like constants, so linearise to 0diff; diff(I, nil) => 0 <- to_atom(I, AI), AI instance_of index_var.(diff; diff(L, nil) => 0 <-

to_atom(L, AL), AL instance_of linearized_var)

.(diff; diff(L, nil) => 0 <-

to_atom(L, AL), AL instance_of parameter_var)

.% return the linearised variable, linearise the discrete value(diff; diff(U, nil) => DU <-

to_atom(U, AU),

AU instance_of variable,

!,

( AU has linearized_var(DU)

; ( (concat(AU, '_TL', DU), \+ (DU isa object) ->

assume DU isa linearized_var

)

; linearized_var do create(DU)

),

AU do get_properties(Ps),

assume DU has Ps,

ignore(remove DU has discrete_value(_G653)),

ignore(remove DU has fortran_name(_G662)),

assume AU has linearized_var(DU),

assume DU has parent_var(AU)

),

( AU instance_of fundamental_var

; DU has discrete_value(_G709)

; (AU has discrete_value(DAU) ->

normalize(diff(DAU, nil), NDDAU),

denormalize(NDDAU, DDAU),

assume DU has discrete_value(DDAU)

)

))

.(diff; diff(S, X) => OpD <-

(to_op(S, Op) ->

Op instance_of stencil_op,

Op =.. [F, A | As],

OpD =.. [F, diff(A, X) | As]

))

.% needed: h_x is inert but that should be clear??!?? % worse: kappa is inert but that is not accepted: assigned! % chain rules(diff; diff({varidx({Var}, Idx)}, X) => DAX <-

to_atom(Var, A),

to_atom(X, D),

A has dependency(Zs),

( memberchk(D, Zs) -> DAX = df(varidx({Var}, Idx), X)

; findall(diff(varidx({Var}, Idx), Z) * diff(Z, X), member(Z, Zs), DAZX), DAX = (+ | DAZX)

),

!)

.(diff; diff(Atom, X) => DAX <-

to_atom(Atom, A),

to_atom(X, D),

( (A has dependency(Zs) ->

( memberchk(D, Zs) -> DAX = df(A, X)

; findall(diff(A, Z) * diff(Z, X), member(Z, Zs), DAZX),

DAX = (+ | DAZX)

)

)

; D has dependency(Zs), memberchk(A, Zs) -> DAX = df(A, X)

; DAX = {0}

),

!)

.diff; diff(Const,_G596) => {0} <- is_constant(Const).(diff; diff(Op, X) *=> + | DFAsX <-

to_op(Op, FAs),

!,

\+ (FAs do commute_over(diff(_G610, X))),

\+ (diff(_G620, X) do commute_over(FAs)),

findall(diff(A, X) * df(FAs, N), arg(N, FAs, A), DFAsX))

.% Symbolic differentiation by chain-rule onlychdiff; diff(undefined,_G596) => undefined.chdiff; diff(X, X) => {1}.(chdiff; diff(X, Y) => DXY <-

to_atom(X, A),

\+ (A has dependency(_G607)),

to_atom(Y, B),

( (B has dependency(Zs) ->

(memberchk(A, Zs) -> DXY = df(X, Y); DXY = {0})

)

; DXY = {0}

))

.(chdiff; diff(FAs, X) => DYX <-

to_atom(X, D),

( (depend : infer(FAs, [dep(Zs)]) ->

( memberchk(D, Zs) -> DYX = df(FAs, X)

; findall(diff(FAs, Z) * diff(Z, X), member(Z, Zs), DYZX),

DYX = (+ | DYZX)

)

)

; (D has dependency(Zs) ->

map(diff(FAs, Zs), DFZs),

map(diff(Zs, X), DZsX),

map(DFZs * DZsX, DYZX),

DYX = (+ | DYZX)

)

))

.chdiff; diff(E, X) => df(E, X).chint; integrate(undefined,_G596) => undefined.chint; integrate(X, X = L .. U) => 0 max ( 1 / 2

* (U ^ 2 - L ^ 2)

).(chint; integrate(X, Y = L .. U) => IXY <-

to_atom(X, A),

\+ (A has dependency(_G613)),

to_atom(Y, B),

B has dependency(Zs),

( memberchk(A, Zs) -> IXY = int(X, Y = L .. U)

; IXY = X * (U - L)

))

.(chint; integrate(FAs, X = L .. U) => IYX <-

depend : infer(FAs, [dep(Zs)]),

to_atom(X, D),

( memberchk(D, Zs) -> IYX = int(FAs, X = L .. U)

; findall(integrate(FAs * diff(X, Z), Z = Z $ L .. Z $ U), member(Z, Zs), IYZX), IYX = (+ | IYZX)

),

!)

.chint; integrate(X, Y) => int(X, Y).% No symbolic differentiation/integrationnodiff; diff(E, X) => df(E, X).nodiff; integrate(E, X) => int(E, X).% Functions that are not differentiable on whole domain:opdiff; df({abs(X)}, {1}) => if(X <> {0}, sign(X), {undefined}).opdiff; df({ceil(X)}, {1}) => if(X <> ceil(X), {0}, {undefined}).opdiff; df({floor(X)}, {1}) => if(X <> floor(X), {0}, {undefined}).opdiff; df({frac(X)}, {1}) => if(X <> trunc(X), {1}, {undefined}).opdiff; df({round(X)}, {1}) => if(X <> round(X), {0}, {undefined}).opdiff; df({trunc(X)}, {1}) => if(X <> trunc(X), {0}, {undefined}).% Functions that are differentiable:opdiff; df(acos(X), 1) => - ({1} - X ^ {2}) ^ {- {{1} / {2}}}.opdiff; df(acosh(X), 1) => (X ^ {2} - {1}) ^ {- {{1} / {2}}}.opdiff; df(asin(X), 1) => ({1} - X ^ {2}) ^ {- {{1} / {2}}}.opdiff; df(asinh(X), 1) => ({1} + X ^ {2}) ^ {- {{1} / {2}}}.opdiff; df(atan(X), 1) => {1} / ({1} + X ^ {2}).opdiff; df(atanh(X), 1) => {1} / ({1} - X ^ {2}).opdiff; df(cos(X), 1) => - sin(X).opdiff; df(cosh(X), 1) => - sinh(X).opdiff; df(exp(X), 1) => exp(X).opdiff; df(log(X), 1) => 1 / X.opdiff; df(sign(_G595), 1) => 0.0.opdiff; df(sin(X), 1) => cos(X).opdiff; df(sinh(X), 1) => cosh(X).opdiff; df(sqrt(X), 1) => {{1} / {2}} * X ^ {- {{1} / {2}}}.opdiff; df(tan(X), 1) => {1} + tan(X) ^ {2}.opdiff; df(tanh(X), 1) => {1} - tanh(X) ^ {2}.(opdiff; df(Op, N) => DOp <-

to_integer(N, I), to_op(Op, FAs) -> FAs has derivative(I, DOp))

.