declaration:
theorem Inner.inner.arg_a0a1.revDerivUpdate_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (g : X → Y) (hf : SciLean.HasAdjDiff R f) (hg : SciLean.HasAdjDiff R g) : (SciLean.revDerivUpdate R fun x => ⟪f x, g x⟫_R) = fun x =>
  let y₁df := SciLean.revDerivUpdate R f x;
  let y₂dg := SciLean.revDerivUpdate R g x;
  (⟪y₁df.1, y₂dg.1⟫_R, fun dr dx => y₂dg.2 (dr • y₁df.1) (y₁df.2 (dr • y₂dg.1) dx))


declaration:
theorem Prod.fst.arg_self.revDerivProjUpdate_rule {K : Type} [RCLike K] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {X' : Type} {Xi : Type} {XI : Xi → Type} [SciLean.StructType X' Xi XI] [DecidableEq Xi] [SciLean.SemiInnerProductSpace K X'] [(i : Xi) → SciLean.SemiInnerProductSpace K (XI i)] {W : Type} [SciLean.SemiInnerProductSpace K W] (f : W → X' × Y) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivProjUpdate K Xi fun x => (f x).1) = fun w =>
  let xydf := SciLean.revDerivProjUpdate K (Xi ⊕ Unit) f w;
  (xydf.1.1, fun i dxy dw => xydf.2 (Sum.inl i) dxy dw)


declaration:
theorem HSMul.hSMul.arg_a0a1.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y Yi YI] [SciLean.IndexType Yi] [SciLean.LawfulIndexType Yi] [DecidableEq Yi] [SciLean.SemiHilbert K Y] [(i : Yi) → SciLean.SemiHilbert K (YI i)] [SciLean.SemiInnerProductSpaceStruct K Y Yi YI] (f : X → K) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProjUpdate K Yi fun x => f x • g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDerivProjUpdate K Yi g x;
  (ydf.1 • zdg.1, fun i dy dx =>
    let dk := ⟪SciLean.structProj zdg.1 i, dy⟫_K;
    let dy' := (starRingEnd K) ydf.1 • dy;
    let dx := zdg.2 i dy' dx;
    ydf.2 dk dx)


SciLean.revDeriv'

declaration: def SciLean.revDeriv' (K : Type u_1) [RCLike K] {X : Type u_2} [SciLean.SemiInnerProductSpace K X] {Y : Type u_3} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) : Y × Y ⊸[K] X


SciLean.revDerivUpdate

declaration: def SciLean.revDerivUpdate (K : Type u_1) [RCLike K] {X : Type u_2} [SciLean.SemiInnerProductSpace K X] {Y : Type u_3} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) : Y × (Y → X → X)


declaration:
theorem HSub.hSub.arg_a0a1.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (f : X → Y') (g : X → Y') (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProjUpdate K Yi fun x => f x - g x) = fun x =>
  let ydf := SciLean.revDerivProjUpdate K Yi f x;
  let ydg := SciLean.revDerivProjUpdate K Yi g x;
  (ydf.1 - ydg.1, fun i dy dx =>
    let dx := ydf.2 i dy dx;
    let dy' := -dy;
    ydg.2 i dy' dx)


declaration:
theorem SciLean.norm₂.arg_x.revDerivProj_rule_at {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (x : X) (hf : SciLean.HasAdjDiffAt R f x) (hx : f x ≠ 0) : SciLean.revDerivProj R Unit (fun x => ‖f x‖₂[R]) x =
  let ydf := SciLean.revDeriv R f x;
  let ynorm := ‖ydf.1‖₂[R];
  (ynorm, fun x dr => (ynorm⁻¹ * dr) • ydf.2 ydf.1)


declaration:
theorem Prod.mk.arg_fstsnd.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {Z : Type} [SciLean.SemiInnerProductSpace K Z] (g : X → Y) (f : X → Z) (hg : SciLean.HasAdjDiff K g) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivUpdate K fun x => (g x, f x)) = fun x =>
  let ydg := SciLean.revDerivUpdate K g x;
  let zdf := SciLean.revDerivUpdate K f x;
  ((ydg.1, zdf.1), fun dyz dx =>
    let dx := ydg.2 dyz.1 dx;
    zdf.2 dyz.2 dx)


SciLean.gradient

declaration: def SciLean.gradient (K : Type u_1) [RCLike K] {X : Type u_2} [SciLean.SemiInnerProductSpace K X] {Y : Type u_3} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) : Y → X


declaration:
theorem HSub.hSub.arg_a0a1.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDeriv K fun x => f x - g x) = fun x =>
  let ydf := SciLean.revDeriv K f x;
  let ydg := SciLean.revDerivUpdate K g x;
  (ydf.1 - ydg.1, fun dy =>
    let dx := ydf.2 dy;
    let dy' := -dy;
    ydg.2 dy' dx)


declaration:
def HPow.hPow.arg_a0.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (n : ℕ) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivProjUpdate K Unit fun x => f x ^ n) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let y' := ↑n * (starRingEnd K) ydf.1 ^ (n - 1);
  (ydf.1 ^ n, fun x dy dx => ydf.2 (y' * dy) dx)


declaration:
theorem Prod.snd.arg_self.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {Z : Type} [SciLean.SemiInnerProductSpace K Z] (f : X → Y × Z) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivUpdate K fun x => (f x).2) = fun x =>
  let yzdf := SciLean.revDerivProjUpdate K (Unit ⊕ Unit) f x;
  (yzdf.1.2, fun dy dx => yzdf.2 (Sum.inr ()) dy dx)


declaration: theorem SciLean.revDerivProj.apply_rule (K : Type u_5) (I : Type u_1) [RCLike K] {ι : Type u_2} [SciLean.IndexType ι] [DecidableEq ι] {E : Type u_3} {EI : I → Type u_4} [SciLean.StructType E I EI] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] [DecidableEq I] (i : ι) : (SciLean.revDerivProj K I fun f => f i) = fun f => (f i, fun j dxj => SciLean.oneHot (i, j) dxj)


declaration:
theorem dite.arg_te.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (c : Prop) [dec : Decidable c] (t : c → X → Y') (e : ¬c → X → Y') : (SciLean.revDerivProj K Yi fun x => if x_1 : c then t x_1 x else e x_1 x) = fun y =>
  if p : c then SciLean.revDerivProj K Yi (t p) y else SciLean.revDerivProj K Yi (e p) y


