(ns emmy.calculus.basis
(:require [emmy.calculus.form-field :as ff]
[emmy.calculus.manifold :as m]
[emmy.calculus.vector-field :as vf]
[emmy.generic :as g]
[emmy.matrix :as matrix]
[emmy.structure :as s]
[emmy.value :as v]))
(defn coordinate-system->basis
"Returns the standard basis object for `coordinate-system`."
[coordinate-system]
(let [vector-basis (vf/coordinate-system->vector-basis coordinate-system)
oneform-basis (ff/coordinate-system->oneform-basis coordinate-system)]
{:type ::coordinate-basis
:dimension (:dimension (m/manifold coordinate-system))
:vector-basis vector-basis
:oneform-basis oneform-basis
:coordinate-system coordinate-system}))
#object[emmy.calculus.basis$coordinate_system__GT_basis 0x5bb4d8c "
emmy.calculus.basis$coordinate_system__GT_basis@5bb4d8c"
]
(defn coordinate-basis?
"Returns true if `x` is a coordinate basis, false otherwise."
[x]
(isa? (v/kind x) ::coordinate-basis))
#object[emmy.calculus.basis$coordinate_basis_QMARK_ 0x21069b01 "
emmy.calculus.basis$coordinate_basis_QMARK_@21069b01"
]
(derive ::coordinate-basis ::basis)
nil
(defn basis->coordinate-system [b]
{:pre [(coordinate-basis? b)]}
(:coordinate-system b))
#object[emmy.calculus.basis$basis__GT_coordinate_system 0x6c10a717 "
emmy.calculus.basis$basis__GT_coordinate_system@6c10a717"
]
(defn make-basis
"Make a basis object out of a vector and dual basis.
The dimensions of `vector-basis` and `dual-basis` must agree."
[vector-basis dual-basis]
(let [d (count (flatten vector-basis))]
(assert (= (count (flatten dual-basis)) d))
{:type ::basis
:dimension d
:vector-basis vector-basis
:oneform-basis dual-basis}))
#object[emmy.calculus.basis$make_basis 0x2861a78 "
emmy.calculus.basis$make_basis@2861a78"
]
(defn basis?
"Returns true if `x` is a basis, false otherwise."
[x]
(isa? (v/kind x) ::basis))
#object[emmy.calculus.basis$basis_QMARK_ 0x5d8ee089 "
emmy.calculus.basis$basis_QMARK_@5d8ee089"
]
(defn basis->oneform-basis
"Extract the dual basis from the given basis object `b`."
[b]
{:pre [(basis? b)]}
(:oneform-basis b))
#object[emmy.calculus.basis$basis__GT_oneform_basis 0x48c5b6aa "
emmy.calculus.basis$basis__GT_oneform_basis@48c5b6aa"
]
(defn basis->vector-basis
"Extract the vector basis from the given basis object `b`."
[b]
{:pre [(basis? b)]}
(:vector-basis b))
#object[emmy.calculus.basis$basis__GT_vector_basis 0x210488ba "
emmy.calculus.basis$basis__GT_vector_basis@210488ba"
]
(defn basis->dimension
"Extract the dimension from the given basis object `b`."
[b]
{:pre [(basis? b)]}
(:dimension b))
#object[emmy.calculus.basis$basis__GT_dimension 0x13631338 "
emmy.calculus.basis$basis__GT_dimension@13631338"
]
(defn contract [f basis]
(let [vector-basis (basis->vector-basis basis)
oneform-basis (basis->oneform-basis basis)]
(s/sumr f vector-basis oneform-basis)))
#object[emmy.calculus.basis$contract 0x39432375 "
emmy.calculus.basis$contract@39432375"
]
(defn vector-basis->dual [vector-basis coordinate-system]
(let [prototype (m/coordinate-prototype coordinate-system)
vector-basis-coefficient-functions
(s/mapr #(vf/vector-field->components % coordinate-system)
vector-basis)
guts (fn [coords]
(let [shape (s/compatible-shape prototype)
invert #(matrix/s:inverse shape % prototype)
transpose #(matrix/s:transpose shape % prototype)]
(-> (s/mapr #(% coords) vector-basis-coefficient-functions)
(invert)
(transpose))))
oneform-basis-coefficient-functions (m/c:generate
(:dimension
(m/manifold coordinate-system))
::s/up
#(comp (s/component %) guts))
oneform-basis (s/mapr #(ff/components->oneform-field % coordinate-system)
oneform-basis-coefficient-functions)]
oneform-basis))
#object[emmy.calculus.basis$vector_basis__GT_dual 0x5c56b211 "
emmy.calculus.basis$vector_basis__GT_dual@5c56b211"
]
(defn make-constant-vector-field [basis m0]
(fn [v]
(fn [f]
(let [vector-basis (basis->vector-basis basis)
oneform-basis (basis->oneform-basis basis)]
(g/* (vector-basis f)
(s/mapr (fn [onefb] (fn [_] ((onefb v) m0)))
oneform-basis))))))
#object[emmy.calculus.basis$make_constant_vector_field 0x5992a079 "
emmy.calculus.basis$make_constant_vector_field@5992a079"
]
(defn Jacobian
"Returns the Jacobian of transition from `from-basis` to `to-basis`.
The Jacobian is a structure of manifold functions. The outer index is the
from-basis index, so this structure can be multiplied by tuple of component
functions of a vector field relative to `from-basis` to get component
functions for a vector field in `to-basis`."
[to-basis from-basis]
(s/mapr (basis->oneform-basis to-basis)
(basis->vector-basis from-basis)))
#object[emmy.calculus.basis$Jacobian 0x52e392a0 "
emmy.calculus.basis$Jacobian@52e392a0"
]