packages feed

egison-5.1.0: sample/math/analysis/vector-analysis.egi

declare symbol x, y, z

def f1 := function (x)
def g1 := function (x)
def f2 := function (x, y)
def g2 := function (x, y)
def f3 := function (x, y, z)
def g3 := function (x, y, z)
def h3 := function (x, y, z)

--
-- Tensor Arithmetics
--
assertEqual "scalar + tensor"
  (1 + [| 1, 2, 3 |])
  [| 2, 3, 4 |]

assertEqual "tensor + scalar"
  ([| 1, 2, 3 |] + 1)
  [| 2, 3, 4 |]

assertEqual "tensor + tensor (same index)"
  ([| 1, 2, 3 |]_i + [| 1, 2, 3 |]_i)
  [| 2, 4, 6 |]_i

assertEqual "tensor + tensor (outer product)"
  ([| 10, 20, 30 |]_i + [| 1, 2, 3 |]_j)
  [| [| 11, 12, 13 |], [| 21, 22, 23 |], [| 31, 32, 33 |] |]

assertEqual "tensor + 2D tensor"
  ([| 100, 200, 300 |]_i + [|[| 1, 2, 3 |], [| 10, 20, 30 |]|]_j_i)
  [| [| 101, 110 |], [| 202, 220 |], [| 303, 330 |] |]_i_j

assertEqual "2D tensor + 1D tensor"
  ([|[| 11, 12 |], [| 21, 22 |], [| 31, 32 |]|]_i_j + [| 100, 200, 300 |]_i)
  [| [| 111, 112 |], [| 221, 222 |], [| 331, 332 |] |]_i_j

--
-- Derivative
--
assertEqual "partial derivative of f(x,y,z)"
  (∂/∂ f3 x)
  (∂/∂ f3 x)

assertEqual "derivative of vector function"
  (∂/∂ [| f1, g1 |] x)
  [| ∂/∂ f1 x, ∂/∂ g1 x |]

assertEqual "gradient of f(x,y,z)"
  (∂/∂ f3 [| x, y, z |])
  [| ∂/∂ f3 x, ∂/∂ f3 y, ∂/∂ f3 z |]

assertEqual "apply partial derivatives"
  ([| (\e -> ∂/∂ e x), (\e -> ∂/∂ e y) |] f2)
  [| ∂/∂ f2 x, ∂/∂ f2 y |]

assert "Jacobian matrix"
  (show ([| (\e -> ∂/∂ e x), (\e -> ∂/∂ e y) |] [| f2, g2 |]) = show [| [| ∂/∂ f2 x, ∂/∂ g2 x |], [| ∂/∂ f2 y, ∂/∂ g2 y |] |])

--
-- Nabla (uses ∇ from lib/math/analysis/derivative.egi)
--
assertEqual "nabla f"
  (∇ f2 [| x, y |])
  [| ∂/∂ f2 x, ∂/∂ f2 y |]

assertEqual "nabla vector"
  [| ∂/∂ f2 [| x, y |], ∂/∂ g2 [| x, y |] |]
  [| [| ∂/∂ f2 x, ∂/∂ f2 y |], [| ∂/∂ g2 x, ∂/∂ g2 y |] |]

--
-- Contraction (uses trace from lib/math/algebra/vector.egi)
--
assertEqual "element-wise product"
  (contract ([|1, 2, 3|]~i * [|10, 20, 30|]_i))
  [10, 40, 90]

assertEqual "trace of matrix"
  (trace [|[|10, 20, 30|], [|20, 40, 60|], [|30, 60, 90|]|])
  140

--
-- Divergence (uses div from lib/math/algebra/vector.egi)
--
assertEqual "divergence"
  (div [| f3, g3, h3 |] [| x, y, z |])
  (∂/∂ f3 x + ∂/∂ g3 y + ∂/∂ h3 z)

--
-- Curl (uses rot from lib/math/algebra/vector.egi)
-- Standard convention: (rot A)_i = eps_ijk d(A_k)/d(x_j),
-- i.e. (rot A)_1 = dA_3/dx_2 - dA_2/dx_3 = dh/dy - dg/dz.
--
assertEqual "curl"
  (rot [| f3, g3, h3 |] [| x, y, z |])
  [| ∂/∂ h3 y - ∂/∂ g3 z,
     ∂/∂ f3 z - ∂/∂ h3 x,
     ∂/∂ g3 x - ∂/∂ f3 y |]

--
-- Taylor Expansion
--
def multivariateTaylorExpansion fexpr xs ys :=
  withSymbols [h]
    let hs := generateTensor (\[x] -> h_x) (tensorShape xs)
     in map2
          (*)
          (map (\n -> 1 / fact n) nats0)
          (map
             (compose
                (\e -> V.substitute xs ys e)
                (\e -> V.substitute hs (withSymbols [i] xs_i - ys_i) e))
             (iterate (compose (\e -> ∇ e xs) (\e -> V.* hs e)) fexpr))

def taylorExpansion fexpr x a := multivariateTaylorExpansion fexpr [|x|] [|a|]

-- Compare values directly. The CAS canonical form puts coefficients first
-- and uses commutative ordering, so the printed string differs from the
-- handwritten form (e.g. `x * f|1 0` becomes `(f|1 0) * x`).
assertEqual "Taylor expansion of f(x)"
  (take 3 (taylorExpansion f1 x 0))
  [(userRefs f1 []) 0,
   (userRefs f1 [1]) 0 * x,
   (userRefs f1 [1, 1]) 0 * x^2 / 2]

assertEqual "Multivariate Taylor expansion"
  (take 3 (multivariateTaylorExpansion f2 [| x, y |] [| 0, 0 |]))
  [(userRefs f2 []) 0 0,
   (userRefs f2 [1]) 0 0 * x + (userRefs f2 [2]) 0 0 * y,
   ((userRefs f2 [1, 1]) 0 0 * x^2
    + (userRefs f2 [2, 1]) 0 0 * x * y
    + (userRefs f2 [1, 2]) 0 0 * x * y
    + (userRefs f2 [2, 2]) 0 0 * y^2) / 2]