declaration:
theorem SciLean.revDeriv.comp_rule (K : Type u_1) [RCLike K] {X : Type u_4} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {Z : Type u_3} [SciLean.SemiInnerProductSpace K Z] (f : Y → Z) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDeriv K fun x => f (g x)) = fun x =>
  let ydg := SciLean.revDeriv K g x;
  let zdf := SciLean.revDeriv K f ydg.1;
  (zdf.1, fun dz =>
    let dy := zdf.2 dz;
    ydg.2 dy)


declaration:
theorem dite.arg_te.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (c : Prop) [dec : Decidable c] (t : c → X → Y') (e : ¬c → X → Y') : (SciLean.revDerivProjUpdate K Yi fun x => if x_1 : c then t x_1 x else e x_1 x) = fun y =>
  if p : c then SciLean.revDerivProjUpdate K Yi (t p) y else SciLean.revDerivProjUpdate K Yi (e p) y


declaration:
theorem SciLean.revDerivProjUpdate.let_rule (K : Type u_1) (I : Type u_5) [RCLike K] {X : Type u_3} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {E : Type u_4} {EI : I → Type u_6} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : X → Y → E) (g : X → Y) (hf : SciLean.HasAdjDiff K fun x =>
  match x with
  | (x, y) => f x y) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProjUpdate K I fun x =>
    let y := g x;
    f x y) =
  fun x =>
  let ydg' := SciLean.revDerivUpdate K g x;
  let zdf' :=
    SciLean.revDerivProjUpdate K I
      (fun x =>
        match x with
        | (x, y) => f x y)
      (x, ydg'.1);
  (zdf'.1, fun i dei dx =>
    let dxy := zdf'.2 i dei (dx, 0);
    ydg'.2 dxy.2 dxy.1)


declaration:
theorem dite.arg_te.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (c : Prop) [dec : Decidable c] (t : c → X → Y) (e : ¬c → X → Y) : (SciLean.revDeriv K fun x => if x_1 : c then t x_1 x else e x_1 x) = fun y =>
  if p : c then SciLean.revDeriv K (t p) y else SciLean.revDeriv K (e p) y


declaration:
theorem SciLean.revDerivProjUpdate.apply_rule (K : Type u_5) (I : Type u_1) [RCLike K] {ι : Type u_2} [SciLean.IndexType ι] [DecidableEq ι] {E : Type u_3} {EI : I → Type u_4} [SciLean.StructType E I EI] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] [DecidableEq I] (i : ι) : (SciLean.revDerivProjUpdate K I fun f => f i) = fun f =>
  (f i, fun j dxj df i' => if i = i' then SciLean.structModify j (fun xj => xj + dxj) (df i') else df i')


SciLean.revDerivProj

declaration: def SciLean.revDerivProj (K : Type u_1) (I : Type u_2) [RCLike K] {X : Type u_3} [SciLean.SemiInnerProductSpace K X] {E : Type u_4} {EI : I → Type u_5} [SciLean.StructType E I EI] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] [DecidableEq I] (f : X → E) (x : X) : E × ((i : I) → EI i → X)


declaration:
theorem Neg.neg.arg_a0.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (f : X → Y') : (SciLean.revDerivProj K Yi fun x => -f x) = fun x =>
  let ydf := SciLean.revDerivProj K Yi f x;
  (-ydf.1, fun i dy =>
    let dy' := -dy;
    ydf.2 i dy')


declaration:
theorem ite.arg_te.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (c : Prop) [dec : Decidable c] (t : X → Y') (e : X → Y') : (SciLean.revDerivProjUpdate K Yi fun x => if c then t x else e x) = fun y =>
  if c then SciLean.revDerivProjUpdate K Yi t y else SciLean.revDerivProjUpdate K Yi e y


declaration:
theorem Prod.fst.arg_self.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {Z : Type} [SciLean.SemiInnerProductSpace K Z] (f : X → Y × Z) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivUpdate K fun x => (f x).1) = fun x =>
  let yzdf := SciLean.revDerivProjUpdate K (Unit ⊕ Unit) f x;
  (yzdf.1.1, fun dy dx => yzdf.2 (Sum.inl ()) dy dx)


declaration:
theorem Prod.snd.arg_self.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] {W : Type} [SciLean.SemiInnerProductSpace K W] (f : W → X × Y') (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivProj K Yi fun x => (f x).2) = fun w =>
  let xydf := SciLean.revDerivProj K (Unit ⊕ Yi) f w;
  (xydf.1.2, fun i dxy => xydf.2 (Sum.inr i) dxy)


SciLean.scalarGradient

declaration: def SciLean.scalarGradient (K : Type u_1) [RCLike K] {X : Type u_2} [SciLean.SemiInnerProductSpace K X] (f : X → K) (x : X) : X


declaration:
theorem Prod.fst.arg_self.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {Z : Type} [SciLean.SemiInnerProductSpace K Z] (f : X → Y × Z) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDeriv K fun x => (f x).1) = fun x =>
  let yzdf := SciLean.revDerivProj K (Unit ⊕ Unit) f x;
  (yzdf.1.1, fun dy => yzdf.2 (Sum.inl ()) dy)


declaration:
theorem HDiv.hDiv.arg_a0a1.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (g : X → K) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) (hx : SciLean.fpropParam (∀ (x : X), g x ≠ 0)) : (SciLean.revDeriv K fun x => f x / g x) = fun x =>
  let ydf := SciLean.revDeriv K f x;
  let zdg := SciLean.revDerivUpdate K g x;
  (ydf.1 / zdg.1, fun dx' =>
    (1 / (starRingEnd K) zdg.1 ^ 2) • zdg.2 (-(starRingEnd K) ydf.1 • dx') ((starRingEnd K) zdg.1 • ydf.2 dx'))


