//
//
// symbolic differentiation
//
//

datatype exp =
  | EXPcst of double
  | EXPvar of string
  | EXPadd of (exp, exp)
  | EXPsub of (exp, exp)
  | EXPmul of (exp, exp)
  | EXPdiv of (exp, exp)
  | EXPpow of (exp, int)

val expcst_0 = EXPcst 0.0 and expcst_1 = EXPcst 1.0

fn exp_derivate
  (e0: exp, x0: string): exp = let
  fun aux (e0: exp):<cloref1> exp =
    case+ e0 of
    | EXPcst _ => expcst_0
    | EXPvar x => begin
        if eq_string_string (x, x0) then expcst_1 else expcst_0
      end // end of [EXPvar]
    | EXPadd (e1, e2) => EXPadd (aux e1, aux e2)
    | EXPsub (e1, e2) => EXPsub (aux e1, aux e2)
    | EXPmul (e1, e2) => begin
        EXPadd (EXPmul (aux e1, e2), EXPmul (e1, aux e2))
      end
    | EXPdiv (e1, e2) => EXPdiv (
        EXPsub (EXPmul (aux e1, e2), EXPmul (e1, aux e2)), EXPpow (e2, 2)
      ) // end of [EXPdiv]
    | EXPpow (e, n) => begin case+ n of
      | _ when n = 1 => aux (e)
      | _ when n = 0 => expcst_0
      | _ => EXPmul (
          EXPcst (double_of_int n), EXPmul (EXPpow (e, n-1), aux e)
        )
      end // end of [EXPpow]
in
  aux (e0)
end // end of [exp_derivate]

(* ****** ****** *)

(* end of [exp_derivate-2008-09-09.dats] *)