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 +8/−1
- downhill.cabal +10/−4
- src/Downhill/BVar.hs +54/−13
- src/Downhill/BVar/Num.hs +5/−13
- src/Downhill/BVar/Traversable.hs +22/−42
- src/Downhill/Grad.hs +44/−125
- src/Downhill/Linear/BackGrad.hs +6/−8
- src/Downhill/Linear/Backprop.hs +2/−3
- src/Downhill/Linear/Expr.hs +84/−48
- src/Downhill/Linear/Lift.hs +4/−4
- src/Downhill/Metric.hs +65/−0
- src/Downhill/TH.hs +0/−917
- test/DownhillTest/Bilinear.hs +92/−0
- test/DownhillTest/TH.hs +0/−102
- test/DownhillTest/TestTHOptions.hs +0/−46
- test/Main.hs +2/−2
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