declaration:
theorem Neg.neg.arg_a0.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (f : X → Y') : (SciLean.revDerivProjUpdate K Yi fun x => -f x) = fun x =>
  let ydf := SciLean.revDerivProjUpdate K Yi f x;
  (-ydf.1, fun i dy dx =>
    let dy' := -dy;
    ydf.2 i dy' dx)


declaration:
theorem ite.arg_te.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (c : Prop) [dec : Decidable c] (t : X → Y') (e : X → Y') : (SciLean.revDerivProj K Yi fun x => if c then t x else e x) = fun y =>
  if c then SciLean.revDerivProj K Yi t y else SciLean.revDerivProj K Yi e y


declaration:
theorem HSMul.hSMul.arg_a0a1.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiHilbert K Y] (f : X → K) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivUpdate K fun x => f x • g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDerivUpdate K g x;
  (ydf.1 • zdg.1, fun dy dx =>
    let dk := ⟪zdg.1, dy⟫_K;
    let dy' := (starRingEnd K) ydf.1 • dy;
    let dx := zdg.2 dy' dx;
    ydf.2 dk dx)


declaration:
def HPow.hPow.arg_a0.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (n : ℕ) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivProj K Unit fun x => f x ^ n) = fun x =>
  let ydf := SciLean.revDeriv K f x;
  let y' := ↑n * (starRingEnd K) ydf.1 ^ (n - 1);
  (ydf.1 ^ n, fun x dx' => ydf.2 (y' * dx'))


declaration:
theorem HMul.hMul.arg_a0a1.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (g : X → K) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivUpdate K fun x => f x * g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDerivUpdate K g x;
  (ydf.1 * zdg.1, fun dx' dx =>
    let dx₁ := (starRingEnd K) zdg.1 * dx';
    let dx₂ := (starRingEnd K) ydf.1 * dx';
    let dx := zdg.2 dx₂ dx;
    ydf.2 dx₁ dx)


declaration:
theorem SciLean.revDerivUpdate.comp_rule (K : Type u_1) [RCLike K] {X : Type u_4} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {Z : Type u_3} [SciLean.SemiInnerProductSpace K Z] (f : Y → Z) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivUpdate K fun x => f (g x)) = fun x =>
  let ydg := SciLean.revDerivUpdate K g x;
  let zdf := SciLean.revDeriv K f ydg.1;
  (zdf.1, fun dz dx =>
    let dy := zdf.2 dz;
    ydg.2 dy dx)


declaration:
theorem HSMul.hSMul.arg_a0a1.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y Yi YI] [SciLean.IndexType Yi] [SciLean.LawfulIndexType Yi] [DecidableEq Yi] [SciLean.SemiHilbert K Y] [(i : Yi) → SciLean.SemiHilbert K (YI i)] [SciLean.SemiInnerProductSpaceStruct K Y Yi YI] (f : X → K) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProj K Yi fun x => f x • g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDerivProj K Yi g x;
  (ydf.1 • zdg.1, fun i dy =>
    let dk := ⟪SciLean.structProj zdg.1 i, dy⟫_K;
    let dx := zdg.2 i dy;
    let dx := (starRingEnd K) ydf.1 • dx;
    ydf.2 dk dx)


declaration:
theorem SciLean.revDerivUpdate.pi_rule (K : Type u_1) (I : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {EI : I → Type u_2} [SciLean.IndexType I] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : X → (i : I) → EI i) (hf : ∀ (i : I), SciLean.HasAdjDiff K fun x => f x i) : (SciLean.revDerivUpdate K fun x i => f x i) = fun x =>
  let xdf := fun i => SciLean.revDerivUpdate K (fun x => f x i) x;
  (fun i => (xdf i).1, fun dy dx => LeanColls.fold (SciLean.IndexType.univ I) (fun dx i => (xdf i).2 (dy i) dx) dx)


declaration: theorem SciLean.revDerivProjUpdate_fst (K : Type u_5) (I : Type u_2) [RCLike K] {X : Type u_3} [SciLean.SemiInnerProductSpace K X] {E : Type u_1} {EI : I → Type u_4} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : X → E) (x : X) : (SciLean.revDerivProjUpdate K I f x).1 = f x


declaration: theorem SciLean.revDerivProj_fst (K : Type u_5) (I : Type u_2) [RCLike K] {X : Type u_3} [SciLean.SemiInnerProductSpace K X] {E : Type u_1} {EI : I → Type u_4} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : X → E) (x : X) : (SciLean.revDerivProj K I f x).1 = f x


declaration:
theorem SciLean.revDeriv.let_rule (K : Type u_1) [RCLike K] {X : Type u_2} [SciLean.SemiInnerProductSpace K X] {Y : Type u_3} [SciLean.SemiInnerProductSpace K Y] {Z : Type u_4} [SciLean.SemiInnerProductSpace K Z] (f : X → Y → Z) (g : X → Y) (hf : SciLean.HasAdjDiff K fun xy => f xy.1 xy.2) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDeriv K fun x =>
    let y := g x;
    f x y) =
  fun x =>
  let ydg := SciLean.revDerivUpdate K g x;
  let zdf := SciLean.revDeriv K (fun xy => f xy.1 xy.2) (x, ydg.1);
  (zdf.1, fun dz =>
    let dxdy := zdf.2 dz;
    let dx := ydg.2 dxdy.2 dxdy.1;
    dx)


declaration: theorem SciLean.revDeriv.id_rule (K : Type u_2) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] : (SciLean.revDeriv K fun x => x) = fun x => (x, fun dx => dx)


declaration: theorem SciLean.revDerivProj.const_rule (K : Type u_5) (I : Type u_1) [RCLike K] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {E : Type u_3} {EI : I → Type u_4} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (x : E) : (SciLean.revDerivProj K I fun x_1 => x) = fun x_1 => (x, fun i de => 0)


declaration: theorem SciLean.revDerivProjUpdate_snd_zero' (K : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) (dy : Y) : (SciLean.revDerivUpdate K f x).2 dy 0 = (SciLean.revDeriv K f x).2 dy


declaration:
theorem Prod.snd.arg_self.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {Z : Type} [SciLean.SemiInnerProductSpace K Z] (f : X → Y × Z) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDeriv K fun x => (f x).2) = fun x =>
  let yzdf := SciLean.revDerivProj K (Unit ⊕ Unit) f x;
  (yzdf.1.2, fun dy => yzdf.2 (Sum.inr ()) dy)


