packages feed

downhill 0.1.0.0 → 0.2.0.0

raw patch · 16 files changed

+398/−1328 lines, 16 filesdep +hedgehogdep +tasty-hedgehogPVP ok

version bump matches the API change (PVP)

Dependencies added: hedgehog, tasty-hedgehog

API changes (from Hackage documentation)

- Downhill.BVar: instance (Data.AdditiveGroup.AdditiveGroup b, Downhill.Grad.HasFullGrad b) => Data.AdditiveGroup.AdditiveGroup (Downhill.BVar.BVar r b)
- Downhill.BVar: instance (Data.VectorSpace.VectorSpace v, Downhill.Grad.HasFullGrad v, Downhill.Grad.Tang v GHC.Types.~ v, Downhill.Linear.Expr.FullVector (Downhill.Grad.MScalar v), Downhill.Grad.Grad (Downhill.Grad.MScalar v) GHC.Types.~ Downhill.Grad.MScalar v) => Data.VectorSpace.VectorSpace (Downhill.BVar.BVar r v)
- Downhill.BVar: instance (Downhill.Grad.HasFullGrad p, Downhill.Grad.HasGradAffine p) => Data.AffineSpace.AffineSpace (Downhill.BVar.BVar r p)
- Downhill.BVar: instance (GHC.Float.Floating b, Downhill.Grad.HasFullGrad b, Downhill.Grad.MScalar b GHC.Types.~ b) => GHC.Float.Floating (Downhill.BVar.BVar r b)
- Downhill.BVar: instance (GHC.Num.Num b, Downhill.Grad.HasFullGrad b, Downhill.Grad.MScalar b GHC.Types.~ b) => GHC.Num.Num (Downhill.BVar.BVar r b)
- Downhill.BVar: instance (GHC.Real.Fractional b, Downhill.Grad.HasFullGrad b, Downhill.Grad.MScalar b GHC.Types.~ b) => GHC.Real.Fractional (Downhill.BVar.BVar r b)
- Downhill.BVar.Num: instance GHC.Num.Num a => Downhill.Grad.Dual (Downhill.BVar.Num.AsNum a) (Downhill.BVar.Num.AsNum a) (Downhill.BVar.Num.AsNum a)
- Downhill.BVar.Num: instance GHC.Num.Num a => Downhill.Grad.MetricTensor (Downhill.BVar.Num.AsNum a)
- Downhill.BVar.Num: instance GHC.Num.Num a => Downhill.Linear.Expr.FullVector (Downhill.BVar.Num.AsNum a)
- Downhill.BVar.Traversable: instance forall k (f :: k) a. GHC.Generics.Generic (Downhill.BVar.Traversable.TraversableMetric f a)
- Downhill.BVar.Traversable: instance forall k (f :: k) v. GHC.Base.Monoid v => GHC.Base.Monoid (Downhill.BVar.Traversable.IntmapVector f v)
- Downhill.BVar.Traversable: instance forall k (f :: k) v. GHC.Base.Semigroup v => GHC.Base.Semigroup (Downhill.BVar.Traversable.IntmapVector f v)
- Downhill.BVar.Traversable: instance forall k (f :: k) v. GHC.Show.Show v => GHC.Show.Show (Downhill.BVar.Traversable.IntmapVector f v)
- Downhill.BVar.Traversable: instance forall k a (f :: k). Data.AdditiveGroup.AdditiveGroup (Downhill.Grad.Metric a) => Data.AdditiveGroup.AdditiveGroup (Downhill.BVar.Traversable.TraversableMetric f a)
- Downhill.BVar.Traversable: instance forall k a (f :: k). Data.AdditiveGroup.AdditiveGroup a => Data.AdditiveGroup.AdditiveGroup (Downhill.BVar.Traversable.IntmapVector f a)
- Downhill.BVar.Traversable: instance forall k a (f :: k). Data.VectorSpace.VectorSpace (Downhill.Grad.Metric a) => Data.VectorSpace.VectorSpace (Downhill.BVar.Traversable.TraversableMetric f a)
- Downhill.BVar.Traversable: instance forall k a s (f :: k). (Downhill.Grad.MetricTensor (Downhill.Grad.Metric a), Downhill.Grad.MtVector (Downhill.Grad.Metric a) GHC.Types.~ Downhill.Grad.Tang a, Downhill.Grad.MtCovector (Downhill.Grad.Metric a) GHC.Types.~ Downhill.Grad.Grad a, Downhill.Grad.Dual s (Downhill.Grad.Tang a) (Downhill.Grad.Grad a)) => Downhill.Grad.MetricTensor (Downhill.BVar.Traversable.TraversableMetric f a)
- Downhill.BVar.Traversable: instance forall k s dv v (f :: k). Downhill.Grad.Dual s dv v => Downhill.Grad.Dual s (Downhill.BVar.Traversable.IntmapVector f dv) (Downhill.BVar.Traversable.IntmapVector f v)
- Downhill.BVar.Traversable: instance forall k v (f :: k). Data.VectorSpace.VectorSpace v => Data.VectorSpace.VectorSpace (Downhill.BVar.Traversable.IntmapVector f v)
- Downhill.BVar.Traversable: instance forall k v (f :: k). Downhill.Linear.Expr.BasicVector v => Downhill.Linear.Expr.BasicVector (Downhill.BVar.Traversable.IntmapVector f v)
- Downhill.Grad: -- <a>VectorSpace</a>, <tt>Tang p</tt> might be the same as <tt>p</tt>
- Downhill.Grad: -- <tt>Tang p</tt> should be <tt><a>Diff</a> p</tt>. If <tt>p</tt> is
- Downhill.Grad: -- itself.
- Downhill.Grad: class (Dual (Scalar g) (MtVector g) (MtCovector g), VectorSpace g) => MetricTensor g where {
- Downhill.Grad: evalMetric :: MetricTensor g => g -> MtCovector g -> MtVector g
- Downhill.Grad: innerProduct :: MetricTensor g => g -> MtCovector g -> MtCovector g -> Scalar g
- Downhill.Grad: instance (Data.AdditiveGroup.AdditiveGroup (Data.VectorSpace.Scalar v), GHC.Num.Num (Data.VectorSpace.Scalar v)) => Data.VectorSpace.VectorSpace (Downhill.Grad.L2 v)
- Downhill.Grad: instance (Data.AdditiveGroup.AdditiveGroup a, GHC.Num.Num a, a GHC.Types.~ Data.VectorSpace.Scalar v, Downhill.Grad.Dual a v v) => Downhill.Grad.MetricTensor (Downhill.Grad.L2 v)
- Downhill.Grad: instance (Downhill.Grad.Dual s a da, Downhill.Grad.Dual s b db) => Downhill.Grad.Dual s (a, b) (da, db)
- Downhill.Grad: instance (Downhill.Grad.Dual s a da, Downhill.Grad.Dual s b db, Downhill.Grad.Dual s c dc) => Downhill.Grad.Dual s (a, b, c) (da, db, dc)
- Downhill.Grad: instance (Downhill.Grad.MetricTensor ma, Downhill.Grad.MetricTensor mb, Data.VectorSpace.Scalar ma GHC.Types.~ Data.VectorSpace.Scalar mb) => Downhill.Grad.MetricTensor (ma, mb)
- Downhill.Grad: instance (Downhill.Grad.MetricTensor ma, Downhill.Grad.MetricTensor mb, Downhill.Grad.MetricTensor mc, Data.VectorSpace.Scalar ma GHC.Types.~ Data.VectorSpace.Scalar mb, Data.VectorSpace.Scalar ma GHC.Types.~ Data.VectorSpace.Scalar mc) => Downhill.Grad.MetricTensor (ma, mb, mc)
- Downhill.Grad: instance Data.AdditiveGroup.AdditiveGroup (Data.VectorSpace.Scalar v) => Data.AdditiveGroup.AdditiveGroup (Downhill.Grad.L2 v)
- Downhill.Grad: instance Downhill.Grad.Dual GHC.Integer.Type.Integer GHC.Integer.Type.Integer GHC.Integer.Type.Integer
- Downhill.Grad: instance Downhill.Grad.Dual GHC.Types.Double GHC.Types.Double GHC.Types.Double
- Downhill.Grad: instance Downhill.Grad.Dual GHC.Types.Float GHC.Types.Float GHC.Types.Float
- Downhill.Grad: instance Downhill.Grad.MetricTensor GHC.Integer.Type.Integer
- Downhill.Grad: instance Downhill.Grad.MetricTensor GHC.Types.Double
- Downhill.Grad: instance Downhill.Grad.MetricTensor GHC.Types.Float
- Downhill.Grad: instance GHC.Generics.Generic (Downhill.Grad.L2 v)
- Downhill.Grad: sqrNorm :: MetricTensor g => g -> MtCovector g -> Scalar g
- Downhill.Grad: type HasFullGrad p = (HasGrad p, FullVector (Grad p))
- Downhill.Linear.BackGrad: instance Downhill.Linear.Expr.FullVector v => Data.AdditiveGroup.AdditiveGroup (Downhill.Linear.BackGrad.BackGrad r v)
- Downhill.Linear.BackGrad: instance Downhill.Linear.Expr.FullVector v => Data.VectorSpace.VectorSpace (Downhill.Linear.BackGrad.BackGrad r v)
- Downhill.Linear.Expr: class (BasicVector v, VectorSpace v) => FullVector v
- Downhill.Linear.Expr: instance (Data.VectorSpace.Scalar a GHC.Types.~ Data.VectorSpace.Scalar b, Downhill.Linear.Expr.FullVector a, Downhill.Linear.Expr.FullVector b) => Downhill.Linear.Expr.FullVector (a, b)
- Downhill.Linear.Expr: instance (s GHC.Types.~ Data.VectorSpace.Scalar a, s GHC.Types.~ Data.VectorSpace.Scalar b, s GHC.Types.~ Data.VectorSpace.Scalar c, Downhill.Linear.Expr.FullVector a, Downhill.Linear.Expr.FullVector b, Downhill.Linear.Expr.FullVector c) => Downhill.Linear.Expr.FullVector (a, b, c)
- Downhill.Linear.Expr: instance Data.VectorSpace.VectorSpace v => Downhill.Linear.Expr.FullVector (Downhill.Linear.Expr.DenseVector v)
- Downhill.Linear.Expr: instance Downhill.Linear.Expr.FullVector GHC.Integer.Type.Integer
- Downhill.Linear.Expr: instance Downhill.Linear.Expr.FullVector GHC.Types.Double
- Downhill.Linear.Expr: instance Downhill.Linear.Expr.FullVector GHC.Types.Float
- Downhill.Linear.Expr: instance Downhill.Linear.Expr.FullVector dv => Data.VectorSpace.VectorSpace (Downhill.Linear.Expr.Expr da dv)
- Downhill.Linear.Expr: instance Downhill.Linear.Expr.FullVector v => Data.AdditiveGroup.AdditiveGroup (Downhill.Linear.Expr.Expr a v)
- Downhill.Linear.Expr: negateBuilder :: FullVector v => v -> VecBuilder v
- Downhill.Linear.Expr: scaleBuilder :: FullVector v => Scalar v -> v -> VecBuilder v
- Downhill.TH: AutoAffineSpace :: AffineSpaceOptions
- Downhill.TH: BVarOptions :: RecordNamer -> RecordNamer -> RecordNamer -> RecordNamer -> AffineSpaceOptions -> [String] -> BVarOptions
- Downhill.TH: MakeAffineSpace :: AffineSpaceOptions
- Downhill.TH: NoAffineSpace :: AffineSpaceOptions
- Downhill.TH: RecordNamer :: (String -> String) -> (String -> String) -> (String -> String) -> RecordNamer
- Downhill.TH: [dataConNamer] :: RecordNamer -> String -> String
- Downhill.TH: [fieldNamer] :: RecordNamer -> String -> String
- Downhill.TH: [optAffineSpace] :: BVarOptions -> AffineSpaceOptions
- Downhill.TH: [optBuilderNamer] :: BVarOptions -> RecordNamer
- Downhill.TH: [optExcludeFields] :: BVarOptions -> [String]
- Downhill.TH: [optGradNamer] :: BVarOptions -> RecordNamer
- Downhill.TH: [optMetricNamer] :: BVarOptions -> RecordNamer
- Downhill.TH: [optTangNamer] :: BVarOptions -> RecordNamer
- Downhill.TH: [typeConNamer] :: RecordNamer -> String -> String
- Downhill.TH: data AffineSpaceOptions
- Downhill.TH: data BVarOptions
- Downhill.TH: data RecordNamer
- Downhill.TH: defaultBVarOptions :: BVarOptions
- Downhill.TH: instance GHC.Show.Show Downhill.TH.DatatypeFields
- Downhill.TH: instance GHC.Show.Show Downhill.TH.DownhillRecord
- Downhill.TH: mkHasGradInstances :: BVarOptions -> Q [Dec] -> Q [Dec]
+ Downhill.BVar: instance (Data.AdditiveGroup.AdditiveGroup b, Downhill.Grad.HasGrad b) => Data.AdditiveGroup.AdditiveGroup (Downhill.BVar.BVar r b)
+ Downhill.BVar: instance (Data.VectorSpace.VectorSpace v, Downhill.Grad.HasGrad v, Downhill.Grad.Grad v GHC.Types.~ v, Downhill.Grad.Tang v GHC.Types.~ v, Downhill.Linear.Expr.BasicVector (Downhill.Grad.MScalar v), Downhill.Grad.Grad (Downhill.Grad.MScalar v) GHC.Types.~ Downhill.Grad.MScalar v, Data.VectorSpace.InnerSpace v, Downhill.Grad.HasGrad (Downhill.Grad.MScalar v)) => Data.VectorSpace.InnerSpace (Downhill.BVar.BVar r v)
+ Downhill.BVar: instance (Data.VectorSpace.VectorSpace v, Downhill.Grad.HasGrad v, Downhill.Grad.Tang v GHC.Types.~ v, Downhill.Linear.Expr.BasicVector (Downhill.Grad.MScalar v), Downhill.Grad.Grad (Downhill.Grad.MScalar v) GHC.Types.~ Downhill.Grad.MScalar v) => Data.VectorSpace.VectorSpace (Downhill.BVar.BVar r v)
+ Downhill.BVar: instance (Downhill.Grad.HasGrad p, Downhill.Grad.HasGradAffine p) => Data.AffineSpace.AffineSpace (Downhill.BVar.BVar r p)
+ Downhill.BVar: instance (GHC.Float.Floating b, Downhill.Grad.HasGrad b, Downhill.Grad.MScalar b GHC.Types.~ b) => GHC.Float.Floating (Downhill.BVar.BVar r b)
+ Downhill.BVar: instance (GHC.Num.Num b, Downhill.Grad.HasGrad b, Downhill.Grad.MScalar b GHC.Types.~ b) => GHC.Num.Num (Downhill.BVar.BVar r b)
+ Downhill.BVar: instance (GHC.Real.Fractional b, Downhill.Grad.HasGrad b, Downhill.Grad.MScalar b GHC.Types.~ b) => GHC.Real.Fractional (Downhill.BVar.BVar r b)
+ Downhill.BVar: pattern T3 :: forall r a b c. (BasicVector (Grad a), BasicVector (Grad b), BasicVector (Grad c)) => BVar r a -> BVar r b -> BVar r c -> BVar r (a, b, c)
+ Downhill.BVar.Num: instance GHC.Num.Num a => Downhill.Grad.Dual (Downhill.BVar.Num.AsNum a) (Downhill.BVar.Num.AsNum a)
+ Downhill.BVar.Num: instance GHC.Num.Num a => Downhill.Metric.MetricTensor (Downhill.BVar.Num.AsNum a) (Downhill.BVar.Num.AsNum a)
+ Downhill.BVar.Traversable: instance Data.AdditiveGroup.AdditiveGroup a => Data.AdditiveGroup.AdditiveGroup (Downhill.BVar.Traversable.IntmapVector f a)
+ Downhill.BVar.Traversable: instance Data.AdditiveGroup.AdditiveGroup g => Data.AdditiveGroup.AdditiveGroup (Downhill.BVar.Traversable.TraversableMetric f g)
+ Downhill.BVar.Traversable: instance Data.VectorSpace.VectorSpace g => Data.VectorSpace.VectorSpace (Downhill.BVar.Traversable.TraversableMetric f g)
+ Downhill.BVar.Traversable: instance Data.VectorSpace.VectorSpace v => Data.VectorSpace.VectorSpace (Downhill.BVar.Traversable.IntmapVector f v)
+ Downhill.BVar.Traversable: instance Downhill.Grad.Dual dv v => Downhill.Grad.Dual (Downhill.BVar.Traversable.IntmapVector f dv) (Downhill.BVar.Traversable.IntmapVector f v)
+ Downhill.BVar.Traversable: instance Downhill.Linear.Expr.BasicVector v => Downhill.Linear.Expr.BasicVector (Downhill.BVar.Traversable.IntmapVector f v)
+ Downhill.BVar.Traversable: instance Downhill.Metric.MetricTensor p g => Downhill.Metric.MetricTensor (Downhill.BVar.Traversable.TraversableVar f p) (Downhill.BVar.Traversable.TraversableMetric f g)
+ Downhill.BVar.Traversable: instance GHC.Base.Monoid v => GHC.Base.Monoid (Downhill.BVar.Traversable.IntmapVector f v)
+ Downhill.BVar.Traversable: instance GHC.Base.Semigroup v => GHC.Base.Semigroup (Downhill.BVar.Traversable.IntmapVector f v)
+ Downhill.BVar.Traversable: instance GHC.Generics.Generic (Downhill.BVar.Traversable.TraversableMetric f g)
+ Downhill.BVar.Traversable: instance GHC.Show.Show v => GHC.Show.Show (Downhill.BVar.Traversable.IntmapVector f v)
+ Downhill.Grad: instance (Data.AdditiveGroup.AdditiveGroup s, Downhill.Grad.GDual s u du, Downhill.Grad.GDual s v dv) => Downhill.Grad.GDual s (u GHC.Generics.:*: v) (du GHC.Generics.:*: dv)
+ Downhill.Grad: instance (Data.VectorSpace.Scalar a GHC.Types.~ Data.VectorSpace.Scalar b, Data.VectorSpace.Scalar a GHC.Types.~ Data.VectorSpace.Scalar c, Downhill.Grad.Dual a da, Downhill.Grad.Dual b db, Downhill.Grad.Dual c dc) => Downhill.Grad.Dual (a, b, c) (da, db, dc)
+ Downhill.Grad: instance (Data.VectorSpace.Scalar a GHC.Types.~ Data.VectorSpace.Scalar b, Downhill.Grad.Dual a da, Downhill.Grad.Dual b db) => Downhill.Grad.Dual (a, b) (da, db)
+ Downhill.Grad: instance (s GHC.Types.~ Data.VectorSpace.Scalar v, Downhill.Grad.Dual v dv) => Downhill.Grad.GDual s (GHC.Generics.K1 x v) (GHC.Generics.K1 x dv)
+ Downhill.Grad: instance Data.AdditiveGroup.AdditiveGroup s => Downhill.Grad.GDual s GHC.Generics.U1 GHC.Generics.U1
+ Downhill.Grad: instance Downhill.Grad.Dual GHC.Integer.Type.Integer GHC.Integer.Type.Integer
+ Downhill.Grad: instance Downhill.Grad.Dual GHC.Types.Double GHC.Types.Double
+ Downhill.Grad: instance Downhill.Grad.Dual GHC.Types.Float GHC.Types.Float
+ Downhill.Grad: instance Downhill.Grad.GDual s GHC.Generics.V1 GHC.Generics.V1
+ Downhill.Grad: instance Downhill.Grad.GDual s v dv => Downhill.Grad.GDual s (GHC.Generics.M1 x y v) (GHC.Generics.M1 x y' dv)
+ Downhill.Grad: type MScalar p = Scalar (Tang p)
+ Downhill.Linear.BackGrad: instance (Downhill.Linear.Expr.BasicVector v, Data.AdditiveGroup.AdditiveGroup v) => Data.AdditiveGroup.AdditiveGroup (Downhill.Linear.BackGrad.BackGrad r v)
+ Downhill.Linear.BackGrad: instance (Downhill.Linear.Expr.BasicVector v, Data.VectorSpace.VectorSpace v) => Data.VectorSpace.VectorSpace (Downhill.Linear.BackGrad.BackGrad r v)
+ Downhill.Linear.Expr: genericIdentityBuilder :: forall b v. (Generic b, Generic v, GBasicVector (Rep b) (Rep v)) => v -> b
+ Downhill.Linear.Expr: genericIdentityMaybeBuilder :: forall b v. (Generic b, Generic v, GBasicVector (Rep b) (Rep v)) => v -> Maybe b
+ Downhill.Linear.Expr: genericSumBuilder :: forall b v. (Generic b, Generic v, GBasicVector (Rep b) (Rep v)) => b -> v
+ Downhill.Linear.Expr: genericSumMaybeBuilder :: forall b v. (Generic b, Generic v, AdditiveGroup v, GBasicVector (Rep b) (Rep v)) => Maybe b -> v
+ Downhill.Linear.Expr: instance (Downhill.Linear.Expr.BasicVector v, b GHC.Types.~ Downhill.Linear.Expr.VecBuilder v) => Downhill.Linear.Expr.GBasicVector (GHC.Generics.K1 x b) (GHC.Generics.K1 x v)
+ Downhill.Linear.Expr: instance (Downhill.Linear.Expr.GBasicVector bu u, Downhill.Linear.Expr.GBasicVector bv v) => Downhill.Linear.Expr.GBasicVector (bu GHC.Generics.:*: bv) (u GHC.Generics.:*: v)
+ Downhill.Linear.Expr: instance Downhill.Linear.Expr.GBasicVector GHC.Generics.U1 GHC.Generics.U1
+ Downhill.Linear.Expr: instance Downhill.Linear.Expr.GBasicVector GHC.Generics.V1 GHC.Generics.V1
+ Downhill.Linear.Expr: instance Downhill.Linear.Expr.GBasicVector b v => Downhill.Linear.Expr.GBasicVector (GHC.Generics.M1 x y b) (GHC.Generics.M1 x y' v)
+ Downhill.Metric: class Dual (Tang p) (Grad p) => MetricTensor p g
+ Downhill.Metric: evalMetric :: MetricTensor p g => g -> Grad p -> Tang p
+ Downhill.Metric: innerProduct :: MetricTensor p g => g -> Grad p -> Grad p -> MScalar p
+ Downhill.Metric: instance (Downhill.Grad.Dual (Downhill.Grad.Tang p) (Downhill.Grad.Grad p), Downhill.Grad.Grad p GHC.Types.~ Downhill.Grad.Tang p) => Downhill.Metric.MetricTensor p Downhill.Metric.L2
+ Downhill.Metric: instance (Downhill.Grad.MScalar a GHC.Types.~ Downhill.Grad.MScalar b, Downhill.Grad.MScalar a GHC.Types.~ Downhill.Grad.MScalar c, Downhill.Metric.MetricTensor a ma, Downhill.Metric.MetricTensor b mb, Downhill.Metric.MetricTensor c mc) => Downhill.Metric.MetricTensor (a, b, c) (ma, mb, mc)
+ Downhill.Metric: instance (Downhill.Grad.MScalar a GHC.Types.~ Downhill.Grad.MScalar b, Downhill.Metric.MetricTensor a ma, Downhill.Metric.MetricTensor b mb) => Downhill.Metric.MetricTensor (a, b) (ma, mb)
+ Downhill.Metric: instance Downhill.Metric.MetricTensor GHC.Integer.Type.Integer GHC.Integer.Type.Integer
+ Downhill.Metric: instance Downhill.Metric.MetricTensor GHC.Types.Double GHC.Types.Double
+ Downhill.Metric: instance Downhill.Metric.MetricTensor GHC.Types.Float GHC.Types.Float
+ Downhill.Metric: sqrNorm :: MetricTensor p g => g -> Grad p -> MScalar p
- Downhill.BVar: backprop :: forall r a. (HasGrad a, FullVector (Grad a), BasicVector r) => BVar r a -> Grad a -> r
+ Downhill.BVar: backprop :: forall r a. (HasGrad a, BasicVector r) => BVar r a -> Grad a -> r
- Downhill.BVar: constant :: forall r a. FullVector (Grad a) => a -> BVar r a
+ Downhill.BVar: constant :: forall r a. (BasicVector (Grad a), AdditiveGroup (Grad a)) => a -> BVar r a
- Downhill.BVar.Traversable: backpropTraversable :: forall f a b p. (Traversable f, Grad (f a) ~ Grad (TraversableVar f a), HasGrad a, HasGrad p, FullVector (Grad p)) => Grad p -> (a -> Grad a -> b) -> (forall r. f (BVar r a) -> BVar r p) -> f a -> f b
+ Downhill.BVar.Traversable: backpropTraversable :: forall f a b p. (Traversable f, Grad (f a) ~ Grad (TraversableVar f a), HasGrad a, HasGrad p) => Grad p -> (a -> Grad a -> b) -> (forall r. f (BVar r a) -> BVar r p) -> f a -> f b
- Downhill.BVar.Traversable: backpropTraversable_GradOnly :: forall f a p. (Traversable f, Grad (f a) ~ Grad (TraversableVar f a), HasGrad a, HasGrad p, FullVector (Grad p)) => Grad p -> (forall r. f (BVar r a) -> BVar r p) -> f a -> f (Grad a)
+ Downhill.BVar.Traversable: backpropTraversable_GradOnly :: forall f a p. (Traversable f, Grad (f a) ~ Grad (TraversableVar f a), HasGrad a, HasGrad p) => Grad p -> (forall r. f (BVar r a) -> BVar r p) -> f a -> f (Grad a)
- Downhill.BVar.Traversable: backpropTraversable_ValueAndGrad :: forall f a p. (Traversable f, Grad (f a) ~ Grad (TraversableVar f a), HasGrad a, HasGrad p, FullVector (Grad p)) => Grad p -> (forall r. f (BVar r a) -> BVar r p) -> f a -> f (a, Grad a)
+ Downhill.BVar.Traversable: backpropTraversable_ValueAndGrad :: forall f a p. (Traversable f, Grad (f a) ~ Grad (TraversableVar f a), HasGrad a, HasGrad p) => Grad p -> (forall r. f (BVar r a) -> BVar r p) -> f a -> f (a, Grad a)
- Downhill.Grad: -- | A <a>MetricTensor</a>.
+ Downhill.Grad: -- | Cotangent space.
- Downhill.Grad: class (AdditiveGroup s, VectorSpace v, VectorSpace dv, Scalar v ~ s, Scalar dv ~ s) => Dual s v dv
+ Downhill.Grad: class (Scalar v ~ Scalar dv, AdditiveGroup (Scalar v), VectorSpace v, VectorSpace dv) => Dual v dv
- Downhill.Grad: class (Dual (MScalar p) (Tang p) (Grad p), MetricTensor (Metric p), MtVector (Metric p) ~ Tang p, MtCovector (Metric p) ~ Grad p, BasicVector (Tang p), BasicVector (Grad p)) => HasGrad p where {
+ Downhill.Grad: class (Dual (Tang p) (Grad p), BasicVector (Grad p), Scalar (Tang p) ~ Scalar (Grad p)) => HasGrad p where {
- Downhill.Grad: evalGrad :: Dual s v dv => dv -> v -> s
+ Downhill.Grad: evalGrad :: (Dual v dv, GDual (Scalar v) (Rep v) (Rep dv), Generic dv, Generic v) => dv -> v -> Scalar v
- Downhill.Grad: type family Metric p :: Type;
+ Downhill.Grad: type family Grad p :: Type;
- Downhill.Linear.Backprop: backprop :: forall a v. (BasicVector a, FullVector v) => BackGrad a v -> v -> a
+ Downhill.Linear.Backprop: backprop :: forall a v. (BasicVector a, BasicVector v) => BackGrad a v -> v -> a
- Downhill.Linear.Expr: identityBuilder :: FullVector v => v -> VecBuilder v
+ Downhill.Linear.Expr: identityBuilder :: forall b. (BasicVector v, VecBuilder v ~ Maybe b, Generic b, Generic v, GBasicVector (Rep b) (Rep v), AdditiveGroup v) => v -> VecBuilder v
- Downhill.Linear.Expr: sumBuilder :: BasicVector v => VecBuilder v -> v
+ Downhill.Linear.Expr: sumBuilder :: forall b. (BasicVector v, VecBuilder v ~ Maybe b, Generic b, Generic v, GBasicVector (Rep b) (Rep v), AdditiveGroup v) => VecBuilder v -> v
- Downhill.Linear.Lift: lift1_dense :: (BasicVector v, FullVector a) => (v -> a) -> BackGrad r a -> BackGrad r v
+ Downhill.Linear.Lift: lift1_dense :: (BasicVector v, BasicVector a) => (v -> a) -> BackGrad r a -> BackGrad r v
- Downhill.Linear.Lift: lift2_dense :: (BasicVector v, FullVector a, FullVector b) => (v -> a) -> (v -> b) -> BackGrad r a -> BackGrad r b -> BackGrad r v
+ Downhill.Linear.Lift: lift2_dense :: (BasicVector v, BasicVector a, BasicVector b) => (v -> a) -> (v -> b) -> BackGrad r a -> BackGrad r b -> BackGrad r v
- Downhill.Linear.Lift: lift3_dense :: (BasicVector v, FullVector a, FullVector b, FullVector c) => (v -> a) -> (v -> b) -> (v -> c) -> BackGrad r a -> BackGrad r b -> BackGrad r c -> BackGrad r v
+ Downhill.Linear.Lift: lift3_dense :: (BasicVector v, BasicVector a, BasicVector b, BasicVector c) => (v -> a) -> (v -> b) -> (v -> c) -> BackGrad r a -> BackGrad r b -> BackGrad r c -> BackGrad r v

Files

CHANGELOG.md view
@@ -1,5 +1,12 @@ # Revision history for downhill -## 0.1.0.0 -- 2021-12-12+## 0.2.0.0+* `MetricTensor` is no longer required to be a `VectorSpace`+* `T2`, `T3` pattern synonyms for `BVar`+* `L2` metric+* Generics for `BasicVector`, `Dual`+* Template Haskell scrapped++## 0.1.0.0  * First version
downhill.cabal view
@@ -1,7 +1,7 @@ cabal-version:       2.4  name:                downhill-version:             0.1.0.0+version:             0.2.0.0 synopsis:            Reverse mode automatic differentiation homepage:            https://andriusstank.github.io/downhill/ description:@@ -33,7 +33,7 @@                        Downhill.BVar.Num                        Downhill.BVar.Prelude,                        Downhill.BVar.Traversable,-                       Downhill.TH+                       Downhill.Metric   -- other-modules:   -- other-extensions:   build-depends:       base                  >= 4.12.0.0 && <4.17,@@ -52,7 +52,13 @@ test-suite downhill-test   type:                exitcode-stdio-1.0   main-is:             Main.hs-  other-modules:       DownhillTest.Point, DownhillTest.Traversable, DownhillTest.TH, DownhillTest.TestTHOptions-  build-depends:       base, downhill, tasty, tasty-hunit, vector-space+  other-modules:       DownhillTest.Point,+                       DownhillTest.Traversable,+                       DownhillTest.Bilinear+  build-depends:       base,+                       downhill,+                       tasty, tasty-hunit, tasty-hedgehog,+                       vector-space,+                       hedgehog   hs-source-dirs:      test   default-language:    Haskell2010
src/Downhill/BVar.hs view
@@ -12,12 +12,17 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ViewPatterns #-}  module Downhill.BVar   ( BVar (..),     var,     constant,     backprop,+    -- * Pattern synonyms+    pattern T2,+    pattern T3   ) where @@ -26,23 +31,24 @@ import qualified Data.AffineSpace as AffineSpace import Data.VectorSpace   ( AdditiveGroup (..),+    InnerSpace ((<.>)),     VectorSpace ((*^)),   ) import qualified Data.VectorSpace as VectorSpace import Downhill.Grad   ( Dual (evalGrad),-    HasFullGrad,-    HasGrad (Grad, MScalar, Tang),-    HasGradAffine,+    HasGrad (Grad, Tang),+    HasGradAffine, MScalar   ) import Downhill.Linear.BackGrad   ( BackGrad (..),     realNode,   ) import qualified Downhill.Linear.Backprop as BP-import Downhill.Linear.Expr (BasicVector, Expr (ExprVar), FullVector)+import Downhill.Linear.Expr (BasicVector, Expr (ExprVar)) import Downhill.Linear.Lift (lift2_dense) import Prelude hiding (id, (.))+import qualified Downhill.Linear.Prelude as Linear  -- | Variable is a value paired with derivative. data BVar r a = BVar@@ -50,13 +56,13 @@     bvarGrad :: BackGrad r (Grad a)   } -instance (AdditiveGroup b, HasFullGrad b) => AdditiveGroup (BVar r b) where+instance (AdditiveGroup b, HasGrad b) => AdditiveGroup (BVar r b) where   zeroV = BVar zeroV zeroV   negateV (BVar y0 dy) = BVar (negateV y0) (negateV dy)   BVar y0 dy ^-^ BVar z0 dz = BVar (y0 ^-^ z0) (dy ^-^ dz)   BVar y0 dy ^+^ BVar z0 dz = BVar (y0 ^+^ z0) (dy ^+^ dz) -instance (Num b, HasFullGrad b, MScalar b ~ b) => Num (BVar r b) where+instance (Num b, HasGrad b, MScalar b ~ b) => Num (BVar r b) where   (BVar f0 df) + (BVar g0 dg) = BVar (f0 + g0) (df ^+^ dg)   (BVar f0 df) - (BVar g0 dg) = BVar (f0 - g0) (df ^-^ dg)   (BVar f0 df) * (BVar g0 dg) = BVar (f0 * g0) (f0 *^ dg ^+^ g0 *^ df)@@ -71,14 +77,14 @@ rsqrt :: Floating a => a -> a rsqrt x = recip (sqrt x) -instance (Fractional b, HasFullGrad b, MScalar b ~ b) => Fractional (BVar r b) where+instance (Fractional b, HasGrad b, MScalar b ~ b) => Fractional (BVar r b) where   fromRational x = BVar (fromRational x) zeroV   recip (BVar x dx) = BVar (recip x) (df *^ dx)     where       df = negate (recip (sqr x))   BVar x dx / BVar y dy = BVar (x / y) ((recip y *^ dx) ^-^ ((x / sqr y) *^ dy)) -instance (Floating b, HasFullGrad b, MScalar b ~ b) => Floating (BVar r b) where+instance (Floating b, HasGrad b, MScalar b ~ b) => Floating (BVar r b) where   pi = BVar pi zeroV   exp (BVar x dx) = BVar (exp x) (exp x *^ dx)   log (BVar x dx) = BVar (log x) (recip x *^ dx)@@ -95,9 +101,9 @@  instance   ( VectorSpace v,-    HasFullGrad v,+    HasGrad v,     Tang v ~ v,-    FullVector (MScalar v),+    BasicVector (MScalar v),     Grad (MScalar v) ~ MScalar v   ) =>   VectorSpace (BVar r v)@@ -110,13 +116,32 @@       bpV :: Grad v -> Grad v       bpV dz = a *^ dz -instance (HasFullGrad p, HasGradAffine p) => AffineSpace (BVar r p) where+instance (HasGrad p, HasGradAffine p) => AffineSpace (BVar r p) where   type Diff (BVar r p) = BVar r (Tang p)   BVar y0 dy .+^ BVar z0 dz = BVar (y0 .+^ z0) (dy ^+^ dz)   BVar y0 dy .-. BVar z0 dz = BVar (y0 .-. z0) (dy ^-^ dz) +instance+  ( VectorSpace v,+    HasGrad v,+    Grad v ~ v,+    Tang v ~ v,+    BasicVector (MScalar v),+    Grad (MScalar v) ~ MScalar v,+    InnerSpace v,+    HasGrad (MScalar v)+  ) =>+  InnerSpace (BVar r v)+  where+  BVar u du <.> BVar v dv = BVar (u <.> v) (lift2_dense bpU bpV du dv)+    where+      bpU :: MScalar v -> Grad v+      bpU dz = dz *^ v+      bpV :: MScalar v -> Grad v+      bpV dz = dz *^ u+ -- | A variable with derivative of zero.-constant :: forall r a. FullVector (Grad a) => a -> BVar r a+constant :: forall r a. (BasicVector (Grad a), AdditiveGroup (Grad a)) => a -> BVar r a constant x = BVar x zeroV  -- | A variable with identity derivative.@@ -129,5 +154,21 @@ -- | Reverse mode differentiation. -- -- -backprop :: forall r a. (HasGrad a, FullVector (Grad a), BasicVector r) => BVar r a -> Grad a -> r+backprop :: forall r a. (HasGrad a, BasicVector r) => BVar r a -> Grad a -> r backprop (BVar _y0 x) = BP.backprop x+++splitPair :: (BasicVector (Grad a), BasicVector (Grad b)) => BVar r (a, b) -> (BVar r a, BVar r b)+splitPair (BVar (a, b) (Linear.T2 da db)) = (BVar a da, BVar b db)++pattern T2 :: forall r a b. (BasicVector (Grad a), BasicVector (Grad b)) => BVar r a -> BVar r b -> BVar r (a, b)+pattern T2 a b <- (splitPair -> (a, b))+  where T2 (BVar a da) (BVar b db) = BVar (a, b) (Linear.T2 da db)++splitTriple :: (BasicVector (Grad a), BasicVector (Grad b), BasicVector (Grad c)) => BVar r (a, b, c) -> (BVar r a, BVar r b, BVar r c)+splitTriple (BVar (a, b, c) (Linear.T3 da db dc)) = (BVar a da, BVar b db, BVar c dc)++pattern T3 :: forall r a b c. (BasicVector (Grad a), BasicVector (Grad b), BasicVector (Grad c))+ => BVar r a -> BVar r b -> BVar r c -> BVar r (a, b, c)+pattern T3 a b c <- (splitTriple -> (a, b, c))+  where T3 (BVar a da) (BVar b db) (BVar c dc) = BVar (a, b, c) (Linear.T3 da db dc)
src/Downhill/BVar/Num.hs view
@@ -34,10 +34,10 @@ import qualified Downhill.BVar as BVar import Downhill.Grad   ( Dual (evalGrad),-    HasGrad (Grad, Metric, MScalar, Tang),-    MetricTensor (MtCovector, MtVector, evalMetric),+    HasGrad (Grad, Tang)   )-import Downhill.Linear.Expr (BasicVector (..), FullVector (identityBuilder, negateBuilder, scaleBuilder))+import Downhill.Linear.Expr (BasicVector (..))+import Downhill.Metric (MetricTensor (evalMetric))  -- | @AsNum a@ implements many instances in terms of @Num a@ instance. newtype AsNum a = AsNum {unAsNum :: a}@@ -46,18 +46,14 @@   deriving (Fractional) via a   deriving (Floating) via a -instance Num a => Dual (AsNum a) (AsNum a) (AsNum a) where+instance Num a => Dual (AsNum a) (AsNum a) where   evalGrad = (*)  instance Num a => HasGrad (AsNum a) where-  type MScalar (AsNum a) = AsNum a   type Grad (AsNum a) = AsNum a   type Tang (AsNum a) = AsNum a-  type Metric (AsNum a) = AsNum a -instance Num a => MetricTensor (AsNum a) where-  type MtVector (AsNum a) = AsNum a-  type MtCovector (AsNum a) = AsNum a+instance Num a => MetricTensor (AsNum a) (AsNum a) where   evalMetric (AsNum m) (AsNum x) = AsNum (m * x)  instance Num a => AdditiveGroup (AsNum a) where@@ -73,11 +69,7 @@ instance Num a => BasicVector (AsNum a) where   type VecBuilder (AsNum a) = Sum a   sumBuilder = AsNum . getSum--instance Num a => FullVector (AsNum a) where   identityBuilder = Sum . unAsNum-  negateBuilder = Sum . negate . unAsNum-  scaleBuilder (AsNum x) (AsNum y) = Sum $ x * y  instance Num a => AffineSpace (AsNum a) where   type Diff (AsNum a) = AsNum a
src/Downhill/BVar/Traversable.hs view
@@ -4,13 +4,12 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeApplications #-}  -- | Easy backpropagation when all variables have the same type. --@@ -20,7 +19,7 @@ -- -- deriving via (TraversableVar MyRecord a) instance HasGrad a => HasGrad (MyRecord a) -- @--- +-- -- = Gradient type -- One might excect gradient type to be @type Grad (MyRecord a) = MyRecord (Grad a)@, but it's not -- the case, because record could contain additional members apart from @a@s, for example:@@ -37,15 +36,13 @@ -- and @MyPoint (Grad a)@ can't be made @VectorSpace@. Gradient type @Grad (MyRecord a)@ -- is a newtype wrapper over @IntMap@ -- that is not exported.---- module Downhill.BVar.Traversable   ( -- * Backpropagate     backpropTraversable,     backpropTraversable_GradOnly,     backpropTraversable_ValueAndGrad, -     -- * Split+    -- * Split     splitTraversable,      -- * TraversableVar@@ -58,62 +55,48 @@ import Data.Foldable (toList) import Data.IntMap (IntMap) import qualified Data.IntMap as IntMap+import Data.Kind (Type) import Data.Maybe (fromMaybe) import Data.VectorSpace (AdditiveGroup (negateV, zeroV, (^+^), (^-^)), VectorSpace (Scalar, (*^))) import qualified Data.VectorSpace as VectorSpace import Downhill.BVar (BVar (BVar, bvarGrad, bvarValue), backprop, var) import Downhill.Grad   ( Dual (evalGrad),-    HasGrad (Grad, MScalar, Metric, Tang),-    MetricTensor-      ( MtCovector,-        MtVector,-        evalMetric-      ),+    HasGrad (Grad, Tang)   ) import Downhill.Linear.BackGrad (BackGrad (BackGrad), castBackGrad, realNode) import Downhill.Linear.Expr-  ( BasicVector (VecBuilder, sumBuilder),+  ( BasicVector (VecBuilder, identityBuilder, sumBuilder),     Expr (ExprSum),-    FullVector,     SparseVector (unSparseVector),     Term,   ) import Downhill.Linear.Lift (lift1_sparse) import GHC.Generics (Generic)+import Downhill.Metric (MetricTensor (evalMetric))  -- | Provides HasGrad instance for use in deriving via newtype TraversableVar f a = TraversableVar {unTraversableVar :: f a}   deriving stock (Functor, Foldable, Traversable) -newtype TraversableMetric f a = TraversableMetric (Metric a)+newtype TraversableMetric (f :: Type -> Type) g = TraversableMetric g   deriving (Generic) -instance AdditiveGroup (Metric a) => AdditiveGroup (TraversableMetric f a)+instance AdditiveGroup g => AdditiveGroup (TraversableMetric f g) -instance VectorSpace (Metric a) => VectorSpace (TraversableMetric f a) where-  type Scalar (TraversableMetric f a) = Scalar (Metric a)+instance VectorSpace g => VectorSpace (TraversableMetric f g) where+  type Scalar (TraversableMetric f g) = Scalar g -instance-  ( MetricTensor (Metric a),-    MtVector (Metric a) ~ Tang a,-    MtCovector (Metric a) ~ Grad a,-    Dual s (Tang a) (Grad a)-  ) =>-  MetricTensor (TraversableMetric f a)-  where-  type MtVector (TraversableMetric f a) = IntmapVector f (Tang a)-  type MtCovector (TraversableMetric f a) = IntmapVector f (Grad a)-  evalMetric (TraversableMetric m) (IntmapVector da) = IntmapVector (IntMap.map (evalMetric m) da)+instance MetricTensor p g => MetricTensor (TraversableVar f p) (TraversableMetric f g) where+  evalMetric (TraversableMetric m) (IntmapVector da) =+    IntmapVector (IntMap.map (evalMetric @p @g m) da)  instance HasGrad a => HasGrad (TraversableVar f a) where-  type MScalar (TraversableVar f a) = MScalar a   type Tang (TraversableVar f a) = IntmapVector f (Tang a)   type Grad (TraversableVar f a) = IntmapVector f (Grad a)-  type Metric (TraversableVar f a) = TraversableMetric f a  -- | @IntmapVector@ serves as a gradient of 'TraversableVar'.-newtype IntmapVector f v = IntmapVector {unIntmapVector :: IntMap v}+newtype IntmapVector (f :: Type -> Type) v = IntmapVector {unIntmapVector :: IntMap v}   deriving (Show)  instance AdditiveGroup a => AdditiveGroup (IntmapVector f a) where@@ -130,7 +113,7 @@   type Scalar (IntmapVector f v) = VectorSpace.Scalar v   a *^ (IntmapVector v) = IntmapVector (fmap (a *^) v) -instance Dual s dv v => Dual s (IntmapVector f dv) (IntmapVector f v) where+instance Dual dv v => Dual (IntmapVector f dv) (IntmapVector f v) where   evalGrad (IntmapVector dv) (IntmapVector v) = sumV $ IntMap.intersectionWith evalGrad dv v  deriving via (IntMap v) instance Semigroup v => Semigroup (IntmapVector f v)@@ -140,6 +123,7 @@ instance BasicVector v => BasicVector (IntmapVector f v) where   type VecBuilder (IntmapVector f v) = IntmapVector f (VecBuilder v)   sumBuilder (IntmapVector v) = IntmapVector (fmap sumBuilder v)+  identityBuilder (IntmapVector x) = IntmapVector (identityBuilder <$> x)  imap ::   forall t a b.@@ -156,7 +140,7 @@       return (mkBVar' index x)  -- | Note that @splitTraversable@ won't be useful--- for top level @BVar@, because the type @Grad (f a)@ is not exposed. +-- for top level @BVar@, because the type @Grad (f a)@ is not exposed. splitTraversable ::   forall f r a.   ( Traversable f,@@ -188,8 +172,7 @@   forall f r a.   ( Traversable f,     Grad (f a) ~ Grad (TraversableVar f a),-    HasGrad a,-    FullVector (Grad a)+    HasGrad a   ) =>   f (BVar r a) ->   BVar r (f a)@@ -224,8 +207,7 @@   ( Traversable f,     Grad (f a) ~ Grad (TraversableVar f a),     HasGrad a,-    HasGrad p,-    FullVector (Grad p)+    HasGrad p   ) =>   Grad p ->   (a -> Grad a -> b) ->@@ -256,8 +238,7 @@   ( Traversable f,     Grad (f a) ~ Grad (TraversableVar f a),     HasGrad a,-    HasGrad p,-    FullVector (Grad p)+    HasGrad p   ) =>   Grad p ->   (forall r. f (BVar r a) -> BVar r p) ->@@ -274,8 +255,7 @@   ( Traversable f,     Grad (f a) ~ Grad (TraversableVar f a),     HasGrad a,-    HasGrad p,-    FullVector (Grad p)+    HasGrad p   ) =>   Grad p ->   (forall r. f (BVar r a) -> BVar r p) ->
src/Downhill/Grad.hs view
@@ -1,103 +1,65 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE EmptyCase #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}  module Downhill.Grad   ( Dual (..),-    MetricTensor (..),-    HasGrad (..),+    HasGrad (..), MScalar,     GradBuilder,-    HasFullGrad,     HasGradAffine,   ) where  import Data.AffineSpace (AffineSpace (Diff)) import Data.Kind (Type)-import Data.VectorSpace (AdditiveGroup ((^+^)), VectorSpace (Scalar, (*^)))-import qualified Data.VectorSpace as VectorSpace-import Downhill.Linear.Expr (BasicVector (VecBuilder), FullVector)-import GHC.Generics (Generic)+import Data.VectorSpace (AdditiveGroup ((^+^), zeroV), VectorSpace(Scalar))+import Downhill.Linear.Expr (BasicVector (VecBuilder))+import GHC.Generics (Generic (Rep, from), K1 (K1), M1 (M1), U1 (U1), V1, (:*:) ((:*:)))  -- | Dual of a vector @v@ is a linear map @v -> Scalar v@. class-  ( AdditiveGroup s,+  ( +    Scalar v ~ Scalar dv,+    AdditiveGroup (Scalar v),     VectorSpace v,-    VectorSpace dv,-    VectorSpace.Scalar v ~ s,-    VectorSpace.Scalar dv ~ s+    VectorSpace dv   ) =>-  Dual s v dv+  Dual v dv   where   -- if evalGrad goes to HasGrad class, parameter p is ambiguous-  evalGrad :: dv -> v -> s---- | @MetricTensor@ converts gradients to vectors.------ It is really inverse of a metric tensor, because it maps cotangent--- space into tangent space. Gradient descent doesn't need metric tensor,--- it needs inverse.--class-  ( Dual (Scalar g) (MtVector g) (MtCovector g),-    VectorSpace g-  ) =>-  MetricTensor g-  where-  type MtVector g :: Type-  type MtCovector g :: Type--  -- | @m@ must be symmetric:-  ---  -- @evalGrad x (evalMetric m y) = evalGrad y (evalMetric m x)@-  evalMetric :: g -> MtCovector g -> MtVector g--  -- | @innerProduct m x y = evalGrad x (evalMetric m y)@-  innerProduct :: g -> MtCovector g -> MtCovector g -> Scalar g-  innerProduct g x y = evalGrad x (evalMetric g y)--  -- | @sqrNorm m x = innerProduct m x x@-  sqrNorm :: g -> MtCovector g -> Scalar g-  sqrNorm g x = innerProduct g x x+  evalGrad :: dv -> v -> Scalar v+  default evalGrad :: (GDual (Scalar v) (Rep v) (Rep dv), Generic dv, Generic v) => dv -> v -> Scalar v+  evalGrad dv v = gevalGrad (from dv) (from v) --- | @HasGrad@ is a collection of types and constraints that are useful--- in many places. It helps to keep type signatures short.+type MScalar p = Scalar (Tang p) --- TODO: FullVector or not?--- TODO: Metric or not?+-- | Differentiable functions don't need to be constrained to vector spaces, they+-- can be defined on other smooth manifolds, too. class-  ( Dual (MScalar p) (Tang p) (Grad p),-    MetricTensor (Metric p),-    MtVector (Metric p) ~ Tang p,-    MtCovector (Metric p) ~ Grad p,-    BasicVector (Tang p),-    BasicVector (Grad p)+  ( Dual (Tang p) (Grad p),+    BasicVector (Grad p),+    Scalar (Tang p) ~ Scalar (Grad p)   ) =>   HasGrad p   where-  -- | Scalar of @Tang p@ and @Grad p@.-  type MScalar p :: Type--  -- | Tangent vector of manifold @p@. If p is 'AffineSpace', @Tang p@ should-  -- be @'Diff' p@. If @p@ is 'VectorSpace', @Tang p@ might be the same as @p@ itself.+  -- | Tangent space.   type Tang p :: Type -  -- | Dual of tangent space of @p@.+  -- | Cotangent space.   type Grad p :: Type -  -- | A 'MetricTensor'.-  type Metric p :: Type- type GradBuilder v = VecBuilder (Grad v) -type HasFullGrad p = (HasGrad p, FullVector (Grad p))- type HasGradAffine p =   ( AffineSpace p,     HasGrad p,@@ -107,32 +69,19 @@     Grad (Tang p) ~ Grad p   ) -instance Dual Integer Integer Integer where+instance Dual Integer Integer where   evalGrad = (*) -instance MetricTensor Integer where-  type MtVector Integer = Integer-  type MtCovector Integer = Integer-  evalMetric m x = m * x- instance HasGrad Integer where-  type MScalar Integer = Integer   type Tang Integer = Integer   type Grad Integer = Integer-  type Metric Integer = Integer -instance (Dual s a da, Dual s b db) => Dual s (a, b) (da, db) where+instance (Scalar a ~ Scalar b, Dual a da, Dual b db) => Dual (a, b) (da, db) where   evalGrad (a, b) (x, y) = evalGrad a x ^+^ evalGrad b y -instance (Dual s a da, Dual s b db, Dual s c dc) => Dual s (a, b, c) (da, db, dc) where+instance (Scalar a ~ Scalar b, Scalar a ~ Scalar c, Dual a da, Dual b db, Dual c dc) => Dual (a, b, c) (da, db, dc) where   evalGrad (a, b, c) (x, y, z) = evalGrad a x ^+^ evalGrad b y ^+^ evalGrad c z -instance (MetricTensor ma, MetricTensor mb, Scalar ma ~ Scalar mb) => MetricTensor (ma, mb) where-  type MtVector (ma, mb) = (MtVector ma, MtVector mb)-  type MtCovector (ma, mb) = (MtCovector ma, MtCovector mb)-  evalMetric (ma, mb) (a, b) = (evalMetric ma a, evalMetric mb b)-  sqrNorm (ma, mb) (a, b) = sqrNorm ma a ^+^ sqrNorm mb b- instance   ( HasGrad a,     HasGrad b,@@ -140,26 +89,10 @@   ) =>   HasGrad (a, b)   where-  type MScalar (a, b) = MScalar a   type Grad (a, b) = (Grad a, Grad b)   type Tang (a, b) = (Tang a, Tang b)-  type Metric (a, b) = (Metric a, Metric b)  instance-  ( MetricTensor ma,-    MetricTensor mb,-    MetricTensor mc,-    Scalar ma ~ Scalar mb,-    Scalar ma ~ Scalar mc-  ) =>-  MetricTensor (ma, mb, mc)-  where-  type MtVector (ma, mb, mc) = (MtVector ma, MtVector mb, MtVector mc)-  type MtCovector (ma, mb, mc) = (MtCovector ma, MtCovector mb, MtCovector mc)-  evalMetric (ma, mb, mc) (a, b, c) = (evalMetric ma a, evalMetric mb b, evalMetric mc c)-  sqrNorm (ma, mb, mc) (a, b, c) = sqrNorm ma a ^+^ sqrNorm mb b ^+^ sqrNorm mc c--instance   ( HasGrad a,     HasGrad b,     HasGrad c,@@ -168,51 +101,37 @@   ) =>   HasGrad (a, b, c)   where-  type MScalar (a, b, c) = MScalar a   type Grad (a, b, c) = (Grad a, Grad b, Grad c)   type Tang (a, b, c) = (Tang a, Tang b, Tang c)-  type Metric (a, b, c) = (Metric a, Metric b, Metric c) -instance Dual Float Float Float where+instance Dual Float Float where   evalGrad = (*) -instance MetricTensor Float where-  type MtVector Float = Float-  type MtCovector Float = Float-  evalMetric m dv = m * dv- instance HasGrad Float where-  type MScalar Float = Float   type Grad Float = Float   type Tang Float = Float-  type Metric Float = Float -instance Dual Double Double Double where+instance Dual Double Double where   evalGrad = (*) -instance MetricTensor Double where-  type MtVector Double = Double-  type MtCovector Double = Double-  evalMetric m dv = m * dv- instance HasGrad Double where-  type MScalar Double = Double   type Grad Double = Double   type Tang Double = Double-  type Metric Double = Double -newtype L2 v = L2 (Scalar v)-  deriving (Generic)+class GDual s v dv where+  gevalGrad :: dv p -> v p -> s -instance AdditiveGroup (Scalar v) => AdditiveGroup (L2 v)+instance (s ~ Scalar v, Dual v dv) => GDual s (K1 x v) (K1 x dv) where+  gevalGrad (K1 dv) (K1 v) = evalGrad dv v -instance (AdditiveGroup (Scalar v), Num (Scalar v)) => VectorSpace (L2 v) where-  type Scalar (L2 v) = Scalar v-  x *^ L2 y = L2 (x * y)+instance (GDual s v dv) => GDual s (M1 x y v) (M1 x y' dv) where+  gevalGrad (M1 dv) (M1 v) = gevalGrad dv v -instance (AdditiveGroup a, Num a, a ~ Scalar v, Dual a v v) => MetricTensor (L2 v) where-  type MtVector (L2 v) = v-  type MtCovector (L2 v) = v-  evalMetric (L2 a) u = a *^ u-  innerProduct (L2 a) x y = a * evalGrad x y-  sqrNorm g x = innerProduct g x x+instance (AdditiveGroup s, GDual s u du, GDual s v dv) => GDual s (u :*: v) (du :*: dv) where+  gevalGrad (du :*: dv) (u :*: v) = gevalGrad du u ^+^ gevalGrad dv v++instance GDual s V1 V1 where+  gevalGrad = \case {}++instance AdditiveGroup s => GDual s U1 U1 where+  gevalGrad U1 = zeroV
src/Downhill/Linear/BackGrad.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE TypeApplications #-}  module Downhill.Linear.BackGrad   ( BackGrad (..),@@ -21,9 +20,8 @@     VectorSpace (..),   ) import Downhill.Linear.Expr-  ( BasicVector (VecBuilder),+  ( BasicVector (VecBuilder, identityBuilder),     Expr (ExprSum),-    FullVector (identityBuilder, negateBuilder, scaleBuilder),     Term (Term), SparseVector (unSparseVector),   ) @@ -79,12 +77,12 @@   BackGrad r z castBackGrad (BackGrad g) = BackGrad g -instance (FullVector v) => AdditiveGroup (BackGrad r v) where+instance (BasicVector v, AdditiveGroup v) => AdditiveGroup (BackGrad r v) where   zeroV = realNode (ExprSum [])-  negateV (BackGrad x) = realNode (ExprSum [x negateBuilder])+  negateV (BackGrad x) = realNode (ExprSum [x (identityBuilder . negateV)])   BackGrad x ^+^ BackGrad y = realNode (ExprSum [x identityBuilder, y identityBuilder])-  BackGrad x ^-^ BackGrad y = realNode (ExprSum [x identityBuilder, y negateBuilder])+  BackGrad x ^-^ BackGrad y = realNode (ExprSum [x identityBuilder, y (identityBuilder . negateV)]) -instance FullVector v => VectorSpace (BackGrad r v) where+instance (BasicVector v, VectorSpace v) => VectorSpace (BackGrad r v) where   type Scalar (BackGrad r v) = Scalar v-  a *^ BackGrad v = realNode (ExprSum [v (scaleBuilder a)])+  a *^ BackGrad v = realNode (ExprSum [v (identityBuilder . (a*^))])
src/Downhill/Linear/Backprop.hs view
@@ -25,8 +25,7 @@ import Downhill.Internal.Graph.Types (BackFun, flipBackFun) import Downhill.Linear.BackGrad (BackGrad (..), castBackGrad) import Downhill.Linear.Expr-  ( BasicVector (VecBuilder),-    FullVector (identityBuilder),+  ( BasicVector (VecBuilder, identityBuilder),     SparseVector (SparseVector, unSparseVector),     Term,   )@@ -65,5 +64,5 @@ -- | Purity of this function depends on laws of arithmetic -- and linearity law of 'Term'. If your addition is approximately -- associative, then this function is approximately pure. Fair?-backprop :: forall a v. (BasicVector a, FullVector v) => BackGrad a v -> v -> a+backprop :: forall a v. (BasicVector a, BasicVector v) => BackGrad a v -> v -> a backprop dvar = abstractBackprop dvar identityBuilder
src/Downhill/Linear/Expr.hs view
@@ -1,13 +1,18 @@ {-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE DerivingVia #-}+{-# LANGUAGE EmptyCase #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-}  module Downhill.Linear.Expr@@ -17,12 +22,17 @@      -- * Vectors     BasicVector (..),-    FullVector (..),     SparseVector (..),     DenseVector (..),     DenseBuilder (..),     toDenseBuilder, +    -- * Generics+    genericSumBuilder,+    genericIdentityBuilder,+    genericSumMaybeBuilder,+    genericIdentityMaybeBuilder,+     -- * Misc     maybeToMonoid,   )@@ -31,7 +41,8 @@ import Data.Kind (Type) import Data.Maybe (fromMaybe) import Data.Semigroup (Sum (Sum, getSum))-import Data.VectorSpace (AdditiveGroup (..), VectorSpace (..))+import Data.VectorSpace (AdditiveGroup (..), VectorSpace (..), zeroV)+import GHC.Generics (Generic (Rep, from, to), K1 (K1), M1 (M1), U1 (U1), V1, (:*:) ((:*:)))  -- | Argument @f@ in @Term f x@ must be /linear/ function. That's a law. data Term a v where@@ -57,69 +68,67 @@   type VecBuilder v :: Type    sumBuilder :: VecBuilder v -> v+  identityBuilder :: v -> VecBuilder v +  default sumBuilder ::+    forall b.+    ( VecBuilder v ~ Maybe b,+      Generic b,+      Generic v,+      GBasicVector (Rep b) (Rep v),+      AdditiveGroup v+    ) =>+    VecBuilder v ->+    v+  sumBuilder = genericSumMaybeBuilder @b @v++  default identityBuilder ::+    forall b.+    ( VecBuilder v ~ Maybe b,+      Generic b,+      Generic v,+      GBasicVector (Rep b) (Rep v),+      AdditiveGroup v+    ) =>+    v ->+    VecBuilder v+  identityBuilder = genericIdentityMaybeBuilder @b @v+ maybeToMonoid :: Monoid m => Maybe m -> m maybeToMonoid = fromMaybe mempty +_maybeToVector :: AdditiveGroup v => Maybe v -> v+_maybeToVector = fromMaybe zeroV+ instance BasicVector Integer where   type VecBuilder Integer = Sum Integer   sumBuilder = getSum+  identityBuilder = Sum  instance (BasicVector a, BasicVector b) => BasicVector (a, b) where   type VecBuilder (a, b) = Maybe (VecBuilder a, VecBuilder b)   sumBuilder = sumPair . maybeToMonoid     where       sumPair (a, b) = (sumBuilder a, sumBuilder b)+  identityBuilder (x, y) = Just (identityBuilder x, identityBuilder y)  instance (BasicVector a, BasicVector b, BasicVector c) => BasicVector (a, b, c) where   type VecBuilder (a, b, c) = Maybe (VecBuilder a, VecBuilder b, VecBuilder c)   sumBuilder = sumTriple . maybeToMonoid     where       sumTriple (a, b, c) = (sumBuilder a, sumBuilder b, sumBuilder c)+  identityBuilder (x, y, z) = Just (identityBuilder x, identityBuilder y, identityBuilder z)  instance BasicVector Float where   type VecBuilder Float = Sum Float   sumBuilder = getSum+  identityBuilder = Sum  instance BasicVector Double where   type VecBuilder Double = Sum Double   sumBuilder = getSum---- | Full-featured vector.------ Gradients are linear functions and form a vector space.--- @FullVector@ class provides functionality that is needed to--- make 'VectorSpace' instances.-class (BasicVector v, VectorSpace v) => FullVector v where-  identityBuilder :: v -> VecBuilder v-  negateBuilder :: v -> VecBuilder v-  scaleBuilder :: Scalar v -> v -> VecBuilder v--instance FullVector Float where   identityBuilder = Sum-  negateBuilder = Sum . negate-  scaleBuilder x = Sum . (x *) -instance FullVector Double where-  identityBuilder = Sum-  negateBuilder = Sum . negate-  scaleBuilder x = Sum . (x *)--instance FullVector Integer where-  identityBuilder = Sum-  negateBuilder = Sum . negate-  scaleBuilder x = Sum . (x *)--instance (Scalar a ~ Scalar b, FullVector a, FullVector b) => FullVector (a, b) where-  identityBuilder (x, y) = Just (identityBuilder x, identityBuilder y)-  negateBuilder (x, y) = Just (negateBuilder x, negateBuilder y)-  scaleBuilder a (x, y) = Just (scaleBuilder a x, scaleBuilder a y)--instance (s ~ Scalar a, s ~ Scalar b, s ~ Scalar c, FullVector a, FullVector b, FullVector c) => FullVector (a, b, c) where-  identityBuilder (x, y, z) = Just (identityBuilder x, identityBuilder y, identityBuilder z)-  negateBuilder (x, y, z) = Just (negateBuilder x, negateBuilder y, negateBuilder z)-  scaleBuilder a (x, y, z) = Just (scaleBuilder a x, scaleBuilder a y, scaleBuilder a z)- -- |  Normally graph node would compute the sum of gradients and then -- propagate it to ancestor nodes. That's the best strategy when -- some computation needs to be performed for backpropagation.@@ -135,6 +144,7 @@ instance Monoid (VecBuilder v) => BasicVector (SparseVector v) where   type VecBuilder (SparseVector v) = VecBuilder v   sumBuilder = SparseVector+  identityBuilder = unSparseVector  newtype DenseSemibuilder v = DenseSemibuilder {_unDenseSemibuilder :: v} @@ -156,18 +166,44 @@   type VecBuilder (DenseVector v) = DenseBuilder v   sumBuilder (DenseBuilder Nothing) = DenseVector zeroV   sumBuilder (DenseBuilder (Just x)) = DenseVector x--instance VectorSpace v => FullVector (DenseVector v) where   identityBuilder (DenseVector v) = DenseBuilder (Just v)-  negateBuilder (DenseVector v) = DenseBuilder (Just (negateV v))-  scaleBuilder a (DenseVector v) = DenseBuilder (Just (a *^ v)) -instance FullVector v => AdditiveGroup (Expr a v) where-  zeroV = ExprSum []-  negateV x = ExprSum [Term negateBuilder x]-  x ^+^ y = ExprSum [Term identityBuilder x, Term identityBuilder y]-  x ^-^ y = ExprSum [Term identityBuilder x, Term negateBuilder y]+class GBasicVector b v where+  gsumBuilder :: b p -> v p+  gidentityBuilder :: v p -> b p -instance FullVector dv => VectorSpace (Expr da dv) where-  type Scalar (Expr da dv) = Scalar dv-  a *^ v = ExprSum [Term (scaleBuilder a) v]+instance (BasicVector v, b ~ VecBuilder v) => GBasicVector (K1 x b) (K1 x v) where+  gsumBuilder (K1 x) = K1 (sumBuilder x)+  gidentityBuilder (K1 x) = K1 (identityBuilder x)++instance (GBasicVector b v) => GBasicVector (M1 x y b) (M1 x y' v) where+  gsumBuilder (M1 x) = M1 (gsumBuilder x)+  gidentityBuilder (M1 x) = M1 (gidentityBuilder x)++instance (GBasicVector bu u, GBasicVector bv v) => GBasicVector (bu :*: bv) (u :*: v) where+  gsumBuilder (x1 :*: x2) = gsumBuilder x1 :*: gsumBuilder x2+  gidentityBuilder (x1 :*: x2) = gidentityBuilder x1 :*: gidentityBuilder x2++instance GBasicVector V1 V1 where+  gsumBuilder = \case {}+  gidentityBuilder = \case {}++instance GBasicVector U1 U1 where+  gsumBuilder U1 = U1+  gidentityBuilder U1 = U1++genericSumBuilder :: forall b v. (Generic b, Generic v, GBasicVector (Rep b) (Rep v)) => b -> v+genericSumBuilder = to . gsumBuilder . from++genericIdentityBuilder :: forall b v. (Generic b, Generic v, GBasicVector (Rep b) (Rep v)) => v -> b+genericIdentityBuilder = to . gidentityBuilder . from++genericSumMaybeBuilder ::+  forall b v.+  (Generic b, Generic v, AdditiveGroup v, GBasicVector (Rep b) (Rep v)) =>+  Maybe b ->+  v+genericSumMaybeBuilder = maybe zeroV genericSumBuilder++genericIdentityMaybeBuilder :: forall b v. (Generic b, Generic v, GBasicVector (Rep b) (Rep v)) => v -> Maybe b+genericIdentityMaybeBuilder = Just . genericIdentityBuilder
src/Downhill/Linear/Lift.hs view
@@ -29,7 +29,7 @@ where  import Downhill.Linear.BackGrad (BackGrad (..), castBackGrad, realNode)-import Downhill.Linear.Expr (BasicVector (..), Expr (ExprSum), FullVector (identityBuilder), SparseVector (unSparseVector))+import Downhill.Linear.Expr (BasicVector (..), Expr (ExprSum), SparseVector (unSparseVector)) import Prelude hiding (fst, snd, zip)  lift1 ::@@ -111,12 +111,12 @@     fc' = fc . unSparseVector  lift1_dense ::-  (BasicVector v, FullVector a) =>+  (BasicVector v, BasicVector a) =>   ((v -> a) -> BackGrad r a -> BackGrad r v) lift1_dense fa = lift1 (identityBuilder . fa)  lift2_dense ::-  (BasicVector v, FullVector a, FullVector b) =>+  (BasicVector v, BasicVector a, BasicVector b) =>   (v -> a) ->   (v -> b) ->   BackGrad r a ->@@ -125,7 +125,7 @@ lift2_dense fa fb = lift2 (identityBuilder . fa) (identityBuilder . fb)  lift3_dense ::-  (BasicVector v, FullVector a, FullVector b, FullVector c) =>+  (BasicVector v, BasicVector a, BasicVector b, BasicVector c) =>   (v -> a) ->   (v -> b) ->   (v -> c) ->
+ src/Downhill/Metric.hs view
@@ -0,0 +1,65 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}++module Downhill.Metric+  ( MetricTensor (..)+  )+where++import Data.VectorSpace ((^+^))+import Downhill.Grad (Dual (evalGrad), HasGrad (Grad, Tang), MScalar)++-- | @MetricTensor@ converts gradients to vectors.+--+-- It is really inverse of a metric tensor, because it maps cotangent+-- space into tangent space. Gradient descent doesn't need metric tensor,+-- it needs inverse.+class Dual (Tang p) (Grad p) => MetricTensor p g where+  -- | @m@ must be symmetric:+  --+  -- @evalGrad x (evalMetric m y) = evalGrad y (evalMetric m x)@+  evalMetric :: g -> Grad p -> Tang p++  -- | @innerProduct m x y = evalGrad x (evalMetric m y)@+  innerProduct :: g -> Grad p -> Grad p -> MScalar p+  innerProduct g x y = evalGrad @(Tang p) @(Grad p) x (evalMetric @p g y)++  -- | @sqrNorm m x = innerProduct m x x@+  sqrNorm :: g -> Grad p -> MScalar p+  sqrNorm g x = innerProduct @p g x x++instance MetricTensor Integer Integer where+  evalMetric m x = m * x++instance (MScalar a ~ MScalar b, MetricTensor a ma, MetricTensor b mb) => MetricTensor (a, b) (ma, mb) where+  evalMetric (ma, mb) (a, b) = (evalMetric @a ma a, evalMetric @b mb b)+  sqrNorm (ma, mb) (a, b) = sqrNorm @a ma a ^+^ sqrNorm @b mb b++instance+  ( MScalar a ~ MScalar b,+    MScalar a ~ MScalar c,+    MetricTensor a ma,+    MetricTensor b mb,+    MetricTensor c mc+  ) =>+  MetricTensor (a, b, c) (ma, mb, mc)+  where+  evalMetric (ma, mb, mc) (a, b, c) = (evalMetric @a ma a, evalMetric @b mb b, evalMetric @c mc c)+  sqrNorm (ma, mb, mc) (a, b, c) = sqrNorm @a ma a ^+^ sqrNorm @b mb b ^+^ sqrNorm @c mc c++instance MetricTensor Float Float where+  evalMetric m dv = m * dv++instance MetricTensor Double Double where+  evalMetric m dv = m * dv++data L2 = L2++instance (Dual (Tang p) (Grad p), Grad p ~ Tang p) => MetricTensor p L2 where+  evalMetric L2 v = v
− src/Downhill/TH.hs
@@ -1,917 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE UndecidableInstances #-}---- | Use like this:------ @--- mkHasGradInstances---   defaultBVarOptions---   [d|---     instance HasGrad MyRecord where---       type MScalar MyRecord = Float---     |]--- @------ Instance declaration passed to @mkHasGradInstances@ gives two important bits of information:------   * Type variables for @MyRecord@, which can be concrete types (such as @instance HasGrad (MyRecord Float)@)---     or regular type variables (@instance HasGrad (MyRecord a)@)------   * Scalar type.----module Downhill.TH-  (-    mkHasGradInstances,-    AffineSpaceOptions (..),-    RecordNamer (..),-    BVarOptions (..),-    defaultBVarOptions,-  )-where--import Control.Monad-import Data.AdditiveGroup ((^+^), (^-^))-import Data.AffineSpace (AffineSpace (Diff, (.+^), (.-.)))-import Data.Foldable (traverse_)-import qualified Data.Map as Map-import Data.Maybe (catMaybes)-import Data.VectorSpace (AdditiveGroup (negateV, zeroV), VectorSpace (Scalar, (*^)))-import Downhill.BVar (BVar (BVar))-import Downhill.Grad-  ( Dual (evalGrad),-    HasGrad (Grad, MScalar, Metric, Tang),-    MetricTensor (MtCovector, MtVector, evalMetric, sqrNorm),-  )-import Downhill.Linear.Expr (BasicVector (VecBuilder, sumBuilder))-import Downhill.Linear.Lift (lift1_sparse)-import GHC.Records (HasField (getField))-import Language.Haskell.TH-  ( Bang (Bang),-    Con (NormalC, RecC),-    Cxt,-    Dec (DataD, InstanceD, NewtypeD, SigD),-    Exp (AppE, ConE, InfixE, VarE),-    Name,-    Pat (VarP),-    Q,-    SourceStrictness (NoSourceStrictness),-    SourceUnpackedness (NoSourceUnpackedness),-    Type (AppT, ConT, VarT),-    nameBase,-    newName,-  )-import Language.Haskell.TH.Datatype (ConstructorInfo (constructorFields, constructorName, constructorVariant), ConstructorVariant (InfixConstructor, NormalConstructor, RecordConstructor), DatatypeInfo (datatypeCons, datatypeInstTypes, datatypeName, datatypeVariant, datatypeVars), DatatypeVariant (Newtype), TypeSubstitution (applySubstitution), reifyDatatype)-import Language.Haskell.TH.Datatype.TyVarBndr (TyVarBndrUnit)-import Language.Haskell.TH.Syntax-  ( BangType,-    Body (NormalB),-    Clause (Clause),-    Dec (FunD, TySynInstD, ValD),-    Exp (AppTypeE),-    TyLit (StrTyLit),-    TySynEqn (TySynEqn),-    Type (ArrowT, EqualityT, LitT, SigT),-    VarBangType,-    mkNameS,-  )-import qualified  Language.Haskell.TH--data DatatypeFields-  = NormalFields [Type]-  | RecordFields [(String, Type)]-  deriving (Show)--data DownhillRecord = DownhillRecord-  { ddtTypeConName :: Name,-    ddtDataConName :: Name,-    ddtFieldTypes :: [Type],-    ddtFieldNames :: Maybe [String],-    ddtTypeVars :: [TyVarBndrUnit],-    ddtFieldCount :: Int,-    ddtVariant :: DatatypeVariant-  }-  deriving (Show)--data RecordNamer = RecordNamer-  { typeConNamer :: String -> String,-    dataConNamer :: String -> String,-    fieldNamer :: String -> String-  }--data RecordTranstorm = RecordTranstorm RecordNamer (Type -> Type)--data AffineSpaceOptions-  = -- | Generate AffineSpace instance-    MakeAffineSpace-  | -- | Don't generate AffineSpace instance-    NoAffineSpace-  | -- | Generate AffineSpace instance if @optExcludeFields@ is empty-    AutoAffineSpace--data BVarOptions = BVarOptions-  { optTangNamer :: RecordNamer,-    optGradNamer :: RecordNamer,-    optMetricNamer :: RecordNamer,-    optBuilderNamer :: RecordNamer,-    optAffineSpace :: AffineSpaceOptions,-     -- | List of fields that take no part in differentiation-    optExcludeFields :: [String]-  }--pattern ConP :: Name -> [Pat] -> Pat-#if MIN_VERSION_template_haskell(2,18,0)-pattern ConP x y = Language.Haskell.TH.ConP x [] y-#else-pattern ConP x y = Language.Haskell.TH.ConP x y-#endif--defaultTangRecordNamer :: RecordNamer-defaultTangRecordNamer =-  RecordNamer-    { typeConNamer = (++ "Tang"),-      dataConNamer = (++ "Tang"),-      fieldNamer = id-    }--defaultGradRecordNamer :: RecordNamer-defaultGradRecordNamer =-  RecordNamer-    { typeConNamer = (++ "Grad"),-      dataConNamer = (++ "Grad"),-      fieldNamer = id-    }--defaultMetricRecordNamer :: RecordNamer-defaultMetricRecordNamer =-  RecordNamer-    { typeConNamer = (++ "Metric"),-      dataConNamer = (++ "Metric"),-      fieldNamer = id-    }--defaultBuilderRecordNamer :: RecordNamer-defaultBuilderRecordNamer =-  RecordNamer-    { typeConNamer = (++ "Builder"),-      dataConNamer = (++ "Builder"),-      fieldNamer = id-    }--defaultBVarOptions :: BVarOptions-defaultBVarOptions =-  BVarOptions-    { optTangNamer = defaultTangRecordNamer,-      optGradNamer = defaultGradRecordNamer,-      optMetricNamer = defaultMetricRecordNamer,-      optBuilderNamer = defaultBuilderRecordNamer,-      optAffineSpace = AutoAffineSpace,-      optExcludeFields = []-    }--mkConstructor :: DownhillRecord -> Con-mkConstructor record =-  case ddtFieldNames record of-    Nothing ->-      NormalC newConstrName (map mkType (ddtFieldTypes record))-    Just names ->-      RecC newConstrName (zipWith mkRecType names (ddtFieldTypes record))-  where-    newConstrName :: Name-    newConstrName = ddtDataConName record-    mkRecType :: String -> Type -> VarBangType-    mkRecType name type_ =-      ( mkNameS name,-        Bang NoSourceUnpackedness NoSourceStrictness,-        type_-      )-    mkType :: Type -> BangType-    mkType type_ =-      ( Bang NoSourceUnpackedness NoSourceStrictness,-        type_-      )--parseGradConstructor :: Name -> DatatypeInfo -> ConstructorInfo -> [TyVarBndrUnit] -> Q DownhillRecord-parseGradConstructor tyName dinfo cinfo typevars = do-  let types = constructorFields cinfo-      n = length types-  (fieldTypes, fieldNames) <- case constructorVariant cinfo of-    NormalConstructor -> return (types, Nothing)-    InfixConstructor -> return (types, Nothing)-    RecordConstructor fieldNames -> do-      return (types, Just (nameBase <$> fieldNames))-  return-    DownhillRecord-      { ddtTypeConName = tyName,-        ddtDataConName = constructorName cinfo,-        ddtTypeVars = typevars,-        ddtFieldCount = n,-        ddtFieldTypes = fieldTypes,-        ddtFieldNames = fieldNames,-        ddtVariant = datatypeVariant dinfo-      }--parseDownhillRecord :: Name -> DatatypeInfo -> Q (DownhillRecord, ConstructorInfo)-parseDownhillRecord recordName record' = do-  let name = datatypeName record'-  let typevars = datatypeVars record'-      constructors' = datatypeCons record'-  constr' <- case constructors' of-    [] -> fail (show recordName <> " has no data constructors")-    [constr''] -> return constr''-    _ -> fail (show recordName <> " has multiple data constructors")--  r <- parseGradConstructor name record' constr' typevars-  return (r, constr')--elementwiseOp :: DownhillRecord -> Name -> Q Dec-elementwiseOp record = elementwiseOp' record record record--elementwiseOp' :: DownhillRecord -> DownhillRecord -> DownhillRecord -> Name -> Q Dec-elementwiseOp' leftRecord rightRecord resRecord func = do-  let n = ddtFieldCount resRecord-  --dataConName :: Name-  --dataConName = ddtDataConName record-  xs <- replicateM n (newName "x")-  ys <- replicateM n (newName "y")-  let fieldOp :: Name -> Name -> Exp-      fieldOp x y = InfixE (Just (VarE x)) (VarE func) (Just (VarE y))-      resultFields :: [Exp]-      resultFields = zipWith fieldOp xs ys-      leftPat = ConP (ddtDataConName leftRecord) (map VarP xs)-      rightPat = ConP (ddtDataConName rightRecord) (map VarP ys)-      rhs :: Exp-      rhs = foldl AppE (ConE (ddtDataConName resRecord)) resultFields-      dec =-        FunD-          func-          [ Clause-              [leftPat, rightPat]-              (NormalB rhs)-              []-          ]-  return dec--elementwiseValue :: DownhillRecord -> Name -> Q Dec-elementwiseValue record func = do-  let n = ddtFieldCount record-      dataConName :: Name-      dataConName = ddtDataConName record-      rhs :: Exp-      rhs = foldl AppE (ConE dataConName) (replicate n (VarE 'zeroV))-      dec = ValD (VarP func) (NormalB rhs) []-  return dec--elementwiseFunc :: DownhillRecord -> Name -> Q Dec-elementwiseFunc record func = do-  let n = ddtFieldCount record-      dataConName :: Name-      dataConName = ddtDataConName record-      rhsConName = ddtDataConName record-  xs <- case ddtFieldNames record of-    Nothing -> replicateM n (newName "x")-    Just names -> traverse newName names-  let fieldOp :: Name -> Exp-      fieldOp = AppE (VarE func) . VarE-      resultFields :: [Exp]-      resultFields = map fieldOp xs-      leftPat = ConP dataConName (map VarP xs)-      rhs :: Exp-      rhs = foldl AppE (ConE rhsConName) resultFields-      dec =-        FunD-          func-          [ Clause-              [leftPat]-              (NormalB rhs)-              []-          ]-  return dec--mkClassInstance :: Name -> Cxt -> DownhillRecord -> [Type] -> [Dec] -> Q [Dec]-mkClassInstance className cxt record instVars decs = do-  let recordType = ConT (ddtTypeConName record)-      ihead = AppT (ConT className) (foldl AppT recordType instVars)-  return [InstanceD Nothing cxt ihead decs]--mkSemigroupInstance :: Cxt -> DownhillRecord -> [Type] -> Q [Dec]-mkSemigroupInstance cxt record instVars = do-  dec <- elementwiseOp record '(<>)-  mkClassInstance ''Semigroup cxt record instVars [dec]--mkAdditiveGroupInstance :: Cxt -> DownhillRecord -> [Type] -> Q [Dec]-mkAdditiveGroupInstance cxt record instVars = do-  zeroVDec <- elementwiseValue record 'zeroV-  negateDec <- elementwiseFunc record 'negateV-  plusDec <- elementwiseOp record '(^+^)-  minusDec <- elementwiseOp record '(^-^)-  let decs =-        [ zeroVDec,-          negateDec,-          plusDec,-          minusDec-        ]-  mkClassInstance ''AdditiveGroup cxt record instVars decs--mkVectorSpaceInstance :: DownhillRecord -> Type -> Cxt -> [Type] -> Q [Dec]-mkVectorSpaceInstance record scalarType cxt instVars = do-  let n = ddtFieldCount record-      dataConName :: Name-      dataConName = ddtDataConName record-  xs <- case ddtFieldNames record of-    Nothing -> replicateM n (newName "x")-    Just names -> traverse newName names--  lhsName <- newName "s"-  let rightPat = ConP (ddtDataConName record) (map VarP xs)-      recordType = foldl AppT (ConT (ddtTypeConName record)) instVars-      mulField :: Name -> Exp-      mulField y = InfixE (Just (VarE lhsName)) (VarE '(*^)) (Just (VarE y))-      rhsMulV :: Exp-      rhsMulV = foldl AppE (ConE dataConName) (map mulField xs)-  let vmulDec =-        FunD-          '(*^)-          [ Clause-              [VarP lhsName, rightPat]-              (NormalB rhsMulV)-              []-          ]-      scalarTypeDec =-        TySynInstD-          ( TySynEqn-              Nothing-              (AppT (ConT ''Scalar) recordType)-              scalarType-          )-      decs = [scalarTypeDec, vmulDec]-  mkClassInstance ''VectorSpace cxt record instVars decs--mkBasicVectorInstance :: DownhillRecord -> BVarOptions -> Cxt -> [Type] -> Q [Dec]-mkBasicVectorInstance vectorRecord options cxt instVars = do-  sumBuilderDec <- mkSumBuilder-  mkClassInstance ''BasicVector cxt vectorRecord instVars [vecbuilderDec, sumBuilderDec]-  where-    n = ddtFieldCount vectorRecord-    builderRecord = renameDownhillRecord (builderTransform options) vectorRecord--    -- not an elementiseOp, because right hand side is wrapped in Maybe-    mkSumBuilder :: Q Dec-    mkSumBuilder = do-      builders <- replicateM n (newName "x")-      let pat :: Pat-          pat = ConP (ddtDataConName builderRecord) (map VarP builders)-          rhs :: Exp-          rhs =-            foldl-              AppE-              (ConE (ddtDataConName vectorRecord))-              [AppE (VarE 'sumBuilder) (VarE x) | x <- builders]-      return $-        FunD-          'sumBuilder-          [ Clause [ConP 'Nothing []] (NormalB (VarE 'zeroV)) [],-            Clause [ConP 'Just [pat]] (NormalB rhs) []-          ]--    vecbuilderDec =-      TySynInstD-        ( TySynEqn-            Nothing-            (AppT (ConT ''VecBuilder) vectorType)-            (AppT (ConT ''Maybe) builderType)-        )-      where-        vectorType = foldl AppT (ConT (ddtTypeConName vectorRecord)) instVars-        builderType = foldl AppT (ConT (ddtTypeConName builderRecord)) instVars--sumVExpr :: [Exp] -> Exp-sumVExpr = \case-  [] -> VarE 'zeroV-  exps -> foldl1 (zipExpInfix '(^+^)) exps-  where-    zipExpInfix :: Name -> Exp -> Exp -> Exp-    zipExpInfix f x y = InfixE (Just x) (VarE f) (Just y)--mkDualInstance ::-  DownhillRecord ->-  DownhillRecord ->-  Type ->-  Cxt ->-  [Type] ->-  Q [Dec]-mkDualInstance tangRecord gradRecord scalarType cxt instVars = do-  when (ddtFieldCount tangRecord /= ddtFieldCount gradRecord) $-    fail "mkDualInstance: ddtFieldCount tangRecord /= ddtFieldCount gradRecord"-  scalarTypeName <- newName "s"-  mkClassDec (VarT scalarTypeName)-  where-    n = ddtFieldCount tangRecord--    -- instance (cxt, AdditiveGroup s, s ~ scalarType) => AdditiveGroup (Record a1 … an) where-    --   …-    mkClassDec :: Type -> Q [Dec]-    mkClassDec scalarVar = do-      evalGradDec <- mkEvalGradDec-      return [InstanceD Nothing (cxt ++ newConstraints) ihead [evalGradDec]]-      where-        -- Dual s (RecordTang a1 … an) (RecordGrad a1 … an)-        ihead :: Type-        ihead = ConT ''Dual `AppT` scalarVar `AppT` vecType `AppT` gradType-          where-            vecType = foldl AppT (ConT $ ddtTypeConName tangRecord) instVars-            gradType = foldl AppT (ConT $ ddtTypeConName gradRecord) instVars-        newConstraints :: Cxt-        newConstraints =-          [ -- AdditiveGroup s-            AppT (ConT ''AdditiveGroup) scalarVar,-            -- s ~ scalarType-            AppT (AppT EqualityT scalarVar) scalarType-          ]--        -- evalGrad (RecordGrad x1 … xn) (RecordTang y1 … yn) = evalGrad x1 y1 ^+^ … ^+^ evalGrad xn yn-        mkEvalGradDec :: Q Dec-        mkEvalGradDec = do-          xs <- replicateM n (newName "x")-          ys <- replicateM n (newName "y")-          let leftPat = ConP (ddtDataConName gradRecord) (map VarP xs)-              rightPat = ConP (ddtDataConName tangRecord) (map VarP ys)-              -- terms = [evalGrad x1 y1, …, evalGrad xn yn]-              terms :: [Exp]-              terms = zipWith evalGradExp xs ys-                where-                  evalGradExp :: Name -> Name -> Exp-                  evalGradExp x y = VarE 'evalGrad `AppE` VarE x `AppE` VarE y-              rhs = sumVExpr terms-          return $-            FunD-              'evalGrad-              [ Clause-                  [leftPat, rightPat]-                  (NormalB rhs)-                  []-              ]--mkMetricInstance ::-  DownhillRecord ->-  DownhillRecord ->-  DownhillRecord ->-  Type ->-  Cxt ->-  [Type] ->-  Q [Dec]-mkMetricInstance metricRecord tangRecord gradRecord scalarType cxt instVars = do-  scalarTypeName <- newName "s"-  mkClassDec (VarT scalarTypeName)-  where-    -- instance (ctx, s ~ scalarType) => MetricTensor s (RecordMetric a1 … an) where-    --   …-    mkClassDec :: Type -> Q [Dec]-    mkClassDec scalarVar = do-      let newConstraints =-            [ -- s ~ scalarType-              AppT (AppT EqualityT scalarVar) scalarType-            ]-          -- MetricTensor s (RecordMetric a1 … an)-          ihead = ConT ''MetricTensor `AppT` metricType-      evalMetricDec <- mkEvalMetric-      sqrNormDec <- mkSqrNorm-      return-        [ InstanceD-            Nothing-            (cxt ++ newConstraints)-            ihead-            [vectypeDec, covectorTypeDec, evalMetricDec, sqrNormDec]-        ]-      where-        vectorType :: Type-        vectorType = foldl AppT (ConT $ ddtTypeConName tangRecord) instVars-        covectorType :: Type-        covectorType = foldl AppT (ConT $ ddtTypeConName gradRecord) instVars-        metricType :: Type-        metricType = foldl AppT (ConT $ ddtTypeConName metricRecord) instVars-        -- type MtVector (RecordMetric a1 … an) = RecordTang a1 … an-        vectypeDec =-          TySynInstD-            ( TySynEqn-                Nothing-                (AppT (ConT ''MtVector) metricType)-                vectorType-            )-        -- type MtCovector (RecordMetric a1 … an) = RecordGrad a1 … an-        covectorTypeDec =-          TySynInstD-            ( TySynEqn-                Nothing-                (AppT (ConT ''MtCovector) metricType)-                covectorType-            )--        mkEvalMetric :: Q Dec-        mkEvalMetric = do-          let n = ddtFieldCount metricRecord-          xs <- replicateM n (newName "m")-          ys <- replicateM n (newName "dv")-          let leftPat, rightPat :: Pat-              leftPat = ConP (ddtDataConName metricRecord) (map VarP xs)-              rightPat = ConP (ddtDataConName gradRecord) (map VarP ys)-              terms :: [Exp]-              terms = zipWith evalGradExp xs ys-                where-                  evalGradExp :: Name -> Name -> Exp-                  evalGradExp x y = VarE 'evalMetric `AppE` VarE x `AppE` VarE y-              rhs =-                foldl-                  AppE-                  (ConE (ddtDataConName tangRecord))-                  terms-          return $-            FunD-              'evalMetric-              [ Clause-                  [leftPat, rightPat]-                  (NormalB rhs)-                  []-              ]--        mkSqrNorm :: Q Dec-        mkSqrNorm = do-          let n = ddtFieldCount metricRecord-          xs <- replicateM n (newName "m")-          ys <- replicateM n (newName "dv")-          let leftPat, rightPat :: Pat-              leftPat = ConP (ddtDataConName metricRecord) (map VarP xs)-              rightPat = ConP (ddtDataConName gradRecord) (map VarP ys)-              terms :: [Exp]-              terms = zipWith evalSqrtNorm xs ys-                where-                  evalSqrtNorm :: Name -> Name -> Exp-                  evalSqrtNorm x y = VarE 'sqrNorm `AppE` VarE x `AppE` VarE y-              rhs = sumVExpr terms-          return $-            FunD-              'sqrNorm-              [ Clause-                  [leftPat, rightPat]-                  (NormalB rhs)-                  []-              ]--mkRecord :: DownhillRecord -> Q [Dec]-mkRecord record = do-  let newConstr = mkConstructor record-  let newRecordName = ddtTypeConName record-  let dataType = case ddtVariant record of-        Newtype -> NewtypeD [] newRecordName (ddtTypeVars record) Nothing newConstr []-        _ -> DataD [] newRecordName (ddtTypeVars record) Nothing [newConstr] []-  return [dataType]--renameTypeS :: (String -> String) -> Name -> Name-renameTypeS f = mkNameS . f . nameBase--data FieldInfo = FieldInfo-  { fiName :: String,-    fiIndex :: Int,-    fiType :: Type-  }--mkGetField ::-  DownhillRecord ->-  DownhillRecord ->-  Cxt ->-  [Type] ->-  FieldInfo ->-  Q [Dec]-mkGetField pointRecord gradBuilderRecord cxt instVars field = do-  rName <- newName "r"-  xName <- newName "x"-  dxName <- newName "dx"-  goName <- newName "go"-  dxdaName <- newName "dx_da"-  let rhsFieldList :: [Exp]-      rhsFieldList =-        replicate (fiIndex field) (VarE 'mempty)-          ++ [VarE dxdaName]-          ++ replicate (n - fiIndex field - 1) (VarE 'mempty)-      -- rhs = MyRecordGradBuilder mempty … mempty dx_da_a6SX mempty … mempty-      rhs :: Exp-      rhs = foldl AppE (ConE (ddtDataConName gradBuilderRecord)) rhsFieldList-  return-    [ InstanceD-        Nothing-        cxt-        ( AppT-            ( AppT-                (AppT (ConT ''HasField) (LitT (StrTyLit (fiName field))))-                (AppT (AppT (ConT ''BVar) (VarT rName)) pointType)-            )-            (AppT (AppT (ConT ''BVar) (VarT rName)) (fiType field))-        )-        [ FunD-            'getField-            [ Clause-                [ConP 'BVar [VarP xName, VarP dxName]]-                ( NormalB-                    ( AppE-                        ( AppE-                            (ConE 'BVar)-                            (AppE (AppTypeE (VarE 'getField) (LitT (StrTyLit (fiName field)))) (VarE xName))-                        )-                        (AppE (AppE (VarE 'lift1_sparse) (VarE goName)) (VarE dxName))-                    )-                )-                [ SigD-                    goName-                    ( AppT-                        ( AppT-                            ArrowT-                            ( ConT ''VecBuilder-                                `AppT` AppT (ConT ''Grad) (fiType field)-                            )-                        )-                        (ConT ''Maybe `AppT` gradBuilderType)-                    ),-                  FunD-                    goName-                    [ Clause-                        [VarP dxdaName]-                        ( NormalB-                            ( AppE-                                (ConE 'Just)-                                rhs-                            )-                        )-                        []-                    ]-                ]-            ]-        ]-    ]-  where-    n = ddtFieldCount pointRecord-    applyVars :: Type -> Type-    applyVars x = foldl AppT x instVars-    pointType :: Type-    pointType = applyVars (ConT $ ddtTypeConName pointRecord)-    gradBuilderType = applyVars (ConT $ ddtTypeConName gradBuilderRecord)--renameDownhillRecord :: RecordTranstorm -> DownhillRecord -> DownhillRecord-renameDownhillRecord (RecordTranstorm namer typeFun) record =-  DownhillRecord-    { ddtTypeConName = renameTypeS (typeConNamer namer) (ddtTypeConName record),-      ddtDataConName = renameTypeS (dataConNamer namer) (ddtDataConName record),-      ddtTypeVars = ddtTypeVars record,-      ddtFieldCount = ddtFieldCount record,-      ddtFieldTypes = typeFun <$> ddtFieldTypes record,-      ddtFieldNames = fmap (fmap (fieldNamer namer)) (ddtFieldNames record),-      ddtVariant = ddtVariant record-    }--builderTransform :: BVarOptions -> RecordTranstorm-builderTransform options = RecordTranstorm (optBuilderNamer options) (AppT (ConT ''VecBuilder))--tangTransform :: BVarOptions -> RecordTranstorm-tangTransform options = RecordTranstorm (optTangNamer options) (AppT (ConT ''Tang))--gradTransform :: BVarOptions -> RecordTranstorm-gradTransform options = RecordTranstorm (optGradNamer options) (AppT (ConT ''Grad))--metricTransform :: BVarOptions -> RecordTranstorm-metricTransform options = RecordTranstorm (optMetricNamer options) (AppT (ConT ''Metric))--mkVec :: Cxt -> [Type] -> Type -> DownhillRecord -> BVarOptions -> Q [Dec]-mkVec cxt instVars scalarType vectorType options = do-  let builderType = renameDownhillRecord (builderTransform options) vectorType-  tangDec <- mkRecord vectorType-  tangBuilderDec <- mkRecord builderType-  tangSemigroup <- mkSemigroupInstance cxt builderType instVars-  tangInst <- mkBasicVectorInstance vectorType options cxt instVars-  additiveTang <- mkAdditiveGroupInstance cxt vectorType instVars-  vspaceTang <- mkVectorSpaceInstance vectorType scalarType cxt instVars-  return-    ( concat-        [ tangDec,-          tangBuilderDec,-          tangInst,-          tangSemigroup,-          additiveTang,-          vspaceTang-        ]-    )--mkDVar'' ::-  Cxt ->-  DownhillRecord ->-  BVarOptions ->-  Type ->-  [Type] ->-  ConstructorInfo ->-  Q [Dec]-mkDVar'' cxt pointRecord options scalarType instVars substitutedCInfo = do-  let tangRecord = renameDownhillRecord (tangTransform options) pointRecord-      gradRecord = renameDownhillRecord (gradTransform options) pointRecord-      metricRecord = renameDownhillRecord (metricTransform options) pointRecord--  tangDecs <- mkVec cxt instVars scalarType tangRecord options-  gradDecs <- mkVec cxt instVars scalarType gradRecord options--  metricDec <- mkRecord metricRecord-  additiveMetric <- mkAdditiveGroupInstance cxt metricRecord instVars-  vspaceMetric <- mkVectorSpaceInstance metricRecord scalarType cxt instVars-  dualInstance <- mkDualInstance tangRecord gradRecord scalarType cxt instVars-  metricInstance <- mkMetricInstance metricRecord tangRecord gradRecord scalarType cxt instVars-  let needAffineSpace = case optAffineSpace options of-        MakeAffineSpace -> True-        NoAffineSpace -> False-        AutoAffineSpace -> null (optExcludeFields options)--  affineSpaceInstance <--    if needAffineSpace-      then mkAffineSpaceInstance cxt pointRecord tangRecord instVars-      else return []--  hasFieldInstance <- case ddtFieldNames pointRecord of-    Nothing -> return []-    Just names ->-      let info :: Int -> String -> Type -> FieldInfo-          info index name = FieldInfo name index-          substitutedFields = constructorFields substitutedCInfo-          fields :: [FieldInfo]-          fields = zipWith3 info [0 ..] names substitutedFields-       in concat-            <$> traverse-              ( mkGetField-                  pointRecord-                  ( renameDownhillRecord (builderTransform options) gradRecord-                  )-                  cxt-                  instVars-              )-              fields--  let decs =-        [ tangDecs,-          gradDecs,-          additiveMetric,-          vspaceMetric,-          dualInstance,-          metricDec,-          metricInstance,-          hasFieldInstance,-          affineSpaceInstance-        ]-  return (concat decs)--parseRecordType :: Type -> [Type] -> Q (Name, [Type])-parseRecordType type_ vars = case type_ of-  AppT inner typeVar -> parseRecordType inner (typeVar : vars)-  ConT recordName -> return (recordName, vars)-  _ -> fail "Expected (T a1 ... an) in constraint"--mkAffineSpaceInstance :: Cxt -> DownhillRecord -> DownhillRecord -> [Type] -> Q [Dec]-mkAffineSpaceInstance cxt recordPoint recordTang instVars = do-  plusDec <- elementwiseOp' recordPoint recordTang recordPoint '(.+^)-  minusDec <- elementwiseOp' recordPoint recordPoint recordTang '(.-.)-  let recordTypePoint = foldl AppT (ConT (ddtTypeConName recordPoint)) instVars-      recordTypeTang = foldl AppT (ConT (ddtTypeConName recordTang)) instVars-      diffTypeDec =-        TySynInstD-          ( TySynEqn-              Nothing-              (AppT (ConT ''Diff) recordTypePoint)-              recordTypeTang-          )-  let decs =-        [ plusDec,-          minusDec,-          diffTypeDec-        ]-  mkClassInstance ''AffineSpace cxt recordPoint instVars decs--filterFields :: forall m. MonadFail m => BVarOptions -> DownhillRecord -> m DownhillRecord-filterFields options record =-  case optExcludeFields options of-    [] -> return record-    _ -> do-      fieldList <- case ddtFieldNames record of-        Just fields -> return fields-        Nothing -> fail (nameBase (ddtTypeConName record) ++ " is not a records, can't exclude fields")-      doFilterFields fieldList-  where-    doFilterFields fieldList = do-      traverse_ check (optExcludeFields options)-      return-        record-          { ddtFieldTypes = go (ddtFieldTypes record),-            ddtFieldNames = go <$> ddtFieldNames record,-            ddtFieldCount = goN (ddtFieldCount record)-          }-      where-        check :: String -> m ()-        check name-          | name `elem` fieldList = return ()-          | otherwise = fail ("Field " ++ name ++ " is not a member of " ++ nameBase (ddtTypeConName record))-        excludeZipList :: [x -> Maybe x]-        excludeZipList = filterField <$> fieldList-          where-            filterField :: String -> x -> Maybe x-            filterField fieldName x-              | fieldName `elem` optExcludeFields options = Nothing-              | otherwise = Just x-        go :: [a] -> [a]-        go = catMaybes . zipWith ($) excludeZipList-        goN :: Int -> Int-        goN n = length . go $ replicate n ()--mkDVarC1 :: BVarOptions -> Dec -> Q [Dec]-mkDVarC1 options = \case-  InstanceD mayOverlap cxt type_ decs -> do-    case mayOverlap of-      Just _ -> fail "Overlapping instances not implemented"-      _ -> return ()-    case type_ of-      AppT (ConT hasgradCtx) recordInConstraintType -> do-        when (hasgradCtx /= ''HasGrad) $-          fail $ "Constraint must be `HasGrad`, got " ++ show hasgradCtx-        (recordName, instVars) <- parseRecordType recordInConstraintType []-        record' <- reifyDatatype recordName--        (fullParsedRecord, cinfo) <- parseDownhillRecord recordName record'-        parsedRecord <- filterFields options fullParsedRecord-        recordTypeVarNames <- do-          let getName x = case x of-                SigT (VarT y) _ -> return y-                _ -> fail "Type variable is not VarT"-          traverse getName (datatypeInstTypes record')-        -- We have two sets of type variables: one in record definition (as in `data MyRecord a b c = ...`)-        -- and another one in instance head (`instance HasGrad (MyRecord a' b' c')). We need-        -- those from instance head for HasField instances.-        let substPairs = zip recordTypeVarNames instVars-            substitutedRecord = applySubstitution (Map.fromList substPairs) cinfo--        scalarType <- case decs of-          [] -> fail "`HasGrad` instance has no declarations"-          [dec1] -> case dec1 of-            TySynInstD (TySynEqn _ (AppT (ConT scalarName) _) scalarType) -> do-              when (scalarName /= ''MScalar) $-                fail ("Expected `Scalar` equation, got " ++ show scalarName)-              return scalarType-            _ -> fail "HasGrad instance must contain `Scalar ... = ...` declaration"-          _ -> fail "`HasGrad` has multiple declarations"--        dvar <- mkDVar'' cxt parsedRecord options scalarType instVars substitutedRecord--        let tangName = ddtTypeConName (renameDownhillRecord (tangTransform options) parsedRecord)-            gradName = ddtTypeConName (renameDownhillRecord (gradTransform options) parsedRecord)-            metricName = ddtTypeConName (renameDownhillRecord (metricTransform options) parsedRecord)-            tangTypeDec =-              TySynInstD-                ( TySynEqn-                    Nothing-                    (AppT (ConT ''Tang) recordInConstraintType)-                    (foldl AppT (ConT tangName) instVars)-                )-            gradTypeDec =-              TySynInstD-                ( TySynEqn-                    Nothing-                    (AppT (ConT ''Grad) recordInConstraintType)-                    (foldl AppT (ConT gradName) instVars)-                )-            metricTypeDec =-              TySynInstD-                ( TySynEqn-                    Nothing-                    (AppT (ConT ''Metric) recordInConstraintType)-                    (foldl AppT (ConT metricName) instVars)-                )--            hasgradInstance =-              InstanceD-                Nothing-                cxt-                type_-                ( decs-                    ++ [ tangTypeDec,-                         gradTypeDec,-                         metricTypeDec-                       ]-                )-        return $ dvar ++ [hasgradInstance]-      _ -> fail "Instance head is not a constraint"-  _ -> fail "Expected instance declaration"---- | Generates @HasGrad@ instance, along with @Tang@ and @Grad@ types,--- @VecBuilder@ types and all other instances needed for @HasGrad@.-mkHasGradInstances :: BVarOptions -> Q [Dec] -> Q [Dec]-mkHasGradInstances options decs = concat <$> (traverse (mkDVarC1 options) =<< decs)
+ test/DownhillTest/Bilinear.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedStrings #-}++module DownhillTest.Bilinear where++import Data.AffineSpace ((.+^))+import Data.VectorSpace (AdditiveGroup, VectorSpace ((*^), Scalar), (^+^))+import Downhill.BVar (BVar (bvarValue))+import qualified Downhill.BVar as BVar+import Downhill.Grad (Dual (evalGrad), HasGrad (Grad), MScalar)+import Hedgehog+  ( Gen,+    Property,+    forAll,+    property,+    (===),+  )+import Test.Tasty (TestTree, testGroup)+import Test.Tasty.Hedgehog (testProperty, testPropertyNamed)+import GHC.Base (VecElem(DoubleElemRep))+import Hedgehog.Internal.Show (Value(Integer))+import qualified Hedgehog.Internal.Show as Gen+import qualified Hedgehog.Gen as Gen+import qualified Hedgehog.Range as Range+import GHC.Generics (Generic)+import Downhill.Linear.Expr (BasicVector, DenseVector (DenseVector))++testBilinear ::+  ( Show u,+    Show v,+    HasGrad u,+    HasGrad v,+    Show (Grad z),+    HasGrad z,+    Eq z,+    AdditiveGroup u,+    Show z,+    AdditiveGroup z,+    Dual (Grad u) u,+    Eq (Scalar u),+    Show (Scalar u),+    Scalar u ~ Scalar z,+    Scalar v ~ Scalar z,+    Dual (Grad z) z, Show (MScalar z), Dual (Grad v) v) =>+  (u -> v -> z) ->+  (forall r. BVar r u -> BVar r v -> BVar r z) ->+  Gen u ->+  Gen v ->+  Gen (Grad z) ->+  Property+testBilinear f bf genU genV genDZ = property $ do+  u <- forAll genU+  v <- forAll genV+  dz <- forAll genDZ+  let z = f u v+      BVar.T2 bu bv = BVar.var (u, v)+      bz = bf bu bv+      (du, dv) = BVar.backprop bz dz+  bvarValue bz === z -- check that `f` and `bf` is the same function+  evalGrad u du === evalGrad z dz+  evalGrad v dv === evalGrad z dz++data Vector = Vector Integer Integer+  deriving Generic++instance AdditiveGroup Vector+instance VectorSpace Vector++bilinearIntMulProperty :: Property+bilinearIntMulProperty = testBilinear ((*) @Integer) (*) genInt genInt genInt+  where+    scalarMul :: Integer -> Integer -> Integer+    scalarMul = (*)+    genInt :: Gen Integer+    genInt = Gen.integral (Range.linear (-100) 100)+++bilinearTests :: TestTree+bilinearTests =+   testGroup "Bilinear operations"+     [ testPropertyNamed "Scalar multiplication" "bilinearIntMulProperty" bilinearIntMulProperty+       -- TODO: scalar-vector product, inner product+     ]
− test/DownhillTest/TH.hs
@@ -1,102 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE TypeApplications #-}--module DownhillTest.TH (thTest) where--import Data.AffineSpace (AffineSpace (..))-import Downhill.Grad (HasGrad (MScalar, Tang))-import Downhill.TH (BVarOptions (..), RecordNamer (..), mkHasGradInstances)-import Test.Tasty (TestTree, testGroup)-import DownhillTest.TestTHOptions (defaultDVarOptions)--{-# ANN module "HLint: ignore Use newtype instead of data" #-}-newtype MyRecord1 = MyRecord1 Float--data MyRecord2 = MyRecord2 Float--mkHasGradInstances-  defaultDVarOptions-  [d|-    instance HasGrad MyRecord1 where-      type MScalar MyRecord1 = Float-    |]--mkHasGradInstances-  defaultDVarOptions-  [d|-    instance HasGrad MyRecord2 where-      type MScalar MyRecord2 = Float-    |]--data MyRecord3 = MyRecord3--mkHasGradInstances-  defaultDVarOptions-  [d|-    instance HasGrad MyRecord3 where-      type MScalar MyRecord3 = ()-    |]--data MyRecord4 a = MyRecord4 a--mkHasGradInstances-  defaultDVarOptions-  [d|-    instance (AffineSpace a, HasGrad a, Diff a ~ Tang a) => HasGrad (MyRecord4 a) where-      type MScalar (MyRecord4 a) = MScalar a-    |]--data MyRecord5 a b = MyRecord5 a b--mkHasGradInstances-  defaultDVarOptions-  [d|-    instance-      ( AffineSpace a,-        AffineSpace b,-        HasGrad a,-        HasGrad b,-        MScalar a ~ MScalar b,-        Diff a ~ Tang a,-        Diff b ~ Tang b-      ) =>-      HasGrad (MyRecord5 a b)-      where-      type MScalar (MyRecord5 a b) = MScalar a-    |]--data MyRecord6 a b = MyRecord6 a b--mkHasGradInstances-  defaultDVarOptions-  [d|-    instance-      ( AffineSpace a,-        HasGrad a,-        MScalar a ~ Float,-        Diff a ~ Tang a-      ) =>-      HasGrad (MyRecord6 a Float)-      where-      type MScalar (MyRecord6 a Float) = Float-    |]--data MyRecord7 a = MyRecord7-  { myField7 :: a-  , myLabel7 :: String-  }--mkHasGradInstances-  defaultDVarOptions {optExcludeFields = ["myLabel7"]}-  [d|-    instance HasGrad a => HasGrad (MyRecord7 a) where-      type MScalar (MyRecord7 a) = MScalar a-    |]--thTest :: TestTree-thTest = testGroup "Template Haskell" [] -- just test if it compiles...
− test/DownhillTest/TestTHOptions.hs
@@ -1,46 +0,0 @@-module DownhillTest.TestTHOptions(defaultDVarOptions) where-import Downhill.TH ( mkHasGradInstances, RecordNamer(..), BVarOptions(..), AffineSpaceOptions (AutoAffineSpace))--defaultTangRecordNamer :: RecordNamer-defaultTangRecordNamer =-  RecordNamer-    { typeConNamer = (++ "TangT"),-      dataConNamer = (++ "TangD"),-      fieldNamer = id-    }--defaultGradRecordNamer :: RecordNamer-defaultGradRecordNamer =-  RecordNamer-    { typeConNamer = (++ "GradT"),-      dataConNamer = (++ "GradD"),-      fieldNamer = id-    }--defaultMetricRecordNamer :: RecordNamer-defaultMetricRecordNamer =-  RecordNamer-    { typeConNamer = (++ "MetricT"),-      dataConNamer = (++ "MetricD"),-      fieldNamer = id-    }--defaultBuilderRecordNamer :: RecordNamer-defaultBuilderRecordNamer =-  RecordNamer-    { typeConNamer = (++ "BuilderT"),-      dataConNamer = (++ "BuilderD"),-      fieldNamer = id-    }--defaultDVarOptions :: BVarOptions-defaultDVarOptions =-  BVarOptions-    { optTangNamer = defaultTangRecordNamer,-      optGradNamer = defaultGradRecordNamer,-      optMetricNamer = defaultMetricRecordNamer,-      optBuilderNamer = defaultBuilderRecordNamer,-      optAffineSpace = AutoAffineSpace,-      optExcludeFields = []-    }-
test/Main.hs view
@@ -5,7 +5,7 @@ import qualified Test.Tasty as Tasty import Downhill.BVar.Num (NumBVar(..), backpropNum, constant, var, numbvarValue, AsNum) import DownhillTest.Traversable(recordTest)-import DownhillTest.TH (thTest)+import DownhillTest.Bilinear(bilinearTests)  basicTests = testGroup "Basic tests"   [ testCase "Derivative of constant == 0" testConstant@@ -20,6 +20,6 @@             in backpropNum ((2+3*x) * (5+7*x)) @?= 29 + 42 * numbvarValue x  tests :: TestTree-tests = testGroup "Tests" [basicTests, recordTest, thTest]+tests = testGroup "Tests" [basicTests, recordTest, bilinearTests]  main = defaultMain tests