\import Algebra.Group
\import Algebra.Meta
\import Algebra.Module
\import Algebra.Module.BilinearMap
\import Algebra.Module.LinearMap
\import Algebra.Monoid
\import Algebra.Pointed
\import Algebra.Ring
\import Function.Meta
\import Logic
\import Meta
\import Paths
\import Paths.Meta
\class SyntheticDiff \noclassifying (R : CRing) {
| \protected isOpenProp : \Prop -> \Prop
| \protected top-isOpenProp : isOpenProp (\Sigma)
| \protected meet-isOpenProp {P Q : \Prop} : isOpenProp P -> isOpenProp Q -> isOpenProp (\Sigma P Q)
\lemma meet3-isOpenProp {P Q R : \Prop} (Po : isOpenProp P) (Qo : isOpenProp Q) (Ro : isOpenProp R) : isOpenProp (\Sigma P Q R)
=> transport isOpenProp (ext (\lam s => (s.1, s.2.1, s.2.2), \lam s => (s.1, (s.2, s.3)))) $ meet-isOpenProp Po (meet-isOpenProp Qo Ro)
\func IsOpenPred {A : \Type} (U : A -> \Prop) : \Prop
=> \Pi (a : A) -> isOpenProp (U a)
\func IsInvDense (B : \Set) : \Prop
=> \Pi (U : R -> \Prop) -> IsOpenPred U -> \Pi (f g : \Sigma (z : R) (U z) -> B)
-> (\Pi (p : \Sigma (z : R) (u : U z)) -> Monoid.Inv p.1 -> f p = g p)
-> \Pi (p : \Sigma (z : R) (u : U z)) -> f p = g p
\lemma cancel-lem {B : LModule R} (Bd : IsInvDense B) {U : R -> \Prop} (Uo : IsOpenPred U)
(f g : \Sigma (z : R) (U z) -> B)
(s : \Pi (p : \Sigma (z : R) (u : U z)) -> p.1 *c f p = p.1 *c g p)
(p : \Sigma (z : R) (u : U z)) : f p = g p
=> Bd U Uo f g (\lam p p-inv => B.cancel p-inv (s p)) p
\func IsDiff {A B : LModule R} (Bd : IsInvDense B) {U : A -> \Prop} (Uo : IsOpenPred U) (f : \Sigma (x : A) (U x) -> B) : \Set
=> \Pi (x : \Sigma (a : A) (U a)) (a : A) (t : \Sigma (r : R) (U (x.1 + r *c a))) -> \Sigma (y : B) (t.1 *c y = f (x.1 + t.1 *c a, t.2) - f x)
\where {
\use \level levelProp (d d' : IsDiff Bd Uo f) : d = d'
=> ext \lam x a t => ext $ cancel-lem Bd (\lam r => Uo _) _ _ (\lam t => (d x a t).2 *> inv (d' x a t).2) t
\lemma IsDiff-eq (Bd : IsInvDense B) (Uo : IsOpenPred U) {f : \Sigma (x : A) (U x) -> B} (d : IsDiff Bd Uo f) {x x' : \Sigma (a : A) (U a)} (p : x.1 = x'.1) {a : A} {t : \Sigma (r : R) (U (x.1 + r *c a))} {t' : \Sigma (r : R) (U (x'.1 + r *c a))} (q : t.1 = t'.1) : (d x a t).1 = (d x' a t').1
=> path \lam i => (d (p i, prop-dpi _ _ _ i) a (q i, prop-dpi _ _ _ i)).1
}
\func IsDiffT {A B : LModule R} (Bd : IsInvDense B) (f : A -> B)
=> IsDiff Bd (\lam _ => top-isOpenProp) (\lam p => f p.1)
-- | The derivative is linear
\func deriv {A B : LModule R} (Bd : IsInvDense B) {U : A -> \Prop} (Uo : IsOpenPred U)
{f : \Sigma (x : A) (U x) -> B} (d : IsDiff Bd Uo f) (x : \Sigma (a : A) (U a)) : LinearMap A B \cowith
| func a => (d x a (0, sub-lem x)).1
| func-+ {a} {a'} =>
\have s => cancel-lem Bd {\lam t => \Sigma (U (x.1 + t *c (a + a'))) (U (x.1 + t *c a)) (U (x.1 + t *c a + t *c a'))} (\lam t => meet3-isOpenProp (Uo _) (Uo _) (Uo _)) (\lam t => (d x (a + a') (t.1, t.2.1)).1) (\lam t => (d (x.1 + t.1 *c a, t.2.2) a' (t.1, t.2.3)).1 + (d x a (t.1, t.2.2)).1)
(\lam t => (d _ _ (_, _)).2 *> pmap (- _) (pmap f (ext $ rewrite *c-ldistr $ inv +-assoc) *> inv zro-right *> pmap (_ +) (inv negative-left) *> inv +-assoc) *> +-assoc *> inv (pmap2 (+) (d _ _ (_, _)).2 (d _ _ (_, _)).2) *> inv B.*c-ldistr)
(0, (sub-lem x, sub-lem x, rewrite (A.*c_zro-left, zro-right) (sub-lem x)))
\in s *> +-comm *> pmap (_ +) (IsDiff.IsDiff-eq Bd Uo d (pmap (x.1 +) A.*c_zro-left *> zro-right) idp)
| func-*c {r} {a} =>
\have s => cancel-lem Bd {\lam t => \Sigma (U (x.1 + t *c (r *c a))) (U (x.1 + t * r *c a))} (\lam t => meet-isOpenProp (Uo _) (Uo _)) (\lam t => (d x (r *c a) (t.1, t.2.1)).1) (\lam t => r *c (d x a (t.1 * r, t.2.2)).1)
(\lam t => later (rewrite ((d x (r *c a) (t.1, t.2.1)).2, (d x a (t.1 * r, t.2.2)).2) $ pmap (f __ - f x) $ ext $ pmap (x.1 +) $ inv *c-assoc) *> *c-assoc)
(0, (sub-lem x, rewrite *c-assoc $ sub-lem x))
\in s *> pmap (r *c) (IsDiff.IsDiff-eq Bd Uo d idp R.zro_*-left)
\where
\lemma sub-lem {A : LModule} {U : A -> \Prop} {a : A} (x : \Sigma (a : A) (U a)) : U (x.1 + 0 *c a)
=> transportInv U (pmap (x.1 +) A.*c_zro-left *> zro-right) x.2
-- | The derivative of a linear map is the map itself
\func linear_diff {A B : LModule R} (Bd : IsInvDense B) (f : LinearMap A B) : IsDiffT Bd f
=> \lam x a t => (f a, rewrite (+-comm,f.func-+) $ inv (simplify f.func-*c))
-- | The derivative of a constant map is zero
\func const_diff {A B : LModule R} (Bd : IsInvDense B) (b : B) : IsDiffT Bd (\lam (_ : A) => b)
=> \lam x a t => (0, B.*c_zro-right *> inv negative-right)
-- | The derivative of a sum is the sum of derivatives
\func +_diff {A B : LModule R} (Bd : IsInvDense B) {U : A -> \Prop} (Uo : IsOpenPred U)
{f g : \Sigma (a : A) (U a) -> B} (df : IsDiff Bd Uo f) (dg : IsDiff Bd Uo g) : IsDiff Bd Uo (\lam x => f x + g x)
=> \lam x a t => ((df x a t).1 + (dg x a t).1, B.*c-ldistr *> pmap2 (+) (df x a t).2 (dg x a t).2 *> equation *> inv (pmap (_ +) AddGroup.negative_+))
{- | Differentiable maps are closed under composition.
-
- The chain rule `deriv (o_diff df dg) x a = deriv dg (f x) (deriv df x a)` follows from this by `idp`.
-}
\func o_diff {A B C : LModule R} (Bd : IsInvDense B) (Cd : IsInvDense C) {U : A -> \Prop} (Uo : IsOpenPred U) {V : B -> \Prop} (Vo : IsOpenPred V)
{f : \Sigma (a : A) (U a) -> \Sigma (b : B) (V b)} {g : \Sigma (b : B) (V b) -> C}
(df : IsDiff Bd Uo (f __).1) (dg : IsDiff Cd Vo g) : IsDiff Cd Uo (\lam x => g (f x))
=> \lam x a t => \have s => dg (f x) (df x a t).1 (t.1, rewrite (df x a t).2 $ transport V simplify (f (x.1 + t.1 *c a, t.2)).2)
\in (s.1, s.2 *> pmap (g __ - _) (ext $ rewrite (df x a t).2 $ +-comm *> simplify))
-- | Bilinear maps are differentiable
\func bilinear_diff {A B C : LModule R} (Cd : IsInvDense C) (m : BilinearMap A B C) : IsDiffT Cd (\lam (p : \Sigma A B) => m p.1 p.2)
=> \lam (x,_) a (t,_) => (m x.1 a.2 + m a.1 x.2 + t *c m a.1 a.2, rewrite (m.linear-left.func-+, m.linear-right.func-+, m.linear-left.func-*c, m.linear-right.func-*c) $
later (rewrite (negative-left,zro-left,*c-ldistr,*c-ldistr) $ +-assoc *> pmap (_ +) (pmap (_ + _ *c __) (inv m.linear-right.func-*c) *> inv *c-ldistr *> pmap (_ *c) (inv m.linear-right.func-+))) *> pmap (+ _) +-assoc *> +-assoc *> +-comm)
}