declaration:
theorem HDiv.hDiv.arg_a0a1.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (g : X → K) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) (hx : ∀ (x : X), g x ≠ 0) : (SciLean.revDerivProj K Unit fun x => f x / g x) = fun x =>
  let ydf := SciLean.revDeriv K f x;
  let zdg := SciLean.revDerivUpdate K g x;
  (ydf.1 / zdg.1, fun x dx' =>
    (1 / (starRingEnd K) zdg.1 ^ 2) • zdg.2 (-(starRingEnd K) ydf.1 • dx') ((starRingEnd K) zdg.1 • ydf.2 dx'))


declaration:
theorem SciLean.Norm2.norm2.arg_a0.revDeriv_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (hf : SciLean.HasAdjDiff R f) : (SciLean.revDeriv R fun x => ‖f x‖₂²) = fun x =>
  let ydf := SciLean.revDeriv R f x;
  let ynorm2 := ‖ydf.1‖₂²;
  (ynorm2, fun dr => (2 * dr) • ydf.2 ydf.1)


declaration:
theorem Neg.neg.arg_a0.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) : SciLean.revDeriv K (fun x => -f x) x =
  let ydf := SciLean.revDeriv K f x;
  (-ydf.1, fun dy =>
    let dx := ydf.2 dy;
    -dx)


declaration:
theorem HMul.hMul.arg_a0a1.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (g : X → K) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProjUpdate K Unit fun x => f x * g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDerivUpdate K g x;
  (ydf.1 * zdg.1, fun x dy dx =>
    let dy₁ := (starRingEnd K) zdg.1 * dy;
    let dy₂ := (starRingEnd K) ydf.1 * dy;
    let dx := zdg.2 dy₂ dx;
    ydf.2 dy₁ dx)


SciLean.revDeriv

declaration: def SciLean.revDeriv (K : Type u_1) [RCLike K] {X : Type u_2} [SciLean.SemiInnerProductSpace K X] {Y : Type u_3} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) : Y × (Y → X)


declaration:
theorem Neg.neg.arg_a0.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) : (SciLean.revDerivUpdate K fun x => -f x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  (-ydf.1, fun dy dx =>
    let dy' := -dy;
    ydf.2 dy' dx)


declaration:
theorem SciLean.revDeriv.pi_rule (K : Type u_1) (I : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {EI : I → Type u_2} [SciLean.IndexType I] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : X → (i : I) → EI i) (hf : ∀ (i : I), SciLean.HasAdjDiff K fun x => f x i) : (SciLean.revDeriv K fun x i => f x i) = fun x =>
  let xdf := fun i => SciLean.revDerivUpdate K (fun x => f x i) x;
  (fun i => (xdf i).1, fun dy => LeanColls.fold (SciLean.IndexType.univ I) (fun dx i => (xdf i).2 (dy i) dx) 0)


declaration:
theorem dite.arg_te.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (c : Prop) [dec : Decidable c] (t : c → X → Y) (e : ¬c → X → Y) : (SciLean.revDerivUpdate K fun x => if x_1 : c then t x_1 x else e x_1 x) = fun y =>
  if p : c then SciLean.revDerivUpdate K (t p) y else SciLean.revDerivUpdate K (e p) y


declaration:
theorem Prod.snd.arg_self.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] {W : Type} [SciLean.SemiInnerProductSpace K W] (f : W → X × Y') (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivProjUpdate K Yi fun x => (f x).2) = fun w =>
  let xydf := SciLean.revDerivProjUpdate K (Unit ⊕ Yi) f w;
  (xydf.1.2, fun i dxy dw => xydf.2 (Sum.inr i) dxy dw)


declaration: theorem SciLean.revDerivProj.id_rule (K : Type u_4) (I : Type u_1) [RCLike K] {E : Type u_2} {EI : I → Type u_3} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] : (SciLean.revDerivProj K I fun x => x) = fun x => (x, fun i de => SciLean.oneHot i de)


declaration: theorem SciLean.revDerivProj_snd_zero (K : Type u_5) (I : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {E : Type u_2} {EI : I → Type u_4} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : X → E) (x : X) (i : I) : (SciLean.revDerivProj K I f x).2 i 0 = 0


declaration:
theorem SciLean.revDerivProjUpdate.comp_rule (K : Type u_1) (I : Type u_5) [RCLike K] {X : Type u_4} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {E : Type u_3} {EI : I → Type u_6} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : Y → E) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProjUpdate K I fun x => f (g x)) = fun x =>
  let ydg' := SciLean.revDerivUpdate K g x;
  let zdf' := SciLean.revDerivProj K I f ydg'.1;
  (zdf'.1, fun i de dx => ydg'.2 (zdf'.2 i de) dx)


declaration:
theorem SciLean.norm₂.arg_x.revDeriv_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (hf : SciLean.HasAdjDiff R f) (hx : ∀ (x : X), f x ≠ 0) : (SciLean.revDeriv R fun x => ‖f x‖₂[R]) = fun x =>
  let ydf := SciLean.revDeriv R f x;
  let ynorm := ‖ydf.1‖₂[R];
  (ynorm, fun dr => (ynorm⁻¹ * dr) • ydf.2 ydf.1)


declaration: theorem SciLean.revDerivProjUpdate.const_rule (K : Type u_5) (I : Type u_1) [RCLike K] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {E : Type u_3} {EI : I → Type u_4} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (x : E) : (SciLean.revDerivProjUpdate K I fun x_1 => x) = fun x_1 => (x, fun i de dx => dx)


declaration:
theorem IndexType.sum.arg_f.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] {ι : Type} [SciLean.IndexType ι] [DecidableEq ι] (f : X → ι → Y') (hf : ∀ (i : ι), SciLean.HasAdjDiff K fun x => f x i) : (SciLean.revDerivProj K Yi fun x =>  ∑ i, f x i) = fun x =>
  let ydf := SciLean.revDerivProjUpdate K (ι × Yi) f x;
  ( ∑ i, ydf.1 i, fun j dy => LeanColls.fold (SciLean.IndexType.univ ι) (fun dx i => ydf.2 (i, j) dy dx) 0)


declaration:
theorem SciLean.norm₂.arg_x.revDerivProj_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (hf : SciLean.HasAdjDiff R f) (hx : ∀ (x : X), f x ≠ 0) : (SciLean.revDerivProj R Unit fun x => ‖f x‖₂[R]) = fun x =>
  let ydf := SciLean.revDeriv R f x;
  let ynorm := ‖ydf.1‖₂[R];
  (ynorm, fun x dr => (ynorm⁻¹ * dr) • ydf.2 ydf.1)


declaration:
theorem HAdd.hAdd.arg_a0a1.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivUpdate K fun x => f x + g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let ydg := SciLean.revDerivUpdate K g x;
  (ydf.1 + ydg.1, fun dy dx =>
    let dx := ydf.2 dy dx;
    ydg.2 dy dx)


declaration:
theorem Prod.mk.arg_fstsnd.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] {Z' : Type} {Zi : Type} {ZI : Zi → Type} [SciLean.StructType Z' Zi ZI] [DecidableEq Zi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] [SciLean.SemiInnerProductSpace K Z'] [(i : Zi) → SciLean.SemiInnerProductSpace K (ZI i)] (g : X → Y') (f : X → Z') (hg : SciLean.HasAdjDiff K g) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivProj K (Yi ⊕ Zi) fun x => (g x, f x)) = fun x =>
  let ydg := SciLean.revDerivProj K Yi g x;
  let zdf := SciLean.revDerivProj K Zi f x;
  ((ydg.1, zdf.1), fun i dyz =>
    match i, dyz with
    | Sum.inl j, dyz => ydg.2 j dyz
    | Sum.inr j, dyz => zdf.2 j dyz)


declaration:
theorem ite.arg_te.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (c : Prop) [dec : Decidable c] (t : X → Y) (e : X → Y) : (SciLean.revDerivUpdate K fun x => if c then t x else e x) = fun y =>
  if c then SciLean.revDerivUpdate K t y else SciLean.revDerivUpdate K e y


declaration: theorem SciLean.revDerivUpdate_snd_zero' (K : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) (dy : Y) : (SciLean.revDerivUpdate K f x).2 dy 0 = (SciLean.revDeriv K f x).2 dy


declaration: theorem SciLean.revDerivUpdate_fst (K : Type u_3) [RCLike K] {X : Type u_2} [SciLean.SemiInnerProductSpace K X] {Y : Type u_1} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) : (SciLean.revDerivUpdate K f x).1 = f x


declaration:
theorem Prod.mk.arg_fstsnd.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] {Z' : Type} {Zi : Type} {ZI : Zi → Type} [SciLean.StructType Z' Zi ZI] [DecidableEq Zi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] [SciLean.SemiInnerProductSpace K Z'] [(i : Zi) → SciLean.SemiInnerProductSpace K (ZI i)] (g : X → Y') (f : X → Z') (hg : SciLean.HasAdjDiff K g) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivProjUpdate K (Yi ⊕ Zi) fun x => (g x, f x)) = fun x =>
  let ydg := SciLean.revDerivProjUpdate K Yi g x;
  let zdf := SciLean.revDerivProjUpdate K Zi f x;
  ((ydg.1, zdf.1), fun i dyz dx =>
    match i, dyz with
    | Sum.inl j, dyz => ydg.2 j dyz dx
    | Sum.inr j, dyz => zdf.2 j dyz dx)


declaration:
theorem HMul.hMul.arg_a0a1.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (g : X → K) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDeriv K fun x => f x * g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDeriv K g x;
  (ydf.1 * zdg.1, fun dx' =>
    let dx₁ := (starRingEnd K) zdg.1 * dx';
    let dx₂ := (starRingEnd K) ydf.1 * dx';
    let dx := zdg.2 dx₂;
    ydf.2 dx₁ dx)


declaration:
theorem Inner.inner.arg_a0a1.revDeriv_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (g : X → Y) (hf : SciLean.HasAdjDiff R f) (hg : SciLean.HasAdjDiff R g) : (SciLean.revDeriv R fun x => ⟪f x, g x⟫_R) = fun x =>
  let y₁df := SciLean.revDeriv R f x;
  let y₂dg := SciLean.revDerivUpdate R g x;
  (⟪y₁df.1, y₂dg.1⟫_R, fun dr => y₂dg.2 (dr • y₁df.1) (y₁df.2 (dr • y₂dg.1)))


declaration: theorem SciLean.revDerivUpdate_snd_zero (K : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) (dx : X) : (SciLean.revDerivUpdate K f x).2 0 dx = dx


declaration:
theorem SciLean.norm₂.arg_x.revDerivUpdate_rule_at {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (x : X) (hf : SciLean.HasAdjDiffAt R f x) (hx : f x ≠ 0) : SciLean.revDerivUpdate R (fun x => ‖f x‖₂[R]) x =
  let ydf := SciLean.revDerivUpdate R f x;
  let ynorm := ‖ydf.1‖₂[R];
  (ynorm, fun dr dx => ydf.2 ((ynorm⁻¹ * dr) • ydf.1) dx)


declaration: theorem SciLean.revDerivProjUpdate_snd_zero (K : Type u_5) (I : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {E : Type u_2} {EI : I → Type u_4} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : X → E) (x : X) (dx : X) (i : I) : (SciLean.revDerivProjUpdate K I f x).2 i 0 dx = dx


declaration:
theorem HAdd.hAdd.arg_a0a1.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (f : X → Y') (g : X → Y') (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProjUpdate K Yi fun x => f x + g x) = fun x =>
  let ydf := SciLean.revDerivProjUpdate K Yi f x;
  let ydg := SciLean.revDerivProjUpdate K Yi g x;
  (ydf.1 + ydg.1, fun i dy dx =>
    let dx := ydf.2 i dy dx;
    ydg.2 i dy dx)


declaration:
theorem SciLean.revDerivProjUpdate.pi_rule (K : Type u_1) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {ι : Type u_3} [SciLean.IndexType ι] (f : X → ι → Y) (hf : ∀ (i : ι), SciLean.HasAdjDiff K fun x => f x i) : (SciLean.revDerivProjUpdate K Unit fun x i => f x i) = fun x =>
  let ydf := fun i => SciLean.revDerivUpdate K (fun x => f x i) x;
  (fun i => (ydf i).1, fun x df dx => LeanColls.fold (SciLean.IndexType.univ ι) (fun dx i => (ydf i).2 (df i) dx) dx)


declaration:
def HPow.hPow.arg_a0.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (n : ℕ) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivUpdate K fun x => f x ^ n) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let y' := ↑n * (starRingEnd K) ydf.1 ^ (n - 1);
  (ydf.1 ^ n, fun dy dx => ydf.2 (y' * dy) dx)


declaration: theorem SciLean.revDeriv_fst (K : Type u_3) [RCLike K] {X : Type u_2} [SciLean.SemiInnerProductSpace K X] {Y : Type u_1} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) : (SciLean.revDeriv K f x).1 = f x


declaration:
theorem ite.arg_te.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (c : Prop) [dec : Decidable c] (t : X → Y) (e : X → Y) : (SciLean.revDeriv K fun x => if c then t x else e x) = fun y =>
  if c then SciLean.revDeriv K t y else SciLean.revDeriv K e y


declaration:
theorem HSub.hSub.arg_a0a1.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivUpdate K fun x => f x - g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let ydg := SciLean.revDerivUpdate K g x;
  (ydf.1 - ydg.1, fun dy dx =>
    let dx := ydf.2 dy dx;
    let dy' := -dy;
    ydg.2 dy' dx)


declaration:
theorem SciLean.norm₂.arg_x.revDerivUpdate_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (hf : SciLean.HasAdjDiff R f) (hx : ∀ (x : X), f x ≠ 0) : (SciLean.revDerivUpdate R fun x => ‖f x‖₂[R]) = fun x =>
  let ydf := SciLean.revDerivUpdate R f x;
  let ynorm := ‖ydf.1‖₂[R];
  (ynorm, fun dr dx => ydf.2 ((ynorm⁻¹ * dr) • ydf.1) dx)


declaration:
theorem HSMul.hSMul.arg_a0a1.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiHilbert K Y] (f : X → K) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDeriv K fun x => f x • g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDeriv K g x;
  (ydf.1 • zdg.1, fun dy' =>
    let dk := ⟪zdg.1, dy'⟫_K;
    let dx := zdg.2 dy';
    let dx := (starRingEnd K) ydf.1 • dx;
    ydf.2 dk dx)


declaration:
theorem HAdd.hAdd.arg_a0a1.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (f : X → Y') (g : X → Y') (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProj K Yi fun x => f x + g x) = fun x =>
  let ydf := SciLean.revDerivProj K Yi f x;
  let ydg := SciLean.revDerivProjUpdate K Yi g x;
  (ydf.1 + ydg.1, fun i dy =>
    let dx := ydf.2 i dy;
    ydg.2 i dy dx)


declaration:
theorem HMul.hMul.arg_a0a1.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (g : X → K) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProj K Unit fun x => f x * g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDeriv K g x;
  (ydf.1 * zdg.1, fun x dy =>
    let dy₁ := (starRingEnd K) zdg.1 * dy;
    let dy₂ := (starRingEnd K) ydf.1 * dy;
    let dx := zdg.2 dy₂;
    ydf.2 dy₁ dx)


declaration:
theorem SciLean.Norm2.norm2.arg_a0.revDerivProj_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (hf : SciLean.HasAdjDiff R f) : (SciLean.revDerivProj R Unit fun x => ‖f x‖₂²) = fun x =>
  let ydf := SciLean.revDeriv R f x;
  let ynorm2 := ‖ydf.1‖₂²;
  (ynorm2, fun x dr => (2 * dr) • ydf.2 ydf.1)


declaration:
theorem SciLean.Norm2.norm2.arg_a0.revDerivUpdate_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (hf : SciLean.HasAdjDiff R f) : (SciLean.revDerivUpdate R fun x => ‖f x‖₂²) = fun x =>
  let ydf := SciLean.revDerivUpdate R f x;
  let ynorm2 := ‖ydf.1‖₂²;
  (ynorm2, fun dr dx => ydf.2 ((2 * dr) • ydf.1) dx)


declaration:
theorem SciLean.norm₂.arg_x.revDeriv_rule_at {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (x : X) (hf : SciLean.HasAdjDiffAt R f x) (hx : f x ≠ 0) : SciLean.revDeriv R (fun x => ‖f x‖₂[R]) x =
  let ydf := SciLean.revDeriv R f x;
  let ynorm := ‖ydf.1‖₂[R];
  (ynorm, fun dr => (ynorm⁻¹ * dr) • ydf.2 ydf.1)


declaration:
theorem SciLean.norm₂.arg_x.revDerivProjUpdate_rule_at {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (x : X) (hf : SciLean.HasAdjDiffAt R f x) (hx : f x ≠ 0) : SciLean.revDerivProjUpdate R Unit (fun x => ‖f x‖₂[R]) x =
  let ydf := SciLean.revDerivUpdate R f x;
  let ynorm := ‖ydf.1‖₂[R];
  (ynorm, fun x dr dx => ydf.2 ((ynorm⁻¹ * dr) • ydf.1) dx)


declaration:
theorem SciLean.revDerivProj.pi_rule (K : Type u_1) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {ι : Type u_3} [SciLean.IndexType ι] (f : X → ι → Y) (hf : ∀ (i : ι), SciLean.HasAdjDiff K fun x => f x i) : (SciLean.revDerivProj K Unit fun x i => f x i) = fun x =>
  let ydf := fun i => SciLean.revDerivUpdate K (fun x => f x i) x;
  (fun i => (ydf i).1, fun x df => LeanColls.fold (SciLean.IndexType.univ ι) (fun dx i => (ydf i).2 (df i) dx) 0)


declaration: theorem SciLean.revDerivProjUpdate.id_rule (K : Type u_4) (I : Type u_1) [RCLike K] {E : Type u_2} {EI : I → Type u_3} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] : (SciLean.revDerivProjUpdate K I fun x => x) = fun x => (x, fun i de dx => SciLean.structModify i (fun ei => ei + de) dx)


declaration: theorem SciLean.revDerivUpdate.id_rule (K : Type u_2) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] : (SciLean.revDerivUpdate K fun x => x) = fun x => (x, fun dx' dx => dx + dx')


declaration:
theorem Inner.inner.arg_a0a1.revDerivProj_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (g : X → Y) (hf : SciLean.HasAdjDiff R f) (hg : SciLean.HasAdjDiff R g) : (SciLean.revDerivProj R Unit fun x => ⟪f x, g x⟫_R) = fun x =>
  let y₁df := SciLean.revDeriv R f x;
  let y₂dg := SciLean.revDerivUpdate R g x;
  (⟪y₁df.1, y₂dg.1⟫_R, fun x dr => y₂dg.2 (dr • y₁df.1) (y₁df.2 (dr • y₂dg.1)))


declaration: theorem SciLean.revDeriv_snd_zero (K : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (x : X) : (SciLean.revDeriv K f x).2 0 = 0


declaration: theorem SciLean.revDeriv.const_rule (K : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] (y : Y) : (SciLean.revDeriv K fun x => y) = fun x => (y, fun x => 0)


declaration:
theorem SciLean.revDerivProj.comp_rule (K : Type u_1) (I : Type u_5) [RCLike K] {X : Type u_4} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {E : Type u_3} {EI : I → Type u_6} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : Y → E) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProj K I fun x => f (g x)) = fun x =>
  let ydg' := SciLean.revDeriv K g x;
  let zdf' := SciLean.revDerivProj K I f ydg'.1;
  (zdf'.1, fun i de => ydg'.2 (zdf'.2 i de))


declaration:
def HPow.hPow.arg_a0.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (n : ℕ) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDeriv K fun x => f x ^ n) = fun x =>
  let ydf := SciLean.revDeriv K f x;
  let y' := ↑n * (starRingEnd K) ydf.1 ^ (n - 1);
  (ydf.1 ^ n, fun dx' => ydf.2 (y' * dx'))


declaration:
theorem HDiv.hDiv.arg_a0a1.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (g : X → K) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) (hx : ∀ (x : X), g x ≠ 0) : (SciLean.revDerivProjUpdate K Unit fun x => f x / g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDerivUpdate K g x;
  (ydf.1 / zdg.1, fun x dx' dx =>
    let c := 1 / (starRingEnd K) zdg.1 ^ 2;
    let a := -(c * (starRingEnd K) ydf.1);
    let b := c * (starRingEnd K) zdg.1;
    zdg.2 (a • dx') (ydf.2 (b • dx') dx))


declaration:
theorem SciLean.norm₂.arg_x.revDerivProjUpdate_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (hf : SciLean.HasAdjDiff R f) (hx : ∀ (x : X), f x ≠ 0) : (SciLean.revDerivProjUpdate R Unit fun x => ‖f x‖₂[R]) = fun x =>
  let ydf := SciLean.revDerivUpdate R f x;
  let ynorm := ‖ydf.1‖₂[R];
  (ynorm, fun x dr dx => ydf.2 ((ynorm⁻¹ * dr) • ydf.1) dx)


declaration:
theorem HAdd.hAdd.arg_a0a1.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] (f : X → Y) (g : X → Y) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDeriv K fun x => f x + g x) = fun x =>
  let ydf := SciLean.revDeriv K f x;
  let ydg := SciLean.revDerivUpdate K g x;
  (ydf.1 + ydg.1, fun dy =>
    let dx := ydf.2 dy;
    ydg.2 dy dx)


declaration:
theorem IndexType.sum.arg_f.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {ι : Type} [SciLean.IndexType ι] (f : X → ι → Y) (hf : ∀ (i : ι), SciLean.HasAdjDiff K fun x => f x i) : (SciLean.revDeriv K fun x =>  ∑ i, f x i) = fun x =>
  let ydf := SciLean.revDeriv K f x;
  ( ∑ i, ydf.1 i, fun dy => ydf.2 fun x => dy)


declaration: theorem SciLean.revDerivUpdate.const_rule (K : Type u_3) [RCLike K] {X : Type u_1} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] (y : Y) : (SciLean.revDerivUpdate K fun x => y) = fun x => (y, fun x dx => dx)


declaration:
theorem Prod.fst.arg_self.revDerivProj_rule {K : Type} [RCLike K] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {X' : Type} {Xi : Type} {XI : Xi → Type} [SciLean.StructType X' Xi XI] [DecidableEq Xi] [SciLean.SemiInnerProductSpace K X'] [(i : Xi) → SciLean.SemiInnerProductSpace K (XI i)] {W : Type} [SciLean.SemiInnerProductSpace K W] (f : W → X' × Y) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDerivProj K Xi fun x => (f x).1) = fun w =>
  let xydf := SciLean.revDerivProj K (Xi ⊕ Unit) f w;
  (xydf.1.1, fun i dxy => xydf.2 (Sum.inl i) dxy)


declaration:
theorem Prod.mk.arg_fstsnd.revDeriv_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {Z : Type} [SciLean.SemiInnerProductSpace K Z] (g : X → Y) (f : X → Z) (hg : SciLean.HasAdjDiff K g) (hf : SciLean.HasAdjDiff K f) : (SciLean.revDeriv K fun x => (g x, f x)) = fun x =>
  let ydg := SciLean.revDeriv K g x;
  let zdf := SciLean.revDerivUpdate K f x;
  ((ydg.1, zdf.1), fun dyz =>
    let dx := ydg.2 dyz.1;
    zdf.2 dyz.2 dx)


declaration:
theorem Inner.inner.arg_a0a1.revDerivProjUpdate_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (g : X → Y) (hf : SciLean.HasAdjDiff R f) (hg : SciLean.HasAdjDiff R g) : (SciLean.revDerivProjUpdate R Unit fun x => ⟪f x, g x⟫_R) = fun x =>
  let y₁df := SciLean.revDerivUpdate R f x;
  let y₂dg := SciLean.revDerivUpdate R g x;
  (⟪y₁df.1, y₂dg.1⟫_R, fun x dr dx => y₂dg.2 (dr • y₁df.1) (y₁df.2 (dr • y₂dg.1) dx))


declaration:
theorem SciLean.Norm2.norm2.arg_a0.revDerivProjUpdate_rule {R : Type u_1} [SciLean.RealScalar R] {X : Type u_2} [SciLean.SemiInnerProductSpace R X] {Y : Type u_3} [SciLean.SemiHilbert R Y] (f : X → Y) (hf : SciLean.HasAdjDiff R f) : (SciLean.revDerivProjUpdate R Unit fun x => ‖f x‖₂²) = fun x =>
  let ydf := SciLean.revDerivUpdate R f x;
  let ynorm2 := ‖ydf.1‖₂²;
  (ynorm2, fun x dr dx => ydf.2 ((2 * dr) • ydf.1) dx)


declaration:
theorem SciLean.revDerivProj.let_rule (K : Type u_1) (I : Type u_5) [RCLike K] {X : Type u_3} [SciLean.SemiInnerProductSpace K X] {Y : Type u_2} [SciLean.SemiInnerProductSpace K Y] {E : Type u_4} {EI : I → Type u_6} [SciLean.StructType E I EI] [DecidableEq I] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (f : X → Y → E) (g : X → Y) (hf : SciLean.HasAdjDiff K fun x =>
  match x with
  | (x, y) => f x y) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProj K I fun x =>
    let y := g x;
    f x y) =
  fun x =>
  let ydg' := SciLean.revDerivUpdate K g x;
  let zdf' :=
    SciLean.revDerivProj K I
      (fun x =>
        match x with
        | (x, y) => f x y)
      (x, ydg'.1);
  (zdf'.1, fun i dei =>
    let dxy := zdf'.2 i dei;
    ydg'.2 dxy.2 dxy.1)


declaration:
theorem SciLean.revDerivUpdate.apply_rule (K : Type u_3) (I : Type u_1) [RCLike K] {EI : I → Type u_2} [SciLean.IndexType I] [DecidableEq I] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (i : I) : (SciLean.revDerivUpdate K fun x => x i) = fun x =>
  (x i, fun dxi dx => SciLean.structModify i (fun dxi' => dxi' + dxi) dx)


declaration: theorem SciLean.revDeriv.apply_rule (K : Type u_3) (I : Type u_1) [RCLike K] {EI : I → Type u_2} [SciLean.IndexType I] [DecidableEq I] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] (i : I) : (SciLean.revDeriv K fun x => x i) = fun x => (x i, fun dxi => SciLean.oneHot i dxi)


declaration:
theorem SciLean.revDerivUpdate.let_rule (K : Type u_1) [RCLike K] {X : Type u_2} [SciLean.SemiInnerProductSpace K X] {Y : Type u_3} [SciLean.SemiInnerProductSpace K Y] {Z : Type u_4} [SciLean.SemiInnerProductSpace K Z] (f : X → Y → Z) (g : X → Y) (hf : SciLean.HasAdjDiff K fun xy => f xy.1 xy.2) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivUpdate K fun x =>
    let y := g x;
    f x y) =
  fun x =>
  let ydg := SciLean.revDerivUpdate K g x;
  let zdf := SciLean.revDerivUpdate K (fun xy => f xy.1 xy.2) (x, ydg.1);
  (zdf.1, fun dz dx =>
    let dxdy := zdf.2 dz (dx, 0);
    let dx := ydg.2 dxdy.2 dxdy.1;
    dx)


declaration:
theorem HDiv.hDiv.arg_a0a1.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] (f : X → K) (g : X → K) (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) (hx : ∀ (x : X), g x ≠ 0) : (SciLean.revDerivUpdate K fun x => f x / g x) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  let zdg := SciLean.revDerivUpdate K g x;
  (ydf.1 / zdg.1, fun dx' dx =>
    let c := 1 / (starRingEnd K) zdg.1 ^ 2;
    let a := -(c * (starRingEnd K) ydf.1);
    let b := c * (starRingEnd K) zdg.1;
    zdg.2 (a • dx') (ydf.2 (b • dx') dx))


declaration:
theorem HSub.hSub.arg_a0a1.revDerivProj_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] (f : X → Y') (g : X → Y') (hf : SciLean.HasAdjDiff K f) (hg : SciLean.HasAdjDiff K g) : (SciLean.revDerivProj K Yi fun x => f x - g x) = fun x =>
  let ydf := SciLean.revDerivProj K Yi f x;
  let ydg := SciLean.revDerivProjUpdate K Yi g x;
  (ydf.1 - ydg.1, fun i dy =>
    let dx := ydf.2 i dy;
    let dy' := -dy;
    ydg.2 i dy' dx)


SciLean.revDerivProjUpdate

declaration: def SciLean.revDerivProjUpdate (K : Type u_1) (I : Type u_2) [RCLike K] {X : Type u_3} [SciLean.SemiInnerProductSpace K X] {E : Type u_4} {EI : I → Type u_5} [SciLean.StructType E I EI] [SciLean.SemiInnerProductSpace K E] [(i : I) → SciLean.SemiInnerProductSpace K (EI i)] [DecidableEq I] (f : X → E) (x : X) : E × ((i : I) → EI i → X → X)


declaration:
theorem IndexType.sum.arg_f.revDerivProjUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y' : Type} {Yi : Type} {YI : Yi → Type} [SciLean.StructType Y' Yi YI] [DecidableEq Yi] [SciLean.SemiInnerProductSpace K Y'] [(i : Yi) → SciLean.SemiInnerProductSpace K (YI i)] {ι : Type} [SciLean.IndexType ι] [DecidableEq ι] (f : X → ι → Y') (hf : ∀ (i : ι), SciLean.HasAdjDiff K fun x => f x i) : (SciLean.revDerivProjUpdate K Yi fun x =>  ∑ i, f x i) = fun x =>
  let ydf := SciLean.revDerivProjUpdate K (ι × Yi) f x;
  ( ∑ i, ydf.1 i, fun j dy dx => LeanColls.fold (SciLean.IndexType.univ ι) (fun dx i => ydf.2 (i, j) dy dx) dx)


declaration:
theorem IndexType.sum.arg_f.revDerivUpdate_rule {K : Type} [RCLike K] {X : Type} [SciLean.SemiInnerProductSpace K X] {Y : Type} [SciLean.SemiInnerProductSpace K Y] {ι : Type} [SciLean.IndexType ι] (f : X → ι → Y) (hf : ∀ (i : ι), SciLean.HasAdjDiff K fun x => f x i) : (SciLean.revDerivUpdate K fun x =>  ∑ i, f x i) = fun x =>
  let ydf := SciLean.revDerivUpdate K f x;
  ( ∑ i, ydf.1 i, fun dy dx => ydf.2 (fun x => dy) dx)