backprop 0.2.6.5 → 0.2.7.0
raw patch · 16 files changed
+4689/−4112 lines, 16 filesdep −primitivesetup-changedPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies removed: primitive
API changes (from Hackage documentation)
- Numeric.Backprop.Class: instance Numeric.Backprop.Class.Backprop Data.Void.Void
+ Numeric.Backprop: ($dmadd) :: (Backprop a, Generic a, GAdd (Rep a)) => a -> a -> a
+ Numeric.Backprop: ($dmone) :: (Backprop a, Generic a, GOne (Rep a)) => a -> a
+ Numeric.Backprop: ($dmzero) :: (Backprop a, Generic a, GZero (Rep a)) => a -> a
+ Numeric.Backprop.Class: ($dmadd) :: (Backprop a, Generic a, GAdd (Rep a)) => a -> a -> a
+ Numeric.Backprop.Class: ($dmone) :: (Backprop a, Generic a, GOne (Rep a)) => a -> a
+ Numeric.Backprop.Class: ($dmzero) :: (Backprop a, Generic a, GZero (Rep a)) => a -> a
+ Numeric.Backprop.Class: instance Numeric.Backprop.Class.Backprop GHC.Base.Void
+ Numeric.Backprop.Explicit: ($dmadd) :: (Backprop a, Generic a, GAdd (Rep a)) => a -> a -> a
+ Numeric.Backprop.Explicit: ($dmone) :: (Backprop a, Generic a, GOne (Rep a)) => a -> a
+ Numeric.Backprop.Explicit: ($dmzero) :: (Backprop a, Generic a, GZero (Rep a)) => a -> a
+ Numeric.Backprop.Internal: AF :: (a -> a -> a) -> AddFunc a
+ Numeric.Backprop.Internal: OF :: (a -> a) -> OneFunc a
+ Numeric.Backprop.Internal: ZF :: (a -> a) -> ZeroFunc a
+ Numeric.Backprop.Internal: [runAF] :: AddFunc a -> a -> a -> a
+ Numeric.Backprop.Internal: [runOF] :: OneFunc a -> a -> a
+ Numeric.Backprop.Internal: [runZF] :: ZeroFunc a -> a -> a
+ Numeric.Backprop.Internal: addFunc :: Backprop a => AddFunc a
+ Numeric.Backprop.Internal: afNum :: Num a => AddFunc a
+ Numeric.Backprop.Internal: backpropWithN :: forall (as :: [Type]) b. Rec ZeroFunc as -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, b -> Rec Identity as)
+ Numeric.Backprop.Internal: coerceVar :: Coercible a b => BVar s a -> BVar s b
+ Numeric.Backprop.Internal: collectVar :: forall t a s. (Reifies s W, Foldable t, Functor t) => AddFunc a -> ZeroFunc a -> t (BVar s a) -> BVar s (t a)
+ Numeric.Backprop.Internal: constVar :: a -> BVar s a
+ Numeric.Backprop.Internal: data BVar s a
+ Numeric.Backprop.Internal: data W
+ Numeric.Backprop.Internal: debugIR :: InpRef a -> String
+ Numeric.Backprop.Internal: debugSTN :: SomeTapeNode -> String
+ Numeric.Backprop.Internal: evalBPN :: forall (as :: [Type]) b. (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> b
+ Numeric.Backprop.Internal: instance (GHC.Float.Floating a, Data.Reflection.Reifies s Numeric.Backprop.Internal.W) => GHC.Float.Floating (Numeric.Backprop.Internal.BVar s a)
+ Numeric.Backprop.Internal: instance (GHC.Num.Num a, Data.Reflection.Reifies s Numeric.Backprop.Internal.W) => GHC.Num.Num (Numeric.Backprop.Internal.BVar s a)
+ Numeric.Backprop.Internal: instance (GHC.Real.Fractional a, Data.Reflection.Reifies s Numeric.Backprop.Internal.W) => GHC.Real.Fractional (Numeric.Backprop.Internal.BVar s a)
+ Numeric.Backprop.Internal: instance (Numeric.Backprop.Class.Backprop a, Data.Reflection.Reifies s Numeric.Backprop.Internal.W) => Numeric.Backprop.Class.Backprop (Numeric.Backprop.Internal.BVar s a)
+ Numeric.Backprop.Internal: instance Control.DeepSeq.NFData (Numeric.Backprop.Internal.BRef s)
+ Numeric.Backprop.Internal: instance Control.DeepSeq.NFData a => Control.DeepSeq.NFData (Numeric.Backprop.Internal.BVar s a)
+ Numeric.Backprop.Internal: instance Data.Vinyl.XRec.IsoHKD (Numeric.Backprop.Internal.BVar s) a
+ Numeric.Backprop.Internal: instance GHC.Classes.Eq a => GHC.Classes.Eq (Numeric.Backprop.Internal.BVar s a)
+ Numeric.Backprop.Internal: instance GHC.Classes.Ord a => GHC.Classes.Ord (Numeric.Backprop.Internal.BVar s a)
+ Numeric.Backprop.Internal: instance GHC.Generics.Generic (Numeric.Backprop.Internal.BRef s)
+ Numeric.Backprop.Internal: instance GHC.Show.Show (Numeric.Backprop.Internal.BRef s)
+ Numeric.Backprop.Internal: liftOp :: forall (as :: [Type]) b s. Reifies s W => Rec AddFunc as -> Op as b -> Rec (BVar s) as -> BVar s b
+ Numeric.Backprop.Internal: liftOp1 :: forall a b s. Reifies s W => AddFunc a -> Op '[a] b -> BVar s a -> BVar s b
+ Numeric.Backprop.Internal: liftOp2 :: forall a b c s. Reifies s W => AddFunc a -> AddFunc b -> Op '[a, b] c -> BVar s a -> BVar s b -> BVar s c
+ Numeric.Backprop.Internal: liftOp3 :: forall a b c d s. Reifies s W => AddFunc a -> AddFunc b -> AddFunc c -> Op '[a, b, c] d -> BVar s a -> BVar s b -> BVar s c -> BVar s d
+ Numeric.Backprop.Internal: newtype AddFunc a
+ Numeric.Backprop.Internal: newtype OneFunc a
+ Numeric.Backprop.Internal: newtype ZeroFunc a
+ Numeric.Backprop.Internal: ofNum :: Num a => OneFunc a
+ Numeric.Backprop.Internal: oneFunc :: Backprop a => OneFunc a
+ Numeric.Backprop.Internal: previewVar :: forall b a s. Reifies s W => AddFunc a -> ZeroFunc b -> Traversal' b a -> BVar s b -> Maybe (BVar s a)
+ Numeric.Backprop.Internal: sequenceVar :: forall t a s. (Reifies s W, Traversable t) => AddFunc a -> ZeroFunc a -> BVar s (t a) -> t (BVar s a)
+ Numeric.Backprop.Internal: setVar :: forall a b s. Reifies s W => AddFunc a -> AddFunc b -> ZeroFunc a -> Lens' b a -> BVar s a -> BVar s b -> BVar s b
+ Numeric.Backprop.Internal: toListOfVar :: forall b a s. Reifies s W => AddFunc a -> ZeroFunc b -> Traversal' b a -> BVar s b -> [BVar s a]
+ Numeric.Backprop.Internal: viewVar :: forall a b s. Reifies s W => AddFunc a -> ZeroFunc b -> Lens' b a -> BVar s b -> BVar s a
+ Numeric.Backprop.Internal: zeroFunc :: Backprop a => ZeroFunc a
+ Numeric.Backprop.Internal: zfNum :: Num a => ZeroFunc a
- Numeric.Backprop: (^^.) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Lens' b a -> BVar s a
+ Numeric.Backprop: (^^.) :: (Backprop b, Backprop a, Reifies s W) => BVar s b -> Lens' b a -> BVar s a
- Numeric.Backprop: (^^..) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> [BVar s a]
+ Numeric.Backprop: (^^..) :: (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> [BVar s a]
- Numeric.Backprop: (^^?!) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> BVar s a
+ Numeric.Backprop: (^^?!) :: (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> BVar s a
- Numeric.Backprop: (^^?) :: forall b a s. (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> Maybe (BVar s a)
+ Numeric.Backprop: (^^?) :: (Backprop b, Backprop a, Reifies s W) => BVar s b -> Traversal' b a -> Maybe (BVar s a)
- Numeric.Backprop: ABP :: f a -> ABP f a
+ Numeric.Backprop: ABP :: f a -> ABP (f :: Type -> Type) a
- Numeric.Backprop: Op :: (Rec Identity as -> (a, a -> Rec Identity as)) -> Op as a
+ Numeric.Backprop: Op :: (Rec Identity as -> (a, a -> Rec Identity as)) -> Op (as :: [Type]) a
- Numeric.Backprop: [runABP] :: ABP f a -> f a
+ Numeric.Backprop: [runABP] :: ABP (f :: Type -> Type) a -> f a
- Numeric.Backprop: [runOpWith] :: Op as a -> Rec Identity as -> (a, a -> Rec Identity as)
+ Numeric.Backprop: [runOpWith] :: Op (as :: [Type]) a -> Rec Identity as -> (a, a -> Rec Identity as)
- Numeric.Backprop: add :: (Backprop a, Generic a, GAdd (Rep a)) => a -> a -> a
+ Numeric.Backprop: add :: Backprop a => a -> a -> a
- Numeric.Backprop: backpropN :: (RPureConstrained Backprop as, Backprop b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, Rec Identity as)
+ Numeric.Backprop: backpropN :: forall (as :: [Type]) b. (RPureConstrained Backprop as, Backprop b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, Rec Identity as)
- Numeric.Backprop: backpropWithN :: RPureConstrained Backprop as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, b -> Rec Identity as)
+ Numeric.Backprop: backpropWithN :: forall (as :: [Type]) b. RPureConstrained Backprop as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, b -> Rec Identity as)
- Numeric.Backprop: bpOp :: RPureConstrained Backprop as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Op as b
+ Numeric.Backprop: bpOp :: forall (as :: [Type]) b. RPureConstrained Backprop as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Op as b
- Numeric.Backprop: class BVGroup s as i o | o -> i, i -> as
+ Numeric.Backprop: class BVGroup s (as :: [Type]) (i :: Type -> Type) (o :: Type -> Type) | o -> i, i -> as
- Numeric.Backprop: evalBPN :: forall as b. () => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> b
+ Numeric.Backprop: evalBPN :: forall (as :: [Type]) b. (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> b
- Numeric.Backprop: gradBPN :: (RPureConstrained Backprop as, Backprop b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> Rec Identity as
+ Numeric.Backprop: gradBPN :: forall (as :: [Type]) b. (RPureConstrained Backprop as, Backprop b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> Rec Identity as
- Numeric.Backprop: isoVarN :: (RPureConstrained Backprop as, Reifies s W) => (Rec Identity as -> b) -> (b -> Rec Identity as) -> Rec (BVar s) as -> BVar s b
+ Numeric.Backprop: isoVarN :: forall (as :: [Type]) s b. (RPureConstrained Backprop as, Reifies s W) => (Rec Identity as -> b) -> (b -> Rec Identity as) -> Rec (BVar s) as -> BVar s b
- Numeric.Backprop: joinBV :: (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (z f), Backprop (Rep (z f) ()), RPureConstrained Backprop as, Reifies s W) => z (BVar s) -> BVar s (z f)
+ Numeric.Backprop: joinBV :: forall z (f :: Type -> Type) s (as :: [Type]). (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (z f), Backprop (Rep (z f) ()), RPureConstrained Backprop as, Reifies s W) => z (BVar s) -> BVar s (z f)
- Numeric.Backprop: liftOp :: (RPureConstrained Backprop as, Reifies s W) => Op as b -> Rec (BVar s) as -> BVar s b
+ Numeric.Backprop: liftOp :: forall (as :: [Type]) s b. (RPureConstrained Backprop as, Reifies s W) => Op as b -> Rec (BVar s) as -> BVar s b
- Numeric.Backprop: newtype ABP f a
+ Numeric.Backprop: newtype ABP (f :: Type -> Type) a
- Numeric.Backprop: newtype Op as a
+ Numeric.Backprop: newtype Op (as :: [Type]) a
- Numeric.Backprop: noGrad :: (Rec Identity as -> b) -> Op as b
+ Numeric.Backprop: noGrad :: forall (as :: [Type]) b. (Rec Identity as -> b) -> Op as b
- Numeric.Backprop: one :: (Backprop a, Generic a, GOne (Rep a)) => a -> a
+ Numeric.Backprop: one :: Backprop a => a -> a
- Numeric.Backprop: op0 :: a -> Op '[] a
+ Numeric.Backprop: op0 :: a -> Op ('[] :: [Type]) a
- Numeric.Backprop: opConst :: forall as a. RPureConstrained Num as => a -> Op as a
+ Numeric.Backprop: opConst :: forall (as :: [Type]) a. RPureConstrained Num as => a -> Op as a
- Numeric.Backprop: opIsoN :: (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b
+ Numeric.Backprop: opIsoN :: forall (as :: [Type]) b. (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b
- Numeric.Backprop: opTup :: Op as (Rec Identity as)
+ Numeric.Backprop: opTup :: forall (as :: [Type]). Op as (Rec Identity as)
- Numeric.Backprop: pattern BV :: (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (Rep (z f) ()), Backprop (z f), RPureConstrained Backprop as, RecApplicative as, Reifies s W) => z (BVar s) -> BVar s (z f)
+ Numeric.Backprop: pattern BV :: forall z (f :: Type -> Type) s (as :: [Type]). (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (Rep (z f) ()), Backprop (z f), RPureConstrained Backprop as, RecApplicative as, Reifies s W) => z (BVar s) -> BVar s (z f)
- Numeric.Backprop: previewVar :: forall b a s. (Backprop b, Backprop a, Reifies s W) => Traversal' b a -> BVar s b -> Maybe (BVar s a)
+ Numeric.Backprop: previewVar :: (Backprop b, Backprop a, Reifies s W) => Traversal' b a -> BVar s b -> Maybe (BVar s a)
- Numeric.Backprop: splitBV :: (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (z f), Backprop (Rep (z f) ()), RPureConstrained Backprop as, Reifies s W) => BVar s (z f) -> z (BVar s)
+ Numeric.Backprop: splitBV :: forall z (f :: Type -> Type) s (as :: [Type]). (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Backprop (z f), Backprop (Rep (z f) ()), RPureConstrained Backprop as, Reifies s W) => BVar s (z f) -> z (BVar s)
- Numeric.Backprop: toListOfVar :: forall b a s. (Backprop b, Backprop a, Reifies s W) => Traversal' b a -> BVar s b -> [BVar s a]
+ Numeric.Backprop: toListOfVar :: (Backprop b, Backprop a, Reifies s W) => Traversal' b a -> BVar s b -> [BVar s a]
- Numeric.Backprop: zero :: (Backprop a, Generic a, GZero (Rep a)) => a -> a
+ Numeric.Backprop: zero :: Backprop a => a -> a
- Numeric.Backprop.Class: ABP :: f a -> ABP f a
+ Numeric.Backprop.Class: ABP :: f a -> ABP (f :: Type -> Type) a
- Numeric.Backprop.Class: NumVec :: v a -> NumVec v a
+ Numeric.Backprop.Class: NumVec :: v a -> NumVec (v :: Type -> Type) a
- Numeric.Backprop.Class: [runABP] :: ABP f a -> f a
+ Numeric.Backprop.Class: [runABP] :: ABP (f :: Type -> Type) a -> f a
- Numeric.Backprop.Class: [runNumVec] :: NumVec v a -> v a
+ Numeric.Backprop.Class: [runNumVec] :: NumVec (v :: Type -> Type) a -> v a
- Numeric.Backprop.Class: add :: (Backprop a, Generic a, GAdd (Rep a)) => a -> a -> a
+ Numeric.Backprop.Class: add :: Backprop a => a -> a -> a
- Numeric.Backprop.Class: class GAdd f
+ Numeric.Backprop.Class: class GAdd (f :: Type -> Type)
- Numeric.Backprop.Class: class GOne f
+ Numeric.Backprop.Class: class GOne (f :: Type -> Type)
- Numeric.Backprop.Class: class GZero f
+ Numeric.Backprop.Class: class GZero (f :: Type -> Type)
- Numeric.Backprop.Class: newtype ABP f a
+ Numeric.Backprop.Class: newtype ABP (f :: Type -> Type) a
- Numeric.Backprop.Class: newtype NumVec v a
+ Numeric.Backprop.Class: newtype NumVec (v :: Type -> Type) a
- Numeric.Backprop.Class: one :: (Backprop a, Generic a, GOne (Rep a)) => a -> a
+ Numeric.Backprop.Class: one :: Backprop a => a -> a
- Numeric.Backprop.Class: zero :: (Backprop a, Generic a, GZero (Rep a)) => a -> a
+ Numeric.Backprop.Class: zero :: Backprop a => a -> a
- Numeric.Backprop.Explicit: ABP :: f a -> ABP f a
+ Numeric.Backprop.Explicit: ABP :: f a -> ABP (f :: Type -> Type) a
- Numeric.Backprop.Explicit: Op :: (Rec Identity as -> (a, a -> Rec Identity as)) -> Op as a
+ Numeric.Backprop.Explicit: Op :: (Rec Identity as -> (a, a -> Rec Identity as)) -> Op (as :: [Type]) a
- Numeric.Backprop.Explicit: [runABP] :: ABP f a -> f a
+ Numeric.Backprop.Explicit: [runABP] :: ABP (f :: Type -> Type) a -> f a
- Numeric.Backprop.Explicit: [runOpWith] :: Op as a -> Rec Identity as -> (a, a -> Rec Identity as)
+ Numeric.Backprop.Explicit: [runOpWith] :: Op (as :: [Type]) a -> Rec Identity as -> (a, a -> Rec Identity as)
- Numeric.Backprop.Explicit: add :: (Backprop a, Generic a, GAdd (Rep a)) => a -> a -> a
+ Numeric.Backprop.Explicit: add :: Backprop a => a -> a -> a
- Numeric.Backprop.Explicit: addFuncs :: RPureConstrained Backprop as => Rec AddFunc as
+ Numeric.Backprop.Explicit: addFuncs :: forall (as :: [Type]). RPureConstrained Backprop as => Rec AddFunc as
- Numeric.Backprop.Explicit: afNums :: RPureConstrained Num as => Rec AddFunc as
+ Numeric.Backprop.Explicit: afNums :: forall (as :: [Type]). RPureConstrained Num as => Rec AddFunc as
- Numeric.Backprop.Explicit: backpropN :: forall as b. () => Rec ZeroFunc as -> OneFunc b -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, Rec Identity as)
+ Numeric.Backprop.Explicit: backpropN :: forall (as :: [Type]) b. Rec ZeroFunc as -> OneFunc b -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, Rec Identity as)
- Numeric.Backprop.Explicit: backpropWithN :: forall as b. () => Rec ZeroFunc as -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, b -> Rec Identity as)
+ Numeric.Backprop.Explicit: backpropWithN :: forall (as :: [Type]) b. Rec ZeroFunc as -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, b -> Rec Identity as)
- Numeric.Backprop.Explicit: bpOp :: Rec ZeroFunc as -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Op as b
+ Numeric.Backprop.Explicit: bpOp :: forall (as :: [Type]) b. Rec ZeroFunc as -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Op as b
- Numeric.Backprop.Explicit: class BVGroup s as i o | o -> i, i -> as
+ Numeric.Backprop.Explicit: class BVGroup s (as :: [Type]) (i :: Type -> Type) (o :: Type -> Type) | o -> i, i -> as
- Numeric.Backprop.Explicit: evalBPN :: forall as b. () => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> b
+ Numeric.Backprop.Explicit: evalBPN :: forall (as :: [Type]) b. (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> b
- Numeric.Backprop.Explicit: gradBPN :: Rec ZeroFunc as -> OneFunc b -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> Rec Identity as
+ Numeric.Backprop.Explicit: gradBPN :: forall (as :: [Type]) b. Rec ZeroFunc as -> OneFunc b -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> Rec Identity as
- Numeric.Backprop.Explicit: isoVarN :: Reifies s W => Rec AddFunc as -> (Rec Identity as -> b) -> (b -> Rec Identity as) -> Rec (BVar s) as -> BVar s b
+ Numeric.Backprop.Explicit: isoVarN :: forall s (as :: [Type]) b. Reifies s W => Rec AddFunc as -> (Rec Identity as -> b) -> (b -> Rec Identity as) -> Rec (BVar s) as -> BVar s b
- Numeric.Backprop.Explicit: joinBV :: forall z f s as. (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Reifies s W) => AddFunc (z f) -> Rec AddFunc as -> ZeroFunc (Rep (z f) ()) -> Rec ZeroFunc as -> z (BVar s) -> BVar s (z f)
+ Numeric.Backprop.Explicit: joinBV :: forall z (f :: Type -> Type) s (as :: [Type]). (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Reifies s W) => AddFunc (z f) -> Rec AddFunc as -> ZeroFunc (Rep (z f) ()) -> Rec ZeroFunc as -> z (BVar s) -> BVar s (z f)
- Numeric.Backprop.Explicit: liftOp :: forall as b s. Reifies s W => Rec AddFunc as -> Op as b -> Rec (BVar s) as -> BVar s b
+ Numeric.Backprop.Explicit: liftOp :: forall (as :: [Type]) b s. Reifies s W => Rec AddFunc as -> Op as b -> Rec (BVar s) as -> BVar s b
- Numeric.Backprop.Explicit: newtype ABP f a
+ Numeric.Backprop.Explicit: newtype ABP (f :: Type -> Type) a
- Numeric.Backprop.Explicit: newtype Op as a
+ Numeric.Backprop.Explicit: newtype Op (as :: [Type]) a
- Numeric.Backprop.Explicit: noGrad :: (Rec Identity as -> b) -> Op as b
+ Numeric.Backprop.Explicit: noGrad :: forall (as :: [Type]) b. (Rec Identity as -> b) -> Op as b
- Numeric.Backprop.Explicit: ofNums :: RPureConstrained Num as => Rec OneFunc as
+ Numeric.Backprop.Explicit: ofNums :: forall (as :: [Type]). RPureConstrained Num as => Rec OneFunc as
- Numeric.Backprop.Explicit: one :: (Backprop a, Generic a, GOne (Rep a)) => a -> a
+ Numeric.Backprop.Explicit: one :: Backprop a => a -> a
- Numeric.Backprop.Explicit: oneFuncs :: RPureConstrained Backprop as => Rec OneFunc as
+ Numeric.Backprop.Explicit: oneFuncs :: forall (as :: [Type]). RPureConstrained Backprop as => Rec OneFunc as
- Numeric.Backprop.Explicit: op0 :: a -> Op '[] a
+ Numeric.Backprop.Explicit: op0 :: a -> Op ('[] :: [Type]) a
- Numeric.Backprop.Explicit: opConst :: forall as a. RPureConstrained Num as => a -> Op as a
+ Numeric.Backprop.Explicit: opConst :: forall (as :: [Type]) a. RPureConstrained Num as => a -> Op as a
- Numeric.Backprop.Explicit: opIsoN :: (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b
+ Numeric.Backprop.Explicit: opIsoN :: forall (as :: [Type]) b. (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b
- Numeric.Backprop.Explicit: opTup :: Op as (Rec Identity as)
+ Numeric.Backprop.Explicit: opTup :: forall (as :: [Type]). Op as (Rec Identity as)
- Numeric.Backprop.Explicit: splitBV :: forall z f s as. (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Reifies s W) => AddFunc (Rep (z f) ()) -> Rec AddFunc as -> ZeroFunc (z f) -> Rec ZeroFunc as -> BVar s (z f) -> z (BVar s)
+ Numeric.Backprop.Explicit: splitBV :: forall z (f :: Type -> Type) s (as :: [Type]). (Generic (z f), Generic (z (BVar s)), BVGroup s as (Rep (z f)) (Rep (z (BVar s))), Reifies s W) => AddFunc (Rep (z f) ()) -> Rec AddFunc as -> ZeroFunc (z f) -> Rec ZeroFunc as -> BVar s (z f) -> z (BVar s)
- Numeric.Backprop.Explicit: zero :: (Backprop a, Generic a, GZero (Rep a)) => a -> a
+ Numeric.Backprop.Explicit: zero :: Backprop a => a -> a
- Numeric.Backprop.Explicit: zeroFuncs :: RPureConstrained Backprop as => Rec ZeroFunc as
+ Numeric.Backprop.Explicit: zeroFuncs :: forall (as :: [Type]). RPureConstrained Backprop as => Rec ZeroFunc as
- Numeric.Backprop.Explicit: zfNums :: RPureConstrained Num as => Rec ZeroFunc as
+ Numeric.Backprop.Explicit: zfNums :: forall (as :: [Type]). RPureConstrained Num as => Rec ZeroFunc as
- Numeric.Backprop.Num: (^^..) :: forall b a s. (Num b, Num a, Reifies s W) => BVar s b -> Traversal' b a -> [BVar s a]
+ Numeric.Backprop.Num: (^^..) :: (Num b, Num a, Reifies s W) => BVar s b -> Traversal' b a -> [BVar s a]
- Numeric.Backprop.Num: (^^?!) :: forall b a s. (Num b, Num a, Reifies s W) => BVar s b -> Traversal' b a -> BVar s a
+ Numeric.Backprop.Num: (^^?!) :: (Num b, Num a, Reifies s W) => BVar s b -> Traversal' b a -> BVar s a
- Numeric.Backprop.Num: (^^?) :: forall b a s. (Num b, Num a, Reifies s W) => BVar s b -> Traversal' b a -> Maybe (BVar s a)
+ Numeric.Backprop.Num: (^^?) :: (Num b, Num a, Reifies s W) => BVar s b -> Traversal' b a -> Maybe (BVar s a)
- Numeric.Backprop.Num: Op :: (Rec Identity as -> (a, a -> Rec Identity as)) -> Op as a
+ Numeric.Backprop.Num: Op :: (Rec Identity as -> (a, a -> Rec Identity as)) -> Op (as :: [Type]) a
- Numeric.Backprop.Num: [runOpWith] :: Op as a -> Rec Identity as -> (a, a -> Rec Identity as)
+ Numeric.Backprop.Num: [runOpWith] :: Op (as :: [Type]) a -> Rec Identity as -> (a, a -> Rec Identity as)
- Numeric.Backprop.Num: backpropN :: (RPureConstrained Num as, Num b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, Rec Identity as)
+ Numeric.Backprop.Num: backpropN :: forall (as :: [Type]) b. (RPureConstrained Num as, Num b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, Rec Identity as)
- Numeric.Backprop.Num: backpropWithN :: RPureConstrained Num as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, b -> Rec Identity as)
+ Numeric.Backprop.Num: backpropWithN :: forall (as :: [Type]) b. RPureConstrained Num as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> (b, b -> Rec Identity as)
- Numeric.Backprop.Num: bpOp :: RPureConstrained Num as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Op as b
+ Numeric.Backprop.Num: bpOp :: forall (as :: [Type]) b. RPureConstrained Num as => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Op as b
- Numeric.Backprop.Num: evalBPN :: forall as b. () => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> b
+ Numeric.Backprop.Num: evalBPN :: forall (as :: [Type]) b. (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> b
- Numeric.Backprop.Num: gradBPN :: (RPureConstrained Num as, Num b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> Rec Identity as
+ Numeric.Backprop.Num: gradBPN :: forall (as :: [Type]) b. (RPureConstrained Num as, Num b) => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) -> Rec Identity as -> Rec Identity as
- Numeric.Backprop.Num: isoVarN :: (RPureConstrained Num as, Reifies s W) => (Rec Identity as -> b) -> (b -> Rec Identity as) -> Rec (BVar s) as -> BVar s b
+ Numeric.Backprop.Num: isoVarN :: forall (as :: [Type]) s b. (RPureConstrained Num as, Reifies s W) => (Rec Identity as -> b) -> (b -> Rec Identity as) -> Rec (BVar s) as -> BVar s b
- Numeric.Backprop.Num: liftOp :: (RPureConstrained Num as, Reifies s W) => Op as b -> Rec (BVar s) as -> BVar s b
+ Numeric.Backprop.Num: liftOp :: forall (as :: [Type]) s b. (RPureConstrained Num as, Reifies s W) => Op as b -> Rec (BVar s) as -> BVar s b
- Numeric.Backprop.Num: newtype Op as a
+ Numeric.Backprop.Num: newtype Op (as :: [Type]) a
- Numeric.Backprop.Num: noGrad :: (Rec Identity as -> b) -> Op as b
+ Numeric.Backprop.Num: noGrad :: forall (as :: [Type]) b. (Rec Identity as -> b) -> Op as b
- Numeric.Backprop.Num: op0 :: a -> Op '[] a
+ Numeric.Backprop.Num: op0 :: a -> Op ('[] :: [Type]) a
- Numeric.Backprop.Num: opConst :: forall as a. RPureConstrained Num as => a -> Op as a
+ Numeric.Backprop.Num: opConst :: forall (as :: [Type]) a. RPureConstrained Num as => a -> Op as a
- Numeric.Backprop.Num: opIsoN :: (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b
+ Numeric.Backprop.Num: opIsoN :: forall (as :: [Type]) b. (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b
- Numeric.Backprop.Num: opTup :: Op as (Rec Identity as)
+ Numeric.Backprop.Num: opTup :: forall (as :: [Type]). Op as (Rec Identity as)
- Numeric.Backprop.Num: previewVar :: forall b a s. (Num b, Num a, Reifies s W) => Traversal' b a -> BVar s b -> Maybe (BVar s a)
+ Numeric.Backprop.Num: previewVar :: (Num b, Num a, Reifies s W) => Traversal' b a -> BVar s b -> Maybe (BVar s a)
- Numeric.Backprop.Num: setVar :: forall a b s. (Num a, Num b, Reifies s W) => Lens' b a -> BVar s a -> BVar s b -> BVar s b
+ Numeric.Backprop.Num: setVar :: (Num a, Num b, Reifies s W) => Lens' b a -> BVar s a -> BVar s b -> BVar s b
- Numeric.Backprop.Num: toListOfVar :: forall b a s. (Num b, Num a, Reifies s W) => Traversal' b a -> BVar s b -> [BVar s a]
+ Numeric.Backprop.Num: toListOfVar :: (Num b, Num a, Reifies s W) => Traversal' b a -> BVar s b -> [BVar s a]
- Numeric.Backprop.Op: (~.) :: RPureConstrained Num as => Op '[b] c -> Op as b -> Op as c
+ Numeric.Backprop.Op: (~.) :: forall (as :: [Type]) b c. RPureConstrained Num as => Op '[b] c -> Op as b -> Op as c
- Numeric.Backprop.Op: Op :: (Rec Identity as -> (a, a -> Rec Identity as)) -> Op as a
+ Numeric.Backprop.Op: Op :: (Rec Identity as -> (a, a -> Rec Identity as)) -> Op (as :: [Type]) a
- Numeric.Backprop.Op: [:&] :: forall {u} (a :: u -> Type) (r :: u) (rs :: [u]). !a r -> !Rec a rs -> Rec a (r : rs)
+ Numeric.Backprop.Op: [:&] :: forall {u} (a :: u -> Type) (r :: u) (rs :: [u]). !a r -> !Rec a rs -> Rec a (r ': rs)
- Numeric.Backprop.Op: [runOpWith] :: Op as a -> Rec Identity as -> (a, a -> Rec Identity as)
+ Numeric.Backprop.Op: [runOpWith] :: Op (as :: [Type]) a -> Rec Identity as -> (a, a -> Rec Identity as)
- Numeric.Backprop.Op: composeOp :: forall as bs c. RPureConstrained Num as => Rec (Op as) bs -> Op bs c -> Op as c
+ Numeric.Backprop.Op: composeOp :: forall (as :: [Type]) (bs :: [Type]) c. RPureConstrained Num as => Rec (Op as) bs -> Op bs c -> Op as c
- Numeric.Backprop.Op: composeOp1 :: RPureConstrained Num as => Op as b -> Op '[b] c -> Op as c
+ Numeric.Backprop.Op: composeOp1 :: forall (as :: [Type]) b c. RPureConstrained Num as => Op as b -> Op '[b] c -> Op as c
- Numeric.Backprop.Op: evalOp :: Op as a -> Rec Identity as -> a
+ Numeric.Backprop.Op: evalOp :: forall (as :: [Type]) a. Op as a -> Rec Identity as -> a
- Numeric.Backprop.Op: gradOp :: Num a => Op as a -> Rec Identity as -> Rec Identity as
+ Numeric.Backprop.Op: gradOp :: forall a (as :: [Type]). Num a => Op as a -> Rec Identity as -> Rec Identity as
- Numeric.Backprop.Op: gradOpWith :: Op as a -> Rec Identity as -> a -> Rec Identity as
+ Numeric.Backprop.Op: gradOpWith :: forall (as :: [Type]) a. Op as a -> Rec Identity as -> a -> Rec Identity as
- Numeric.Backprop.Op: newtype Op as a
+ Numeric.Backprop.Op: newtype Op (as :: [Type]) a
- Numeric.Backprop.Op: noGrad :: (Rec Identity as -> b) -> Op as b
+ Numeric.Backprop.Op: noGrad :: forall (as :: [Type]) b. (Rec Identity as -> b) -> Op as b
- Numeric.Backprop.Op: op0 :: a -> Op '[] a
+ Numeric.Backprop.Op: op0 :: a -> Op ('[] :: [Type]) a
- Numeric.Backprop.Op: opConst :: forall as a. RPureConstrained Num as => a -> Op as a
+ Numeric.Backprop.Op: opConst :: forall (as :: [Type]) a. RPureConstrained Num as => a -> Op as a
- Numeric.Backprop.Op: opIsoN :: (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b
+ Numeric.Backprop.Op: opIsoN :: forall (as :: [Type]) b. (Rec Identity as -> b) -> (b -> Rec Identity as) -> Op as b
- Numeric.Backprop.Op: opTup :: Op as (Rec Identity as)
+ Numeric.Backprop.Op: opTup :: forall (as :: [Type]). Op as (Rec Identity as)
- Numeric.Backprop.Op: runOp :: Num a => Op as a -> Rec Identity as -> (a, Rec Identity as)
+ Numeric.Backprop.Op: runOp :: forall a (as :: [Type]). Num a => Op as a -> Rec Identity as -> (a, Rec Identity as)
Files
- Build.hs +156/−138
- CHANGELOG.md +9/−0
- README.md +1/−1
- Setup.hs +1/−0
- backprop.cabal +77/−79
- bench/bench.hs +348/−331
- src/Data/Type/Util.hs +92/−84
- src/Numeric/Backprop.hs +336/−277
- src/Numeric/Backprop/Class.hs +1146/−1074
- src/Numeric/Backprop/Explicit.hs +392/−301
- src/Numeric/Backprop/Internal.hs +973/−872
- src/Numeric/Backprop/Num.hs +273/−218
- src/Numeric/Backprop/Op.hs +259/−201
- src/Prelude/Backprop.hs +192/−151
- src/Prelude/Backprop/Explicit.hs +256/−237
- src/Prelude/Backprop/Num.hs +178/−148
Build.hs view
@@ -1,164 +1,182 @@ #!/usr/bin/env stack -- stack --install-ghc runghc --package shake-0.16.4 --stack-yaml stack.yaml -import Development.Shake-import Development.Shake.FilePath-import System.Directory+import Development.Shake+import Development.Shake.FilePath+import System.Directory -opts = shakeOptions { shakeFiles = ".shake"- , shakeVersion = "1.0"- , shakeVerbosity = Normal- , shakeThreads = 1- }+opts =+ shakeOptions+ { shakeFiles = ".shake"+ , shakeVersion = "1.0"+ , shakeVerbosity = Normal+ , shakeThreads = 1+ } data Doc = Lab main :: IO ()-main = getDirectoryFilesIO "samples" ["/*.lhs", "/*.hs"] >>= \allSamps ->- getDirectoryFilesIO "src" ["//*.hs"] >>= \allSrc ->- shakeArgs opts $ do-- want ["all"]-- "all" ~>- need ["pdf", "md", "gentags", "install", "exe"]+main =+ getDirectoryFilesIO "samples" ["/*.lhs", "/*.hs"] >>= \allSamps ->+ getDirectoryFilesIO "src" ["//*.hs"] >>= \allSrc ->+ shakeArgs opts $ do+ want ["all"] - "pdf" ~>- need [ "renders" </> takeFileName f -<.> ".pdf"- | f <- allSamps, takeExtension f == ".lhs"- ]+ "all"+ ~> need ["pdf", "md", "gentags", "install", "exe"] - "md" ~>- need [ "renders" </> takeFileName f -<.> ".md"- | f <- allSamps, takeExtension f == ".lhs"- ]+ "pdf"+ ~> need+ [ "renders" </> takeFileName f -<.> ".pdf"+ | f <- allSamps+ , takeExtension f == ".lhs"+ ] - "exe" ~>- need (map (\f -> "samples-exe" </> dropExtension f) allSamps)+ "md"+ ~> need+ [ "renders" </> takeFileName f -<.> ".md"+ | f <- allSamps+ , takeExtension f == ".lhs"+ ] - "haddocks" ~> do- need $ ("src" </>) <$> allSrc- cmd "jle-git-haddocks"+ "exe"+ ~> need (map (\f -> "samples-exe" </> dropExtension f) allSamps) - "install" ~> do- need $ ("src" </>) <$> allSrc- cmd "stack install"+ "haddocks" ~> do+ need $ ("src" </>) <$> allSrc+ cmd "jle-git-haddocks" - "install-profile" ~> do- need $ ("src" </>) <$> allSrc- cmd "stack install --profile"+ "install" ~> do+ need $ ("src" </>) <$> allSrc+ cmd "stack install" - "gentags" ~>- need ["tags", "TAGS"]+ "install-profile" ~> do+ need $ ("src" </>) <$> allSrc+ cmd "stack install --profile" - ["renders/*.pdf", "renders/*.md"] |%> \f -> do- let src = "samples" </> takeFileName f -<.> "lhs"- need [src]- liftIO $ createDirectoryIfMissing True "renders"- cmd "pandoc"- "-V geometry:margin=1in"- "-V fontfamily:palatino,cmtt"- "-V links-as-notes"- "-s"- "--highlight-style tango"- "--reference-links"- "--reference-location block"- "-o" f- src+ "gentags"+ ~> need ["tags", "TAGS"] - "samples-exe/*" %> \f -> do- need ["install"]- [src] <- getDirectoryFiles "samples" $ (takeFileName f <.>) <$> ["hs","lhs"]- liftIO $ do- createDirectoryIfMissing True "samples-exe"- createDirectoryIfMissing True ".build"- removeFilesAfter "samples" ["/*.o"]- cmd "stack ghc"- "--stack-yaml stack.yaml"- "--package finite-typelits"- "--package hmatrix-backprop"- "--package hmatrix-vector-sized"- "--package microlens-th"- "--package mnist-idx"- "--package mwc-random"- "--package one-liner"- "--package one-liner-instances"- "--package random"- "--package singletons"- "--package split"- "--package vector-sized"- "--"- ("samples" </> src)- "-o" f- "-hidir .build"- "-Wall"- "-O2"+ ["renders/*.pdf", "renders/*.md"] |%> \f -> do+ let src = "samples" </> takeFileName f -<.> "lhs"+ need [src]+ liftIO $ createDirectoryIfMissing True "renders"+ cmd+ "pandoc"+ "-V geometry:margin=1in"+ "-V fontfamily:palatino,cmtt"+ "-V links-as-notes"+ "-s"+ "--highlight-style tango"+ "--reference-links"+ "--reference-location block"+ "-o"+ f+ src - "profile" ~> do- need $ do- s <- ["manual","bp-lens","bp-hkd","hybrid"]- e <- ["prof.html","svg"]- return $ "bench-prof/bench-" ++ s <.> e+ "samples-exe/*" %> \f -> do+ need ["install"]+ [src] <- getDirectoryFiles "samples" $ (takeFileName f <.>) <$> ["hs", "lhs"]+ liftIO $ do+ createDirectoryIfMissing True "samples-exe"+ createDirectoryIfMissing True ".build"+ removeFilesAfter "samples" ["/*.o"]+ cmd+ "stack ghc"+ "--stack-yaml stack.yaml"+ "--package finite-typelits"+ "--package hmatrix-backprop"+ "--package hmatrix-vector-sized"+ "--package microlens-th"+ "--package mnist-idx"+ "--package mwc-random"+ "--package one-liner"+ "--package one-liner-instances"+ "--package random"+ "--package singletons"+ "--package split"+ "--package vector-sized"+ "--"+ ("samples" </> src)+ "-o"+ f+ "-hidir .build"+ "-Wall"+ "-O2" - "bench-prof/bench" %> \f -> do- let src = "bench" </> takeFileName f <.> ".hs"- need ["install-profile", src]- unit $ cmd "stack install"- "--profile"- "--stack-yaml stack.yaml"- [ "lens"- , "hmatrix"- , "one-liner-instances"- , "split"- , "criterion"- ]- unit $ cmd "stack ghc"- "--profile"- "--stack-yaml stack.yaml"- src- "--"- "-o" f- "-hidir .build"- "-O2"- "-prof"- "-fexternal-interpreter"+ "profile" ~> do+ need $ do+ s <- ["manual", "bp-lens", "bp-hkd", "hybrid"]+ e <- ["prof.html", "svg"]+ return $ "bench-prof/bench-" ++ s <.> e - "bench-prof/bench-*.prof" %> \f -> do- need ["bench-prof/bench"]- let b = drop 6 $ takeBaseName f- unit $ cmd "./bench-prof/bench"- ("gradient/" ++ b)- "+RTS"- "-p"- cmd "mv" "bench.prof" f+ "bench-prof/bench" %> \f -> do+ let src = "bench" </> takeFileName f <.> ".hs"+ need ["install-profile", src]+ unit $+ cmd+ "stack install"+ "--profile"+ "--stack-yaml stack.yaml"+ [ "lens"+ , "hmatrix"+ , "one-liner-instances"+ , "split"+ , "criterion"+ ]+ unit $+ cmd+ "stack ghc"+ "--profile"+ "--stack-yaml stack.yaml"+ src+ "--"+ "-o"+ f+ "-hidir .build"+ "-O2"+ "-prof"+ "-fexternal-interpreter" - "**/*.prof.html" %> \f -> do- let src = f -<.> ""- need [src]- cmd "profiteur" src+ "bench-prof/bench-*.prof" %> \f -> do+ need ["bench-prof/bench"]+ let b = drop 6 $ takeBaseName f+ unit $+ cmd+ "./bench-prof/bench"+ ("gradient/" ++ b)+ "+RTS"+ "-p"+ cmd "mv" "bench.prof" f - "**/*.prof.folded" %> \f -> do- let src = f -<.> ""- need [src]- Stdout out <- cmd "cat" [src]- cmd (Stdin out)- (FileStdout f)- "ghc-prof-flamegraph"+ "**/*.prof.html" %> \f -> do+ let src = f -<.> ""+ need [src]+ cmd "profiteur" src - "bench-prof/*.svg" %> \f -> do- let src = f -<.> "prof.folded"- need [src]- cmd (FileStdout f)- "flamegraph.pl"- "--width 2000"- src+ "**/*.prof.folded" %> \f -> do+ let src = f -<.> ""+ need [src]+ Stdout out <- cmd "cat" [src]+ cmd+ (Stdin out)+ (FileStdout f)+ "ghc-prof-flamegraph" - ["tags","TAGS"] &%> \_ -> do- need (("src" </>) <$> allSrc)- cmd "hasktags" "src/"+ "bench-prof/*.svg" %> \f -> do+ let src = f -<.> "prof.folded"+ need [src]+ cmd+ (FileStdout f)+ "flamegraph.pl"+ "--width 2000"+ src - "clean" ~> do- unit $ cmd "stack clean"- removeFilesAfter ".shake" ["//*"]- removeFilesAfter ".build" ["//*"]+ ["tags", "TAGS"] &%> \_ -> do+ need (("src" </>) <$> allSrc)+ cmd "hasktags" "src/" + "clean" ~> do+ unit $ cmd "stack clean"+ removeFilesAfter ".shake" ["//*"]+ removeFilesAfter ".build" ["//*"]
CHANGELOG.md view
@@ -1,6 +1,15 @@ Changelog ========= +Version 0.2.7.0+---------------++*June 3, 2025*++<https://github.com/mstksg/backprop/releases/tag/v0.2.7.0>++* Export `Numeric.Backprop.Internal`.+ Version 0.2.6.5 ---------------
README.md view
@@ -235,7 +235,7 @@ 3. There is a link between *backprop* and deep learning/neural network libraries like *[tensorflow][]*, *[caffe][]*, and *[theano][]*, which all- all support some form of heterogeneous automatic differentiation. Haskell+ support some form of heterogeneous automatic differentiation. Haskell libraries doing similar things include *[grenade][]*. These are all frameworks for working with neural networks or other
Setup.hs view
@@ -1,2 +1,3 @@ import Distribution.Simple+ main = defaultMain
backprop.cabal view
@@ -1,113 +1,111 @@-cabal-version: 1.12---- This file has been generated from package.yaml by hpack version 0.35.2.------ see: https://github.com/sol/hpack------ hash: b1229ff8088fce05c68ad20c4c853349f1b30d0f9e19aa5b2c594a833b05790a+cabal-version: 1.12+name: backprop+version: 0.2.7.0+synopsis: Heterogeneous automatic differentation+description:+ Write your functions to compute your result, and the library will+ automatically generate functions to compute your gradient.+ .+ Implements heterogeneous reverse-mode automatic differentiation, commonly+ known as "backpropagation".+ .+ See <https://backprop.jle.im> for official introduction and documentation. -name: backprop-version: 0.2.6.5-synopsis: Heterogeneous automatic differentation-description: Write your functions to compute your result, and the library will- automatically generate functions to compute your gradient.- .- Implements heterogeneous reverse-mode automatic differentiation, commonly- known as "backpropagation".- .- See <https://backprop.jle.im> for official introduction and documentation.-category: Math-homepage: https://backprop.jle.im-bug-reports: https://github.com/mstksg/backprop/issues-author: Justin Le-maintainer: justin@jle.im-copyright: (c) Justin Le 2018-license: BSD3-license-file: LICENSE-tested-with:- GHC >= 8.4-build-type: Simple+category: Math+homepage: https://backprop.jle.im+bug-reports: https://github.com/mstksg/backprop/issues+author: Justin Le+maintainer: justin@jle.im+copyright: (c) Justin Le 2018+license: BSD3+license-file: LICENSE+build-type: Simple+tested-with: GHC >=8.4 extra-source-files:- README.md- CHANGELOG.md- Build.hs- samples/backprop-mnist.lhs- samples/extensible-neural.lhs- renders/backprop-mnist.pdf- renders/extensible-neural.pdf- renders/backprop-mnist.md- renders/extensible-neural.md- doc/01-getting-started.md- doc/02-a-detailed-look.md- doc/03-manipulating-bvars.md- doc/04-the-backprop-typeclass.md- doc/05-applications.md- doc/06-manual-gradients.md- doc/07-performance.md- doc/08-equipping-your-library.md- doc/09-comparisons.md- doc/index.md+ Build.hs+ CHANGELOG.md+ doc/01-getting-started.md+ doc/02-a-detailed-look.md+ doc/03-manipulating-bvars.md+ doc/04-the-backprop-typeclass.md+ doc/05-applications.md+ doc/06-manual-gradients.md+ doc/07-performance.md+ doc/08-equipping-your-library.md+ doc/09-comparisons.md+ doc/index.md+ README.md+ renders/backprop-mnist.md+ renders/backprop-mnist.pdf+ renders/extensible-neural.md+ renders/extensible-neural.pdf+ samples/backprop-mnist.lhs+ samples/extensible-neural.lhs source-repository head- type: git+ type: git location: https://github.com/mstksg/backprop flag vinyl_0_14- manual: False+ manual: False default: True library exposed-modules:- Numeric.Backprop- Numeric.Backprop.Class- Numeric.Backprop.Explicit- Numeric.Backprop.Num- Numeric.Backprop.Op- Prelude.Backprop- Prelude.Backprop.Explicit- Prelude.Backprop.Num- other-modules:- Numeric.Backprop.Internal- Data.Type.Util- hs-source-dirs:- src- ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints+ Numeric.Backprop+ Numeric.Backprop.Class+ Numeric.Backprop.Explicit+ Numeric.Backprop.Internal+ Numeric.Backprop.Num+ Numeric.Backprop.Op+ Prelude.Backprop+ Prelude.Backprop.Explicit+ Prelude.Backprop.Num++ other-modules: Data.Type.Util+ hs-source-dirs: src+ ghc-options:+ -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints+ -Wunused-packages+ build-depends:- base >=4.7 && <5+ base >=4.7 && <5 , containers , deepseq , microlens- , primitive , reflection , transformers , vector- , vinyl >=0.9.1+ , vinyl >=0.9.1+ default-language: Haskell2010+ if flag(vinyl_0_14)- build-depends:- vinyl >=0.14.2+ build-depends: vinyl >=0.14.2+ else- build-depends:- vinyl <0.14+ build-depends: vinyl <0.14 benchmark backprop-mnist-bench- type: exitcode-stdio-1.0- main-is: bench.hs- other-modules:- Paths_backprop- hs-source-dirs:- bench- ghc-options: -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints -threaded -rtsopts -with-rtsopts=-N -O2+ type: exitcode-stdio-1.0+ main-is: bench.hs+ other-modules: Paths_backprop+ hs-source-dirs: bench+ ghc-options:+ -Wall -Wcompat -Wincomplete-record-updates -Wredundant-constraints+ -threaded -rtsopts -with-rtsopts=-N -O2 -Wunused-packages+ build-depends: backprop- , base >=4.7 && <5+ , base >=4.7 && <5 , criterion , deepseq , directory- , hmatrix >=0.18+ , hmatrix >=0.18 , microlens , microlens-th , mwc-random , time , vector+ default-language: Haskell2010
bench/bench.hs view
@@ -1,46 +1,46 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -import Control.DeepSeq-import Criterion.Main-import Criterion.Types-import Data.Char-import Data.Functor.Identity-import Data.Time-import GHC.Generics (Generic)-import GHC.TypeLits-import Lens.Micro-import Lens.Micro.TH-import Numeric.Backprop-import Numeric.Backprop.Class-import Numeric.LinearAlgebra.Static-import System.Directory-import qualified Data.Vector as V-import qualified Numeric.LinearAlgebra as HM-import qualified System.Random.MWC as MWC+import Control.DeepSeq+import Criterion.Main+import Criterion.Types+import Data.Char+import Data.Functor.Identity+import Data.Time+import qualified Data.Vector as V+import GHC.Generics (Generic)+import GHC.TypeLits+import Lens.Micro+import Lens.Micro.TH+import Numeric.Backprop+import Numeric.Backprop.Class+import qualified Numeric.LinearAlgebra as HM+import Numeric.LinearAlgebra.Static+import System.Directory+import qualified System.Random.MWC as MWC type family HKD f a where- HKD Identity a = a- HKD f a = f a+ HKD Identity a = a+ HKD f a = f a -data Layer' i o f =- Layer { _lWeights :: !(HKD f (L o i))- , _lBiases :: !(HKD f (R o))- }+data Layer' i o f+ = Layer+ { _lWeights :: !(HKD f (L o i))+ , _lBiases :: !(HKD f (R o))+ } deriving (Generic) type Layer i o = Layer' i o Identity@@ -50,11 +50,12 @@ makeLenses ''Layer' -data Network' i h1 h2 o f =- Net { _nLayer1 :: !(HKD f (Layer i h1))- , _nLayer2 :: !(HKD f (Layer h1 h2))- , _nLayer3 :: !(HKD f (Layer h2 o ))- }+data Network' i h1 h2 o f+ = Net+ { _nLayer1 :: !(HKD f (Layer i h1))+ , _nLayer2 :: !(HKD f (Layer h1 h2))+ , _nLayer3 :: !(HKD f (Layer h2 o))+ } deriving (Generic) type Network i h1 h2 o = Network' i h1 h2 o Identity@@ -66,60 +67,65 @@ main :: IO () main = do- g <- MWC.initialize- . V.fromList- . map (fromIntegral . ord)- $ "hello world"- test0 <- MWC.uniformR @(R 784, R 10) ((0,0),(1,1)) g- net0 <- MWC.uniformR @(Network 784 300 100 10) (-0.5, 0.5) g- t <- getZonedTime- let tstr = formatTime defaultTimeLocale "%Y%m%d-%H%M%S" t- createDirectoryIfMissing True "bench-results"- defaultMainWith defaultConfig- { reportFile = Just $ "bench-results/mnist-bench_" ++ tstr ++ ".html"- , timeLimit = 10- } [- bgroup "gradient"- [ let runTest x y = gradNetManual x y net0- in bench "manual" $ nf (uncurry runTest) test0- , let runTest x y = gradBP (netErr x y) net0- in bench "bp-lens" $ nf (uncurry runTest) test0- , let runTest x y = gradBP (netErrHKD x y) net0- in bench "bp-hkd" $ nf (uncurry runTest) test0- , let runTest x y = gradBP (\n' -> netErrHybrid n' y x) net0- in bench "hybrid" $ nf (uncurry runTest) test0- ]- , bgroup "descent"- [ let runTest x y = trainStepManual 0.02 x y net0- in bench "manual" $ nf (uncurry runTest) test0- , let runTest x y = trainStep 0.02 x y net0- in bench "bp-lens" $ nf (uncurry runTest) test0- , let runTest x y = trainStepHKD 0.02 x y net0- in bench "bp-hkd" $ nf (uncurry runTest) test0- , let runTest x y = trainStepHybrid 0.02 x y net0- in bench "hybrid" $ nf (uncurry runTest) test0- ]- , bgroup "run"- [ let runTest = runNetManual net0- in bench "manual" $ nf runTest (fst test0)- , let runTest x = evalBP (`runNetwork` x) net0- in bench "bp-lens" $ nf runTest (fst test0)- , let runTest x = evalBP (`runNetworkHKD` x) net0- in bench "bp-hkd" $ nf runTest (fst test0)- , let runTest x = evalBP (`runNetHybrid` x) net0- in bench "hybrid" $ nf runTest (fst test0)- ]- ]+ g <-+ MWC.initialize+ . V.fromList+ . map (fromIntegral . ord)+ $ "hello world"+ test0 <- MWC.uniformR @(R 784, R 10) ((0, 0), (1, 1)) g+ net0 <- MWC.uniformR @(Network 784 300 100 10) (-0.5, 0.5) g+ t <- getZonedTime+ let tstr = formatTime defaultTimeLocale "%Y%m%d-%H%M%S" t+ createDirectoryIfMissing True "bench-results"+ defaultMainWith+ defaultConfig+ { reportFile = Just $ "bench-results/mnist-bench_" ++ tstr ++ ".html"+ , timeLimit = 10+ }+ [ bgroup+ "gradient"+ [ let runTest x y = gradNetManual x y net0+ in bench "manual" $ nf (uncurry runTest) test0+ , let runTest x y = gradBP (netErr x y) net0+ in bench "bp-lens" $ nf (uncurry runTest) test0+ , let runTest x y = gradBP (netErrHKD x y) net0+ in bench "bp-hkd" $ nf (uncurry runTest) test0+ , let runTest x y = gradBP (\n' -> netErrHybrid n' y x) net0+ in bench "hybrid" $ nf (uncurry runTest) test0+ ]+ , bgroup+ "descent"+ [ let runTest x y = trainStepManual 0.02 x y net0+ in bench "manual" $ nf (uncurry runTest) test0+ , let runTest x y = trainStep 0.02 x y net0+ in bench "bp-lens" $ nf (uncurry runTest) test0+ , let runTest x y = trainStepHKD 0.02 x y net0+ in bench "bp-hkd" $ nf (uncurry runTest) test0+ , let runTest x y = trainStepHybrid 0.02 x y net0+ in bench "hybrid" $ nf (uncurry runTest) test0+ ]+ , bgroup+ "run"+ [ let runTest = runNetManual net0+ in bench "manual" $ nf runTest (fst test0)+ , let runTest x = evalBP (`runNetwork` x) net0+ in bench "bp-lens" $ nf runTest (fst test0)+ , let runTest x = evalBP (`runNetworkHKD` x) net0+ in bench "bp-hkd" $ nf runTest (fst test0)+ , let runTest x = evalBP (`runNetHybrid` x) net0+ in bench "hybrid" $ nf runTest (fst test0)+ ]+ ] -- ------------------------------ -- - "Backprop" Lens Mode - -- ------------------------------ -runLayer- :: (KnownNat i, KnownNat o, Reifies s W)- => BVar s (Layer i o)- -> BVar s (R i)- -> BVar s (R o)+runLayer ::+ (KnownNat i, KnownNat o, Reifies s W) =>+ BVar s (Layer i o) ->+ BVar s (R i) ->+ BVar s (R o) runLayer l x = (l ^^. lWeights) #>! x + (l ^^. lBiases) {-# INLINE runLayer #-} @@ -129,44 +135,46 @@ expx = exp x {-# INLINE softMax #-} -runNetwork- :: (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W)- => BVar s (Network i h1 h2 o)- -> R i- -> BVar s (R o)-runNetwork n = softMax- . runLayer (n ^^. nLayer3)- . logistic- . runLayer (n ^^. nLayer2)- . logistic- . runLayer (n ^^. nLayer1)- . auto+runNetwork ::+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W) =>+ BVar s (Network i h1 h2 o) ->+ R i ->+ BVar s (R o)+runNetwork n =+ softMax+ . runLayer (n ^^. nLayer3)+ . logistic+ . runLayer (n ^^. nLayer2)+ . logistic+ . runLayer (n ^^. nLayer1)+ . auto {-# INLINE runNetwork #-} -crossEntropy- :: (KnownNat n, Reifies s W)- => R n- -> BVar s (R n)- -> BVar s Double+crossEntropy ::+ (KnownNat n, Reifies s W) =>+ R n ->+ BVar s (R n) ->+ BVar s Double crossEntropy t r = negate $ log r <.>! auto t {-# INLINE crossEntropy #-} -netErr- :: (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W)- => R i- -> R o- -> BVar s (Network i h1 h2 o)- -> BVar s Double+netErr ::+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W) =>+ R i ->+ R o ->+ BVar s (Network i h1 h2 o) ->+ BVar s Double netErr x t n = crossEntropy t (runNetwork n x) {-# INLINE netErr #-} -trainStep- :: forall i h1 h2 o. (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o)- => Double- -> R i- -> R o- -> Network i h1 h2 o- -> Network i h1 h2 o+trainStep ::+ forall i h1 h2 o.+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) =>+ Double ->+ R i ->+ R o ->+ Network i h1 h2 o ->+ Network i h1 h2 o trainStep r !x !t !n = n - realToFrac r * gradBP (netErr x t) n {-# INLINE trainStep #-} @@ -174,44 +182,46 @@ -- - "Backprop" HKD Mode - -- ------------------------------ -runLayerHKD- :: (KnownNat i, KnownNat o, Reifies s W)- => BVar s (Layer i o)- -> BVar s (R i)- -> BVar s (R o)-runLayerHKD (splitBV->Layer w b) x = w #>! x + b+runLayerHKD ::+ (KnownNat i, KnownNat o, Reifies s W) =>+ BVar s (Layer i o) ->+ BVar s (R i) ->+ BVar s (R o)+runLayerHKD (splitBV -> Layer w b) x = w #>! x + b {-# INLINE runLayerHKD #-} -runNetworkHKD- :: (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W)- => BVar s (Network i h1 h2 o)- -> R i- -> BVar s (R o)-runNetworkHKD (splitBV->Net l1 l2 l3) = softMax- . runLayerHKD l3- . logistic- . runLayerHKD l2- . logistic- . runLayerHKD l1- . auto+runNetworkHKD ::+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W) =>+ BVar s (Network i h1 h2 o) ->+ R i ->+ BVar s (R o)+runNetworkHKD (splitBV -> Net l1 l2 l3) =+ softMax+ . runLayerHKD l3+ . logistic+ . runLayerHKD l2+ . logistic+ . runLayerHKD l1+ . auto {-# INLINE runNetworkHKD #-} -netErrHKD- :: (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W)- => R i- -> R o- -> BVar s (Network i h1 h2 o)- -> BVar s Double+netErrHKD ::+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W) =>+ R i ->+ R o ->+ BVar s (Network i h1 h2 o) ->+ BVar s Double netErrHKD x t n = crossEntropy t (runNetworkHKD n x) {-# INLINE netErrHKD #-} -trainStepHKD- :: forall i h1 h2 o. (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o)- => Double- -> R i- -> R o- -> Network i h1 h2 o- -> Network i h1 h2 o+trainStepHKD ::+ forall i h1 h2 o.+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) =>+ Double ->+ R i ->+ R o ->+ Network i h1 h2 o ->+ Network i h1 h2 o trainStepHKD r !x !t !n = n - realToFrac r * gradBP (netErrHKD x t) n {-# INLINE trainStepHKD #-} @@ -219,11 +229,11 @@ -- - "Manual" Mode - -- ------------------------------ -runLayerManual- :: (KnownNat i, KnownNat o)- => Layer i o- -> R i- -> R o+runLayerManual ::+ (KnownNat i, KnownNat o) =>+ Layer i o ->+ R i ->+ R o runLayerManual l x = (l ^. lWeights) #> x + (l ^. lBiases) {-# INLINE runLayerManual #-} @@ -233,69 +243,72 @@ expx = exp x {-# INLINE softMaxManual #-} -runNetManual- :: (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o)- => Network i h1 h2 o- -> R i- -> R o-runNetManual n = softMaxManual- . runLayerManual (n ^. nLayer3)- . logistic- . runLayerManual (n ^. nLayer2)- . logistic- . runLayerManual (n ^. nLayer1)+runNetManual ::+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) =>+ Network i h1 h2 o ->+ R i ->+ R o+runNetManual n =+ softMaxManual+ . runLayerManual (n ^. nLayer3)+ . logistic+ . runLayerManual (n ^. nLayer2)+ . logistic+ . runLayerManual (n ^. nLayer1) {-# INLINE runNetManual #-} -gradNetManual- :: forall i h1 h2 o. (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o)- => R i- -> R o- -> Network i h1 h2 o- -> Network i h1 h2 o+gradNetManual ::+ forall i h1 h2 o.+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) =>+ R i ->+ R o ->+ Network i h1 h2 o ->+ Network i h1 h2 o gradNetManual x t (Net (Layer w1 b1) (Layer w2 b2) (Layer w3 b3)) =- let y1 = w1 #> x- z1 = y1 + b1- x2 = logistic z1- y2 = w2 #> x2- z2 = y2 + b2- x3 = logistic z2- y3 = w3 #> x3- z3 = y3 + b3- o0 = exp z3- o1 = HM.sumElements (extract o0)- o2 = o0 / konst o1- -- o3 = - (log o2 <.> t)- dEdO3 = 1- dEdO2 = dEdO3 * (- t / o2)- dEdO1 = - (dEdO2 <.> o0) / (o1 ** 2)- dEdO0 = konst dEdO1 + dEdO2 / konst o1- dEdZ3 = dEdO0 * o0- dEdY3 = dEdZ3- dEdX3 = tr w3 #> dEdY3- dEdZ2 = dEdX3 * (x3 * (1 - x3))- dEdY2 = dEdZ2- dEdX2 = tr w2 #> dEdY2- dEdZ1 = dEdX2 * (x2 * (1 - x2))- dEdY1 = dEdZ1- dEdB3 = dEdZ3- dEdW3 = dEdY3 `outer` x3- dEdB2 = dEdZ2- dEdW2 = dEdY2 `outer` x2- dEdB1 = dEdZ1- dEdW1 = dEdY1 `outer` x- in Net (Layer dEdW1 dEdB1) (Layer dEdW2 dEdB2) (Layer dEdW3 dEdB3)+ let y1 = w1 #> x+ z1 = y1 + b1+ x2 = logistic z1+ y2 = w2 #> x2+ z2 = y2 + b2+ x3 = logistic z2+ y3 = w3 #> x3+ z3 = y3 + b3+ o0 = exp z3+ o1 = HM.sumElements (extract o0)+ o2 = o0 / konst o1+ -- o3 = - (log o2 <.> t)+ dEdO3 = 1+ dEdO2 = - (dEdO3 * t / o2)+ dEdO1 = -((dEdO2 <.> o0) / (o1 ** 2))+ dEdO0 = konst dEdO1 + dEdO2 / konst o1+ dEdZ3 = dEdO0 * o0+ dEdY3 = dEdZ3+ dEdX3 = tr w3 #> dEdY3+ dEdZ2 = dEdX3 * (x3 * (1 - x3))+ dEdY2 = dEdZ2+ dEdX2 = tr w2 #> dEdY2+ dEdZ1 = dEdX2 * (x2 * (1 - x2))+ dEdY1 = dEdZ1+ dEdB3 = dEdZ3+ dEdW3 = dEdY3 `outer` x3+ dEdB2 = dEdZ2+ dEdW2 = dEdY2 `outer` x2+ dEdB1 = dEdZ1+ dEdW1 = dEdY1 `outer` x+ in Net (Layer dEdW1 dEdB1) (Layer dEdW2 dEdB2) (Layer dEdW3 dEdB3) {-# INLINE gradNetManual #-} -trainStepManual- :: forall i h1 h2 o. (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o)- => Double- -> R i- -> R o- -> Network i h1 h2 o- -> Network i h1 h2 o+trainStepManual ::+ forall i h1 h2 o.+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) =>+ Double ->+ R i ->+ R o ->+ Network i h1 h2 o ->+ Network i h1 h2 o trainStepManual r !x !t !n =- let gN = gradNetManual x t n- in n - (realToFrac r * gN)+ let gN = gradNetManual x t n+ in n - (realToFrac r * gN) -- ------------------------------ -- - "Hybrid" Mode -@@ -303,84 +316,87 @@ layerOp :: (KnownNat i, KnownNat o) => Op '[Layer i o, R i] (R o) layerOp = op2 $ \(Layer w b) x ->- ( w #> x + b- , \g -> (Layer (g `outer` x) g, tr w #> g)- )+ ( w #> x + b+ , \g -> (Layer (g `outer` x) g, tr w #> g)+ ) {-# INLINE layerOp #-} -logisticOp- :: Floating a- => Op '[a] a+logisticOp ::+ Floating a =>+ Op '[a] a logisticOp = op1 $ \x ->- let lx = logistic x- in (lx, \g -> lx * (1 - lx) * g)+ let lx = logistic x+ in (lx, \g -> lx * (1 - lx) * g) {-# INLINE logisticOp #-} -softMaxOp- :: KnownNat n- => Op '[R n] (R n)+softMaxOp ::+ KnownNat n =>+ Op '[R n] (R n) softMaxOp = op1 $ \x ->- let expx = exp x- tot = sumElements expx- invtot = 1 / tot- res = konst invtot * expx- in ( res- , \g -> res - konst (invtot ** 2) * exp (2 * x) * g- )+ let expx = exp x+ tot = sumElements expx+ invtot = 1 / tot+ res = konst invtot * expx+ in ( res+ , \g -> res - konst (invtot ** 2) * exp (2 * x) * g+ ) {-# INLINE softMaxOp #-} -softMaxCrossEntropyOp- :: KnownNat n- => R n- -> Op '[R n] Double+softMaxCrossEntropyOp ::+ KnownNat n =>+ R n ->+ Op '[R n] Double softMaxCrossEntropyOp targ = op1 $ \x ->- let expx = exp x- sm = konst (1 / sumElements expx) * expx- ce = negate $ log sm <.> targ- in ( ce- , \g -> (sm - targ) * konst g- )+ let expx = exp x+ sm = konst (1 / sumElements expx) * expx+ ce = negate $ log sm <.> targ+ in ( ce+ , \g -> (sm - targ) * konst g+ ) {-# INLINE softMaxCrossEntropyOp #-} -runNetHybrid- :: (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W)- => BVar s (Network i h1 h2 o)- -> R i- -> BVar s (R o)-runNetHybrid n = liftOp1 softMaxOp- . liftOp2 layerOp (n ^^. nLayer3)- . liftOp1 logisticOp- . liftOp2 layerOp (n ^^. nLayer2)- . liftOp1 logisticOp- . liftOp2 layerOp (n ^^. nLayer1)- . auto+runNetHybrid ::+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W) =>+ BVar s (Network i h1 h2 o) ->+ R i ->+ BVar s (R o)+runNetHybrid n =+ liftOp1 softMaxOp+ . liftOp2 layerOp (n ^^. nLayer3)+ . liftOp1 logisticOp+ . liftOp2 layerOp (n ^^. nLayer2)+ . liftOp1 logisticOp+ . liftOp2 layerOp (n ^^. nLayer1)+ . auto {-# INLINE runNetHybrid #-} -netErrHybrid- :: (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W)- => BVar s (Network i h1 h2 o)- -> R o- -> R i- -> BVar s Double-netErrHybrid n t = liftOp1 (softMaxCrossEntropyOp t)- . liftOp2 layerOp (n ^^. nLayer3)- . liftOp1 logisticOp- . liftOp2 layerOp (n ^^. nLayer2)- . liftOp1 logisticOp- . liftOp2 layerOp (n ^^. nLayer1)- . auto+netErrHybrid ::+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o, Reifies s W) =>+ BVar s (Network i h1 h2 o) ->+ R o ->+ R i ->+ BVar s Double+netErrHybrid n t =+ liftOp1 (softMaxCrossEntropyOp t)+ . liftOp2 layerOp (n ^^. nLayer3)+ . liftOp1 logisticOp+ . liftOp2 layerOp (n ^^. nLayer2)+ . liftOp1 logisticOp+ . liftOp2 layerOp (n ^^. nLayer1)+ . auto {-# INLINE netErrHybrid #-} -trainStepHybrid- :: forall i h1 h2 o. (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o)- => Double- -> R i- -> R o- -> Network i h1 h2 o- -> Network i h1 h2 o+trainStepHybrid ::+ forall i h1 h2 o.+ (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) =>+ Double ->+ R i ->+ R o ->+ Network i h1 h2 o ->+ Network i h1 h2 o trainStepHybrid r !x !t !n =- let gN = gradBP (\n' -> netErrHybrid n' t x) n- in n - (realToFrac r * gN)+ let gN = gradBP (\n' -> netErrHybrid n' t x) n+ in n - (realToFrac r * gN) {-# INLINE trainStepHybrid #-} -- ------------------------------@@ -388,30 +404,31 @@ -- ------------------------------ infixr 8 #>!-(#>!)- :: (KnownNat m, KnownNat n, Reifies s W)- => BVar s (L m n)- -> BVar s (R n)- -> BVar s (R m)+(#>!) ::+ (KnownNat m, KnownNat n, Reifies s W) =>+ BVar s (L m n) ->+ BVar s (R n) ->+ BVar s (R m) (#>!) = liftOp2 . op2 $ \m v ->- ( m #> v, \g -> (g `outer` v, tr m #> g) )+ (m #> v, \g -> (g `outer` v, tr m #> g)) {-# INLINE (#>!) #-} infixr 8 <.>!-(<.>!)- :: (KnownNat n, Reifies s W)- => BVar s (R n)- -> BVar s (R n)- -> BVar s Double+(<.>!) ::+ (KnownNat n, Reifies s W) =>+ BVar s (R n) ->+ BVar s (R n) ->+ BVar s Double (<.>!) = liftOp2 . op2 $ \x y ->- ( x <.> y, \g -> (konst g * y, x * konst g)+ ( x <.> y+ , \g -> (konst g * y, x * konst g) ) {-# INLINE (<.>!) #-} -konst'- :: (KnownNat n, Reifies s W)- => BVar s Double- -> BVar s (R n)+konst' ::+ (KnownNat n, Reifies s W) =>+ BVar s Double ->+ BVar s (R n) konst' = liftOp1 . op1 $ \c -> (konst c, HM.sumElements . extract) {-# INLINE konst' #-} @@ -419,10 +436,10 @@ sumElements = HM.sumElements . extract {-# INLINE sumElements #-} -sumElements'- :: (KnownNat n, Reifies s W)- => BVar s (R n)- -> BVar s Double+sumElements' ::+ (KnownNat n, Reifies s W) =>+ BVar s (R n) ->+ BVar s Double sumElements' = liftOp1 . op1 $ \x -> (sumElements x, konst) {-# INLINE sumElements' #-} @@ -435,58 +452,58 @@ -- ------------------------------ instance (KnownNat i, KnownNat o) => Num (Layer i o) where- Layer w1 b1 + Layer w2 b2 = Layer (w1 + w2) (b1 + b2)- Layer w1 b1 - Layer w2 b2 = Layer (w1 - w2) (b1 - b2)- Layer w1 b1 * Layer w2 b2 = Layer (w1 * w2) (b1 * b2)- abs (Layer w b) = Layer (abs w) (abs b)- signum (Layer w b) = Layer (signum w) (signum b)- negate (Layer w b) = Layer (negate w) (negate b)- fromInteger x = Layer (fromInteger x) (fromInteger x)+ Layer w1 b1 + Layer w2 b2 = Layer (w1 + w2) (b1 + b2)+ Layer w1 b1 - Layer w2 b2 = Layer (w1 - w2) (b1 - b2)+ Layer w1 b1 * Layer w2 b2 = Layer (w1 * w2) (b1 * b2)+ abs (Layer w b) = Layer (abs w) (abs b)+ signum (Layer w b) = Layer (signum w) (signum b)+ negate (Layer w b) = Layer (negate w) (negate b)+ fromInteger x = Layer (fromInteger x) (fromInteger x) instance (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) => Num (Network i h1 h2 o) where- Net a b c + Net d e f = Net (a + d) (b + e) (c + f)- Net a b c - Net d e f = Net (a - d) (b - e) (c - f)- Net a b c * Net d e f = Net (a * d) (b * e) (c * f)- abs (Net a b c) = Net (abs a) (abs b) (abs c)- signum (Net a b c) = Net (signum a) (signum b) (signum c)- negate (Net a b c) = Net (negate a) (negate b) (negate c)- fromInteger x = Net (fromInteger x) (fromInteger x) (fromInteger x)+ Net a b c + Net d e f = Net (a + d) (b + e) (c + f)+ Net a b c - Net d e f = Net (a - d) (b - e) (c - f)+ Net a b c * Net d e f = Net (a * d) (b * e) (c * f)+ abs (Net a b c) = Net (abs a) (abs b) (abs c)+ signum (Net a b c) = Net (signum a) (signum b) (signum c)+ negate (Net a b c) = Net (negate a) (negate b) (negate c)+ fromInteger x = Net (fromInteger x) (fromInteger x) (fromInteger x) instance (KnownNat i, KnownNat o) => Fractional (Layer i o) where- Layer w1 b1 / Layer w2 b2 = Layer (w1 / w2) (b1 / b2)- recip (Layer w b) = Layer (recip w) (recip b)- fromRational x = Layer (fromRational x) (fromRational x)+ Layer w1 b1 / Layer w2 b2 = Layer (w1 / w2) (b1 / b2)+ recip (Layer w b) = Layer (recip w) (recip b)+ fromRational x = Layer (fromRational x) (fromRational x) instance (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) => Fractional (Network i h1 h2 o) where- Net a b c / Net d e f = Net (a / d) (b / e) (c / f)- recip (Net a b c) = Net (recip a) (recip b) (recip c)- fromRational x = Net (fromRational x) (fromRational x) (fromRational x)+ Net a b c / Net d e f = Net (a / d) (b / e) (c / f)+ recip (Net a b c) = Net (recip a) (recip b) (recip c)+ fromRational x = Net (fromRational x) (fromRational x) (fromRational x) instance KnownNat n => MWC.Variate (R n) where- uniform g = randomVector <$> MWC.uniform g <*> pure Uniform- uniformR (l, h) g = (\x -> x * (h - l) + l) <$> MWC.uniform g+ uniform g = randomVector <$> MWC.uniform g <*> pure Uniform+ uniformR (l, h) g = (\x -> x * (h - l) + l) <$> MWC.uniform g instance (KnownNat m, KnownNat n) => MWC.Variate (L m n) where- uniform g = uniformSample <$> MWC.uniform g <*> pure 0 <*> pure 1- uniformR (l, h) g = (\x -> x * (h - l) + l) <$> MWC.uniform g+ uniform g = uniformSample <$> MWC.uniform g <*> pure 0 <*> pure 1+ uniformR (l, h) g = (\x -> x * (h - l) + l) <$> MWC.uniform g instance (KnownNat i, KnownNat o) => MWC.Variate (Layer i o) where- uniform g = Layer <$> MWC.uniform g <*> MWC.uniform g- uniformR (l, h) g = (\x -> x * (h - l) + l) <$> MWC.uniform g+ uniform g = Layer <$> MWC.uniform g <*> MWC.uniform g+ uniformR (l, h) g = (\x -> x * (h - l) + l) <$> MWC.uniform g instance (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) => MWC.Variate (Network i h1 h2 o) where- uniform g = Net <$> MWC.uniform g <*> MWC.uniform g <*> MWC.uniform g- uniformR (l, h) g = (\x -> x * (h - l) + l) <$> MWC.uniform g+ uniform g = Net <$> MWC.uniform g <*> MWC.uniform g <*> MWC.uniform g+ uniformR (l, h) g = (\x -> x * (h - l) + l) <$> MWC.uniform g instance Backprop (R n) where- zero = zeroNum- add = addNum- one = oneNum+ zero = zeroNum+ add = addNum+ one = oneNum instance (KnownNat n, KnownNat m) => Backprop (L m n) where- zero = zeroNum- add = addNum- one = oneNum+ zero = zeroNum+ add = addNum+ one = oneNum instance (KnownNat i, KnownNat o) => Backprop (Layer i o) instance (KnownNat i, KnownNat h1, KnownNat h2, KnownNat o) => Backprop (Network i h1 h2 o)
src/Data/Type/Util.hs view
@@ -1,64 +1,68 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TupleSections #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-} {-# LANGUAGE TypeFamilyDependencies #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-} module Data.Type.Util (- runzipWith- , rzipWithM_- , Replicate- , VecT(.., (:+))- , vmap- , withVec- , vecToRec- , fillRec- , zipVecList- , splitRec- , p1, p2, s1, s2- ) where+ runzipWith,+ rzipWithM_,+ Replicate,+ VecT (.., (:+)),+ vmap,+ withVec,+ vecToRec,+ fillRec,+ zipVecList,+ splitRec,+ p1,+ p2,+ s1,+ s2,+) where -import Data.Bifunctor-import Data.Functor.Identity-import Data.Kind-import Data.Proxy-import Data.Vinyl.Core-import Data.Vinyl.TypeLevel-import GHC.Generics-import Lens.Micro+import Data.Bifunctor+import Data.Functor.Identity+import Data.Kind+import Data.Proxy+import Data.Vinyl.Core+import Data.Vinyl.TypeLevel+import GHC.Generics+import Lens.Micro -runzipWith- :: forall f g h. ()- => (forall x. f x -> (g x, h x))- -> (forall xs. Rec f xs -> (Rec g xs, Rec h xs))+runzipWith ::+ forall f g h.+ () =>+ (forall x. f x -> (g x, h x)) ->+ (forall xs. Rec f xs -> (Rec g xs, Rec h xs)) runzipWith f = go where go :: forall ys. Rec f ys -> (Rec g ys, Rec h ys) go = \case- RNil -> (RNil, RNil)- x :& xs -> let (y , z ) = f x- (ys, zs) = go xs- in (y :& ys, z :& zs)+ RNil -> (RNil, RNil)+ x :& xs ->+ let (y, z) = f x+ (ys, zs) = go xs+ in (y :& ys, z :& zs) {-# INLINE runzipWith #-} data VecT :: Nat -> (k -> Type) -> k -> Type where- VNil :: VecT 'Z f a- (:*) :: !(f a) -> VecT n f a -> VecT ('S n) f a+ VNil :: VecT 'Z f a+ (:*) :: !(f a) -> VecT n f a -> VecT ('S n) f a pattern (:+) :: a -> VecT n Identity a -> VecT ('S n) Identity a pattern x :+ xs = Identity x :* xs -vmap- :: forall n f g a. ()- => (f a -> g a) -> VecT n f a -> VecT n g a+vmap ::+ forall n f g a.+ () =>+ (f a -> g a) -> VecT n f a -> VecT n g a vmap f = go where go :: VecT m f a -> VecT m g a@@ -67,49 +71,51 @@ x :* xs -> f x :* go xs {-# INLINE vmap #-} -withVec- :: [f a]- -> (forall n. VecT n f a -> r)- -> r+withVec ::+ [f a] ->+ (forall n. VecT n f a -> r) ->+ r withVec = \case- [] -> \f -> f VNil- x:xs -> \f -> withVec xs (f . (x :*))+ [] -> \f -> f VNil+ x : xs -> \f -> withVec xs (f . (x :*)) {-# INLINE withVec #-} type family Replicate (n :: Nat) (a :: k) = (as :: [k]) | as -> n where- Replicate 'Z a = '[]- Replicate ('S n) a = a ': Replicate n a+ Replicate 'Z a = '[]+ Replicate ('S n) a = a ': Replicate n a -vecToRec- :: VecT n f a- -> Rec f (Replicate n a)+vecToRec ::+ VecT n f a ->+ Rec f (Replicate n a) vecToRec = \case- VNil -> RNil- x :* xs -> x :& vecToRec xs+ VNil -> RNil+ x :* xs -> x :& vecToRec xs {-# INLINE vecToRec #-} -fillRec- :: forall f g as c. ()- => (forall a. f a -> c -> g a)- -> Rec f as- -> [c]- -> Maybe (Rec g as)+fillRec ::+ forall f g as c.+ () =>+ (forall a. f a -> c -> g a) ->+ Rec f as ->+ [c] ->+ Maybe (Rec g as) fillRec f = go where go :: Rec f bs -> [c] -> Maybe (Rec g bs) go = \case RNil -> \_ -> Just RNil x :& xs -> \case- [] -> Nothing- y:ys -> (f x y :&) <$> go xs ys+ [] -> Nothing+ y : ys -> (f x y :&) <$> go xs ys {-# INLINE fillRec #-} -rzipWithM_- :: forall h f g as. Applicative h- => (forall a. f a -> g a -> h ())- -> Rec f as- -> Rec g as- -> h ()+rzipWithM_ ::+ forall h f g as.+ Applicative h =>+ (forall a. f a -> g a -> h ()) ->+ Rec f as ->+ Rec g as ->+ h () rzipWithM_ f = go where go :: forall bs. Rec f bs -> Rec g bs -> h ()@@ -120,26 +126,28 @@ y :& ys -> f x y *> go xs ys {-# INLINE rzipWithM_ #-} -zipVecList- :: forall a b c f g n. ()- => (f a -> Maybe b -> g c)- -> VecT n f a- -> [b]- -> VecT n g c+zipVecList ::+ forall a b c f g n.+ () =>+ (f a -> Maybe b -> g c) ->+ VecT n f a ->+ [b] ->+ VecT n g c zipVecList f = go where go :: VecT m f a -> [b] -> VecT m g c go = \case VNil -> const VNil x :* xs -> \case- [] -> f x Nothing :* go xs []- y:ys -> f x (Just y) :* go xs ys+ [] -> f x Nothing :* go xs []+ y : ys -> f x (Just y) :* go xs ys {-# INLINE zipVecList #-} -splitRec- :: forall f as bs. RecApplicative as- => Rec f (as ++ bs)- -> (Rec f as, Rec f bs)+splitRec ::+ forall f as bs.+ RecApplicative as =>+ Rec f (as ++ bs) ->+ (Rec f as, Rec f bs) splitRec = go (rpure Proxy) where go :: Rec Proxy as' -> Rec f (as' ++ bs) -> (Rec f as', Rec f bs)
src/Numeric/Backprop.hs view
@@ -1,10 +1,10 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-} -- | -- Module : Numeric.Backprop@@ -66,61 +66,110 @@ -- 'zero', 'add', and 'one' explicitly, which can be useful when attempting -- to avoid orphan instances or when mixing both 'Backprop' and 'Num' -- styles.---- module Numeric.Backprop (- -- * Types- BVar, W, Backprop(..), ABP(..), NumBP(..)- -- * Running- , backprop, E.evalBP, gradBP, backpropWith- -- ** Multiple inputs- , backprop2, E.evalBP2, gradBP2, backpropWith2- , backpropN, E.evalBPN, gradBPN, backpropWithN- -- * Manipulating 'BVar'- , E.evalBP0- , E.constVar, E.auto, E.coerceVar- , (^^.), (.~~), (%~~), (^^?), (^^..), (^^?!)- , viewVar, setVar, overVar- , sequenceVar, collectVar- , previewVar, toListOfVar- , pattern T2, pattern T3- -- ** With Isomorphisms- , isoVar, isoVar2, isoVar3, isoVarN- -- ** With 'Op's#liftops#- -- $liftops- , liftOp- , liftOp1, liftOp2, liftOp3- -- ** Generics#hkd#- -- $hkd- , splitBV- , joinBV- , pattern BV- , E.BVGroup- -- * 'Op'- , Op(..)- -- ** Creation- , op0, opConst, idOp- , bpOp- -- *** Giving gradients directly- , op1, op2, op3- -- *** From Isomorphisms- , opCoerce, opTup, opIso, opIsoN, opLens- -- *** No gradients- , noGrad1, noGrad- -- * Utility- , Reifies- ) where+ -- * Types+ BVar,+ W,+ Backprop (..),+ ABP (..),+ NumBP (..), -import Data.Functor.Identity-import Data.Maybe-import Data.Reflection-import Data.Vinyl-import GHC.Generics-import Lens.Micro-import Numeric.Backprop.Class-import Numeric.Backprop.Explicit (BVar, W)-import Numeric.Backprop.Op+ -- * Running+ backprop,+ E.evalBP,+ gradBP,+ backpropWith,++ -- ** Multiple inputs+ backprop2,+ E.evalBP2,+ gradBP2,+ backpropWith2,+ backpropN,+ E.evalBPN,+ gradBPN,+ backpropWithN,++ -- * Manipulating 'BVar'+ E.evalBP0,+ E.constVar,+ E.auto,+ E.coerceVar,+ (^^.),+ (.~~),+ (%~~),+ (^^?),+ (^^..),+ (^^?!),+ viewVar,+ setVar,+ overVar,+ sequenceVar,+ collectVar,+ previewVar,+ toListOfVar,+ pattern T2,+ pattern T3,++ -- ** With Isomorphisms+ isoVar,+ isoVar2,+ isoVar3,+ isoVarN,++ -- ** With 'Op's#liftops#+ -- $liftops+ liftOp,+ liftOp1,+ liftOp2,+ liftOp3,++ -- ** Generics#hkd#+ -- $hkd+ splitBV,+ joinBV,+ pattern BV,+ E.BVGroup,++ -- * 'Op'+ Op (..),++ -- ** Creation+ op0,+ opConst,+ idOp,+ bpOp,++ -- *** Giving gradients directly+ op1,+ op2,+ op3,++ -- *** From Isomorphisms+ opCoerce,+ opTup,+ opIso,+ opIsoN,+ opLens,++ -- *** No gradients+ noGrad1,+ noGrad,++ -- * Utility+ Reifies,+) where++import Data.Functor.Identity+import Data.Maybe+import Data.Reflection+import Data.Vinyl+import GHC.Generics+import Lens.Micro+import Numeric.Backprop.Class+import Numeric.Backprop.Explicit (BVar, W) import qualified Numeric.Backprop.Explicit as E+import Numeric.Backprop.Op -- $liftops --@@ -186,11 +235,11 @@ -- If you stick to /concerete/, monomorphic usage of this (with specific -- types, typed into source code, known at compile-time), then -- @'RPureConstrained' 'Backprop' as@ should be fulfilled automatically.-backpropN- :: (RPureConstrained Backprop as, Backprop b)- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> (b, Rec Identity as)+backpropN ::+ (RPureConstrained Backprop as, Backprop b) =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ (b, Rec Identity as) backpropN = E.backpropN E.zeroFuncs E.oneFunc {-# INLINE backpropN #-} @@ -201,11 +250,11 @@ -- Note that argument order changed in v0.2.4. -- -- @since 0.2.0.0-backpropWithN- :: RPureConstrained Backprop as- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> (b, b -> Rec Identity as)+backpropWithN ::+ RPureConstrained Backprop as =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ (b, b -> Rec Identity as) backpropWithN = E.backpropWithN E.zeroFuncs {-# INLINE backpropWithN #-} @@ -216,11 +265,11 @@ -- that 'BVar's do not leak out of the context (similar to how it is used -- in "Control.Monad.ST"), and also as a reference to an ephemeral Wengert -- tape used to track the graph of references.-backprop- :: (Backprop a, Backprop b)- => (forall s. Reifies s W => BVar s a -> BVar s b)- -> a- -> (b, a)+backprop ::+ (Backprop a, Backprop b) =>+ (forall s. Reifies s W => BVar s a -> BVar s b) ->+ a ->+ (b, a) backprop = E.backprop E.zeroFunc E.oneFunc {-# INLINE backprop #-} @@ -241,11 +290,11 @@ -- Note that argument order changed in v0.2.4 -- -- @since 0.2.0.0-backpropWith- :: Backprop a- => (forall s. Reifies s W => BVar s a -> BVar s b)- -> a- -> (b, b -> a)+backpropWith ::+ Backprop a =>+ (forall s. Reifies s W => BVar s a -> BVar s b) ->+ a ->+ (b, b -> a) backpropWith = E.backpropWith E.zeroFunc {-# INLINE backpropWith #-} @@ -263,21 +312,21 @@ -- -- If you want to provide an explicit "final gradient" for the end, see -- 'backpropWith'.-gradBP- :: (Backprop a, Backprop b)- => (forall s. Reifies s W => BVar s a -> BVar s b)- -> a- -> a+gradBP ::+ (Backprop a, Backprop b) =>+ (forall s. Reifies s W => BVar s a -> BVar s b) ->+ a ->+ a gradBP = E.gradBP E.zeroFunc E.oneFunc {-# INLINE gradBP #-} -- | 'gradBP' generalized to multiple inputs of different types. See -- documentation for 'backpropN' for more details.-gradBPN- :: (RPureConstrained Backprop as, Backprop b)- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> Rec Identity as+gradBPN ::+ (RPureConstrained Backprop as, Backprop b) =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ Rec Identity as gradBPN = E.gradBPN E.zeroFuncs E.oneFunc {-# INLINE gradBPN #-} @@ -288,12 +337,12 @@ -- However, this could potentially be more performant. -- -- For 3 and more arguments, consider using 'backpropN'.-backprop2- :: (Backprop a, Backprop b, Backprop c)- => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> (c, (a, b))+backprop2 ::+ (Backprop a, Backprop b, Backprop c) =>+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ (c, (a, b)) backprop2 = E.backprop2 E.zeroFunc E.zeroFunc E.oneFunc {-# INLINE backprop2 #-} @@ -304,22 +353,22 @@ -- Note that argument order changed in v0.2.4 -- -- @since 0.2.0.0-backpropWith2- :: (Backprop a, Backprop b)- => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> (c, c -> (a, b))+backpropWith2 ::+ (Backprop a, Backprop b) =>+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ (c, c -> (a, b)) backpropWith2 = E.backpropWith2 E.zeroFunc E.zeroFunc {-# INLINE backpropWith2 #-} -- | 'gradBP' for a two-argument function. See 'backprop2' for notes.-gradBP2- :: (Backprop a, Backprop b, Backprop c)- => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> (a, b)+gradBP2 ::+ (Backprop a, Backprop b, Backprop c) =>+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ (a, b) gradBP2 = E.gradBP2 E.zeroFunc E.zeroFunc E.oneFunc {-# INLINE gradBP2 #-} @@ -332,10 +381,10 @@ -- 'liftOp' . 'bpOp' = 'id' -- 'bpOp' . 'liftOp' = 'id' -- @-bpOp- :: RPureConstrained Backprop as- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Op as b+bpOp ::+ RPureConstrained Backprop as =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Op as b bpOp = E.bpOp E.zeroFuncs {-# INLINE bpOp #-} @@ -374,13 +423,14 @@ -- -- __WARNING__: Do not use with any lenses that operate "numerically" on -- the contents (like 'multiplying').----(^^.)- :: forall b a s. (Backprop b, Backprop a, Reifies s W)- => BVar s b- -> Lens' b a- -> BVar s a+(^^.) ::+ forall b a s.+ (Backprop b, Backprop a, Reifies s W) =>+ BVar s b ->+ Lens' b a ->+ BVar s a x ^^. l = viewVar l x+ infixl 8 ^^. {-# INLINE (^^.) #-} @@ -388,15 +438,15 @@ -- parallels to 'view' from lens. -- -- See documentation for '^^.' for more information, caveats, and warnings.-viewVar- :: forall b a s. (Backprop a, Backprop b, Reifies s W)- => Lens' b a- -> BVar s b- -> BVar s a+viewVar ::+ forall b a s.+ (Backprop a, Backprop b, Reifies s W) =>+ Lens' b a ->+ BVar s b ->+ BVar s a viewVar = E.viewVar E.addFunc E.zeroFunc {-# INLINE viewVar #-} - -- | An infix version of 'setVar', meant to evoke parallels to '.~' from -- lens. --@@ -421,14 +471,14 @@ -- -- Note that this does not incurr the performance overhead issues of -- 'viewVar' and '^^.', and is fairly cheap.----(.~~)- :: (Backprop a, Backprop b, Reifies s W)- => Lens' b a- -> BVar s a- -> BVar s b- -> BVar s b+(.~~) ::+ (Backprop a, Backprop b, Reifies s W) =>+ Lens' b a ->+ BVar s a ->+ BVar s b ->+ BVar s b l .~~ x = setVar l x+ infixl 8 .~~ {-# INLINE (.~~) #-} @@ -436,12 +486,12 @@ -- parallels to "set" from lens. -- -- See documentation for '.~~' for more information.-setVar- :: (Backprop a, Backprop b, Reifies s W)- => Lens' b a- -> BVar s a- -> BVar s b- -> BVar s b+setVar ::+ (Backprop a, Backprop b, Reifies s W) =>+ Lens' b a ->+ BVar s a ->+ BVar s b ->+ BVar s b setVar = E.setVar E.addFunc E.addFunc E.zeroFunc {-# INLINE setVar #-} @@ -470,14 +520,14 @@ -- a 'setVar'. -- -- @since 0.2.4.0----(%~~)- :: (Backprop a, Backprop b, Reifies s W)- => Lens' b a- -> (BVar s a -> BVar s a)- -> BVar s b- -> BVar s b+(%~~) ::+ (Backprop a, Backprop b, Reifies s W) =>+ Lens' b a ->+ (BVar s a -> BVar s a) ->+ BVar s b ->+ BVar s b l %~~ f = overVar l f+ infixr 4 %~~ {-# INLINE (%~~) #-} @@ -486,16 +536,15 @@ -- information. -- -- @since 0.2.4.0-overVar- :: (Backprop a, Backprop b, Reifies s W)- => Lens' b a- -> (BVar s a -> BVar s a)- -> BVar s b- -> BVar s b+overVar ::+ (Backprop a, Backprop b, Reifies s W) =>+ Lens' b a ->+ (BVar s a -> BVar s a) ->+ BVar s b ->+ BVar s b overVar = E.overVar E.addFunc E.addFunc E.zeroFunc E.zeroFunc {-# INLINE overVar #-} - -- | An infix version of 'previewVar', meant to evoke parallels to '^?' -- from lens. --@@ -528,12 +577,14 @@ -- -- __NOTE__: Has the same potential of performance overhead issues as -- '^^.'; see documentation of '^^.' for more details.-(^^?)- :: forall b a s. (Backprop b, Backprop a, Reifies s W)- => BVar s b- -> Traversal' b a- -> Maybe (BVar s a)+(^^?) ::+ forall b a s.+ (Backprop b, Backprop a, Reifies s W) =>+ BVar s b ->+ Traversal' b a ->+ Maybe (BVar s a) v ^^? t = previewVar t v+ infixl 8 ^^? {-# INLINE (^^?) #-} @@ -545,14 +596,16 @@ -- Is essentially '^^?' with 'fromJust', or '^^..' with 'head'. -- -- @since 0.2.1.0-(^^?!)- :: forall b a s. (Backprop b, Backprop a, Reifies s W)- => BVar s b- -> Traversal' b a- -> BVar s a+(^^?!) ::+ forall b a s.+ (Backprop b, Backprop a, Reifies s W) =>+ BVar s b ->+ Traversal' b a ->+ BVar s a v ^^?! t = fromMaybe (error e) (previewVar t v) where e = "Numeric.Backprop.^^?!: Empty traversal"+ infixl 8 ^^?! {-# INLINE (^^?!) #-} @@ -562,11 +615,12 @@ -- to be used wth 'Prism''s, or up-to-one target traversals. -- -- See documentation for '^^?' for more information, warnings, and caveats.-previewVar- :: forall b a s. (Backprop b, Backprop a, Reifies s W)- => Traversal' b a- -> BVar s b- -> Maybe (BVar s a)+previewVar ::+ forall b a s.+ (Backprop b, Backprop a, Reifies s W) =>+ Traversal' b a ->+ BVar s b ->+ Maybe (BVar s a) previewVar = E.previewVar E.addFunc E.zeroFunc {-# INLINE previewVar #-} @@ -593,12 +647,12 @@ -- -- __NOTE__: Has all of the performance overhead issues of 'sequenceVar'; -- see documentation for 'sequenceVar' for more information.----(^^..)- :: forall b a s. (Backprop b, Backprop a, Reifies s W)- => BVar s b- -> Traversal' b a- -> [BVar s a]+(^^..) ::+ forall b a s.+ (Backprop b, Backprop a, Reifies s W) =>+ BVar s b ->+ Traversal' b a ->+ [BVar s a] v ^^.. t = toListOfVar t v {-# INLINE (^^..) #-} @@ -607,11 +661,12 @@ -- -- See documentation for '^^..' for more information, warnings, and -- caveats.-toListOfVar- :: forall b a s. (Backprop b, Backprop a, Reifies s W)- => Traversal' b a- -> BVar s b- -> [BVar s a]+toListOfVar ::+ forall b a s.+ (Backprop b, Backprop a, Reifies s W) =>+ Traversal' b a ->+ BVar s b ->+ [BVar s a] toListOfVar = E.toListOfVar E.addFunc E.zeroFunc {-# INLINE toListOfVar #-} @@ -631,10 +686,10 @@ -- with cheap 'add' (like 'Double'), but may be costly for things like -- large matrices. See <https://backprop.jle.im/07-performance.html the -- performance guide> for for details.-sequenceVar- :: (Traversable t, Backprop a, Reifies s W)- => BVar s (t a)- -> t (BVar s a)+sequenceVar ::+ (Traversable t, Backprop a, Reifies s W) =>+ BVar s (t a) ->+ t (BVar s a) sequenceVar = E.sequenceVar E.addFunc E.zeroFunc {-# INLINE sequenceVar #-} @@ -652,10 +707,10 @@ -- a very small constant factor that consistent for all types. This -- reveals a general property of reverse-mode automatic differentiation; -- "many to one" is cheap, but "one to many" is expensive.-collectVar- :: (Foldable t, Functor t, Backprop a, Reifies s W)- => t (BVar s a)- -> BVar s (t a)+collectVar ::+ (Foldable t, Functor t, Backprop a, Reifies s W) =>+ t (BVar s a) ->+ BVar s (t a) collectVar = E.collectVar E.addFunc E.zeroFunc {-# INLINE collectVar #-} @@ -668,11 +723,11 @@ -- See "Numeric.Backprop#liftops" and documentation for 'liftOp' for more -- information, and "Numeric.Backprop.Op#prod" for a mini-tutorial on using -- 'Rec'.-liftOp- :: (RPureConstrained Backprop as, Reifies s W)- => Op as b- -> Rec (BVar s) as- -> BVar s b+liftOp ::+ (RPureConstrained Backprop as, Reifies s W) =>+ Op as b ->+ Rec (BVar s) as ->+ BVar s b liftOp = E.liftOp E.addFuncs {-# INLINE liftOp #-} @@ -683,11 +738,11 @@ -- -- See "Numeric.Backprop#liftops" and documentation for 'liftOp' for more -- information.-liftOp1- :: (Backprop a, Reifies s W)- => Op '[a] b- -> BVar s a- -> BVar s b+liftOp1 ::+ (Backprop a, Reifies s W) =>+ Op '[a] b ->+ BVar s a ->+ BVar s b liftOp1 = E.liftOp1 E.addFunc {-# INLINE liftOp1 #-} @@ -698,12 +753,12 @@ -- -- See "Numeric.Backprop#liftops" and documentation for 'liftOp' for more -- information.-liftOp2- :: (Backprop a, Backprop b, Reifies s W)- => Op '[a,b] c- -> BVar s a- -> BVar s b- -> BVar s c+liftOp2 ::+ (Backprop a, Backprop b, Reifies s W) =>+ Op '[a, b] c ->+ BVar s a ->+ BVar s b ->+ BVar s c liftOp2 = E.liftOp2 E.addFunc E.addFunc {-# INLINE liftOp2 #-} @@ -714,13 +769,13 @@ -- -- See "Numeric.Backprop#liftops" and documentation for 'liftOp' for more -- information.-liftOp3- :: (Backprop a, Backprop b, Backprop c, Reifies s W)- => Op '[a,b,c] d- -> BVar s a- -> BVar s b- -> BVar s c- -> BVar s d+liftOp3 ::+ (Backprop a, Backprop b, Backprop c, Reifies s W) =>+ Op '[a, b, c] d ->+ BVar s a ->+ BVar s b ->+ BVar s c ->+ BVar s d liftOp3 = E.liftOp3 E.addFunc E.addFunc E.addFunc {-# INLINE liftOp3 #-} @@ -736,12 +791,12 @@ -- Basically, don't use this for any "numeric" isomorphisms. -- -- @since 0.1.4.0-isoVar- :: (Backprop a, Reifies s W)- => (a -> b)- -> (b -> a)- -> BVar s a- -> BVar s b+isoVar ::+ (Backprop a, Reifies s W) =>+ (a -> b) ->+ (b -> a) ->+ BVar s a ->+ BVar s b isoVar = E.isoVar E.addFunc {-# INLINE isoVar #-} @@ -753,13 +808,13 @@ -- join together 'BVar's as their fields. -- -- @since 0.1.4.0-isoVar2- :: (Backprop a, Backprop b, Reifies s W)- => (a -> b -> c)- -> (c -> (a, b))- -> BVar s a- -> BVar s b- -> BVar s c+isoVar2 ::+ (Backprop a, Backprop b, Reifies s W) =>+ (a -> b -> c) ->+ (c -> (a, b)) ->+ BVar s a ->+ BVar s b ->+ BVar s c isoVar2 = E.isoVar2 E.addFunc E.addFunc {-# INLINE isoVar2 #-} @@ -767,14 +822,14 @@ -- Useful for things like constructors. See 'isoVar' for caveats. -- -- @since 0.1.4.0-isoVar3- :: (Backprop a, Backprop b, Backprop c, Reifies s W)- => (a -> b -> c -> d)- -> (d -> (a, b, c))- -> BVar s a- -> BVar s b- -> BVar s c- -> BVar s d+isoVar3 ::+ (Backprop a, Backprop b, Backprop c, Reifies s W) =>+ (a -> b -> c -> d) ->+ (d -> (a, b, c)) ->+ BVar s a ->+ BVar s b ->+ BVar s c ->+ BVar s d isoVar3 = E.isoVar3 E.addFunc E.addFunc E.addFunc {-# INLINE isoVar3 #-} @@ -787,12 +842,12 @@ -- join together 'BVar's as their fields. -- -- @since 0.1.4.0-isoVarN- :: (RPureConstrained Backprop as, Reifies s W)- => (Rec Identity as -> b)- -> (b -> Rec Identity as)- -> Rec (BVar s) as- -> BVar s b+isoVarN ::+ (RPureConstrained Backprop as, Reifies s W) =>+ (Rec Identity as -> b) ->+ (b -> Rec Identity as) ->+ Rec (BVar s) as ->+ BVar s b isoVarN = E.isoVarN E.addFuncs {-# INLINE isoVarN #-} @@ -800,11 +855,11 @@ -- two-tuples. -- -- @since 0.2.1.0-pattern T2- :: (Backprop a, Backprop b, Reifies s W)- => BVar s a- -> BVar s b- -> BVar s (a, b)+pattern T2 ::+ (Backprop a, Backprop b, Reifies s W) =>+ BVar s a ->+ BVar s b ->+ BVar s (a, b) pattern T2 x y <- (\xy -> (xy ^^. _1, xy ^^. _2) -> (x, y)) where T2 = isoVar2 (,) id@@ -816,12 +871,12 @@ -- three-tuples. -- -- @since 0.2.1.0-pattern T3- :: (Backprop a, Backprop b, Backprop c, Reifies s W)- => BVar s a- -> BVar s b- -> BVar s c- -> BVar s (a, b, c)+pattern T3 ::+ (Backprop a, Backprop b, Backprop c, Reifies s W) =>+ BVar s a ->+ BVar s b ->+ BVar s c ->+ BVar s (a, b, c) pattern T3 x y z <- (\xyz -> (xyz ^^. _1, xyz ^^. _2, xyz ^^. _3) -> (x, y, z)) where T3 = isoVar3 (,,) id@@ -953,17 +1008,19 @@ -- interested in helping out! -- -- @since 0.2.2.0-splitBV- :: ( Generic (z f)- , Generic (z (BVar s))- , E.BVGroup s as (Rep (z f)) (Rep (z (BVar s)))- , Backprop (z f)- , Backprop (Rep (z f) ())- , RPureConstrained Backprop as- , Reifies s W- )- => BVar s (z f) -- ^ 'BVar' of value- -> z (BVar s) -- ^ 'BVar's of fields+splitBV ::+ ( Generic (z f)+ , Generic (z (BVar s))+ , E.BVGroup s as (Rep (z f)) (Rep (z (BVar s)))+ , Backprop (z f)+ , Backprop (Rep (z f) ())+ , RPureConstrained Backprop as+ , Reifies s W+ ) =>+ -- | 'BVar' of value+ BVar s (z f) ->+ -- | 'BVar's of fields+ z (BVar s) splitBV = E.splitBV E.addFunc E.addFuncs E.zeroFunc E.zeroFuncs {-# INLINE splitBV #-} @@ -987,17 +1044,19 @@ -- differentiation: "many to one" is cheap, but "one to many" is expensive. -- -- @since 0.2.2.0-joinBV- :: ( Generic (z f)- , Generic (z (BVar s))- , E.BVGroup s as (Rep (z f)) (Rep (z (BVar s)))- , Backprop (z f)- , Backprop (Rep (z f) ())- , RPureConstrained Backprop as- , Reifies s W- )- => z (BVar s) -- ^ 'BVar's of fields- -> BVar s (z f) -- ^ 'BVar' of combined value+joinBV ::+ ( Generic (z f)+ , Generic (z (BVar s))+ , E.BVGroup s as (Rep (z f)) (Rep (z (BVar s)))+ , Backprop (z f)+ , Backprop (Rep (z f) ())+ , RPureConstrained Backprop as+ , Reifies s W+ ) =>+ -- | 'BVar's of fields+ z (BVar s) ->+ -- | 'BVar' of combined value+ BVar s (z f) joinBV = E.joinBV E.addFunc E.addFuncs E.zeroFunc E.zeroFuncs {-# INLINE joinBV #-} @@ -1005,16 +1064,16 @@ -- is a pattern for a @'BVar' s (z f)@ containing a @z ('BVar' s)@ -- -- @since 0.2.3.0-pattern BV- :: ( Generic (z f)- , Generic (z (BVar s))- , E.BVGroup s as (Rep (z f)) (Rep (z (BVar s)))- , Backprop (Rep (z f) ())- , Backprop (z f)- , RPureConstrained Backprop as- , RecApplicative as- , Reifies s W- )+pattern BV ::+ ( Generic (z f)+ , Generic (z (BVar s))+ , E.BVGroup s as (Rep (z f)) (Rep (z (BVar s)))+ , Backprop (Rep (z f) ())+ , Backprop (z f)+ , RPureConstrained Backprop as+ , RecApplicative as+ , Reifies s W+ ) #if MIN_VERSION_base(4,10,0) => z (BVar s) -- ^ 'BVar's of fields -> BVar s (z f) -- ^ 'BVar' of combined value@@ -1022,7 +1081,7 @@ => z (BVar s) -> BVar s (z f) #endif-pattern BV v <- (splitBV->v)+pattern BV v <- (splitBV -> v) where BV = joinBV #if MIN_VERSION_base(4,10,0)
src/Numeric/Backprop/Class.hs view
@@ -1,1074 +1,1146 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DefaultSignatures #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE EmptyCase #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}---- |--- Module : Numeric.Backprop.Class--- Copyright : (c) Justin Le 2023--- License : BSD3------ Maintainer : justin@jle.im--- Stability : experimental--- Portability : non-portable------ Provides the 'Backprop' typeclass, a class for values that can be used--- for backpropagation.------ This class replaces the old (version 0.1) API relying on 'Num'.------ @since 0.2.0.0--module Numeric.Backprop.Class (- -- * Backpropagatable types- Backprop(..)- -- * Derived methods- , zeroNum, addNum, oneNum- , zeroVec, addVec, oneVec, zeroVecNum, oneVecNum- , zeroFunctor, addIsList, addAsList, oneFunctor- , genericZero, genericAdd, genericOne- -- * Newtype- , ABP(..), NumBP(..), NumVec(..)- -- * Generics- , GZero, GAdd, GOne- ) where--import Control.Applicative-import Control.DeepSeq-import Control.Monad-import Data.Coerce-import Data.Complex-import Data.Data-import Data.Foldable hiding (toList)-import Data.Functor.Compose-import Data.Functor.Identity-import Data.List.NonEmpty (NonEmpty(..))-import Data.Monoid-import Data.Ratio-import Data.Vinyl-import Data.Vinyl.ARec-import Data.Vinyl.TypeLevel-import Data.Void-import Data.Word-import GHC.Exts-import GHC.Generics-import Numeric.Natural-import qualified Control.Arrow as Arr-import qualified Data.Functor.Product as DFP-import qualified Data.IntMap as IM-import qualified Data.Map as M-import qualified Data.Semigroup as SG-import qualified Data.Sequence as Seq-import qualified Data.Vector as V-import qualified Data.Vector.Generic as VG-import qualified Data.Vector.Primitive as VP-import qualified Data.Vector.Storable as VS-import qualified Data.Vector.Unboxed as VU-import qualified Data.Vinyl.Functor as V-import qualified Data.Vinyl.XRec as V---- | Class of values that can be backpropagated in general.------ For instances of 'Num', these methods can be given by 'zeroNum',--- 'addNum', and 'oneNum'. There are also generic options given in--- "Numeric.Backprop.Class" for functors, 'IsList' instances, and 'Generic'--- instances.------ @--- instance 'Backprop' 'Double' where--- 'zero' = 'zeroNum'--- 'add' = 'addNum'--- 'one' = 'oneNum'--- @------ If you leave the body of an instance declaration blank, GHC Generics--- will be used to derive instances if the type has a single constructor--- and each field is an instance of 'Backprop'.------ To ensure that backpropagation works in a sound way, should obey the--- laws:------ [/identity/]------ * @'add' x ('zero' y) = x@------ * @'add' ('zero' x) y = y@------ Also implies preservation of information, making @'zipWith' ('+')@ an--- illegal implementation for lists and vectors.------ This is only expected to be true up to potential "extra zeroes" in @x@--- and @y@ in the result.------ [/commutativity/]------ * @'add' x y = 'add' y x@------ [/associativity/]------ * @'add' x ('add' y z) = 'add' ('add' x y) z@------ [/idempotence/]------ * @'zero' '.' 'zero' = 'zero'@------ * @'one' '.' 'one' = 'one'@------ [/unital/]------ * @'one' = 'gradBP' 'id'@------ Note that not all values in the backpropagation process needs all of--- these methods: Only the "final result" needs 'one', for example. These--- are all grouped under one typeclass for convenience in defining--- instances, and also to talk about sensible laws. For fine-grained--- control, use the "explicit" versions of library functions (for example,--- in "Numeric.Backprop.Explicit") instead of 'Backprop' based ones.------ This typeclass replaces the reliance on 'Num' of the previous API--- (v0.1). 'Num' is strictly more powerful than 'Backprop', and is--- a stronger constraint on types than is necessary for proper--- backpropagating. In particular, 'fromInteger' is a problem for many--- types, preventing useful backpropagation for lists, variable-length--- vectors (like "Data.Vector") and variable-size matrices from linear--- algebra libraries like /hmatrix/ and /accelerate/.------ @since 0.2.0.0-class Backprop a where- -- | "Zero out" all components of a value. For scalar values, this- -- should just be @'const' 0@. For vectors and matrices, this should- -- set all components to zero, the additive identity.- --- -- Should be idempotent:- --- -- * @'zero' '.' 'zero' = 'zero'@- --- -- Should be as /lazy/ as possible. This behavior is observed for- -- all instances provided by this library.- --- -- See 'zeroNum' for a pre-built definition for instances of 'Num' and- -- 'zeroFunctor' for a definition for instances of 'Functor'. If left- -- blank, will automatically be 'genericZero', a pre-built definition- -- for instances of 'GHC.Generic' whose fields are all themselves- -- instances of 'Backprop'.- zero :: a -> a- -- | Add together two values of a type. To combine contributions of- -- gradients, so should be information-preserving:- --- -- * @'add' x ('zero' y) = x@- --- -- * @'add' ('zero' x) y = y@- --- -- Should be as /strict/ as possible. This behavior is observed for- -- all instances provided by this library.- --- -- See 'addNum' for a pre-built definition for instances of 'Num' and- -- 'addIsList' for a definition for instances of 'IsList'. If left- -- blank, will automatically be 'genericAdd', a pre-built definition- -- for instances of 'GHC.Generic' with one constructor whose fields are- -- all themselves instances of 'Backprop'.- add :: a -> a -> a- -- | "One" all components of a value. For scalar values, this should- -- just be @'const' 1@. For vectors and matrices, this should set all- -- components to one, the multiplicative identity.- --- -- As the library uses it, the most important law is:- --- -- * @'one' = 'gradBP' 'id'@- --- -- That is, @'one' x@ is the gradient of the identity function with- -- respect to its input.- --- -- Ideally should be idempotent:- --- -- * @'one' '.' 'one' = 'one'@- --- -- Should be as /lazy/ as possible. This behavior is observed for- -- all instances provided by this library.- --- -- See 'oneNum' for a pre-built definition for instances of 'Num' and- -- 'oneFunctor' for a definition for instances of 'Functor'. If left- -- blank, will automatically be 'genericOne', a pre-built definition- -- for instances of 'GHC.Generic' whose fields are all themselves- -- instances of 'Backprop'.- one :: a -> a-- default zero :: (Generic a, GZero (Rep a)) => a -> a- zero = genericZero- {-# INLINE zero #-}- default add :: (Generic a, GAdd (Rep a)) => a -> a -> a- add = genericAdd- {-# INLINE add #-}- default one :: (Generic a, GOne (Rep a)) => a -> a- one = genericOne- {-# INLINE one #-}---- | 'zero' using GHC Generics; works if all fields are instances of--- 'Backprop'.-genericZero :: (Generic a, GZero (Rep a)) => a -> a-genericZero = to . gzero . from-{-# INLINE genericZero #-}---- | 'add' using GHC Generics; works if all fields are instances of--- 'Backprop', but only for values with single constructors.-genericAdd :: (Generic a, GAdd (Rep a)) => a -> a -> a-genericAdd x y = to $ gadd (from x) (from y)-{-# INLINE genericAdd #-}---- | 'one' using GHC Generics; works if all fields are instaces of--- 'Backprop'.-genericOne :: (Generic a, GOne (Rep a)) => a -> a-genericOne = to . gone . from-{-# INLINE genericOne #-}---- | 'zero' for instances of 'Num'.------ Is lazy in its argument.-zeroNum :: Num a => a -> a-zeroNum _ = 0-{-# INLINE zeroNum #-}---- | 'add' for instances of 'Num'.-addNum :: Num a => a -> a -> a-addNum = (+)-{-# INLINE addNum #-}---- | 'one' for instances of 'Num'.------ Is lazy in its argument.-oneNum :: Num a => a -> a-oneNum _ = 1-{-# INLINE oneNum #-}---- | 'zero' for instances of 'VG.Vector'.-zeroVec :: (VG.Vector v a, Backprop a) => v a -> v a-zeroVec = VG.map zero-{-# INLINE zeroVec #-}---- | 'add' for instances of 'VG.Vector'. Automatically pads the end of the--- shorter vector with zeroes.-addVec :: (VG.Vector v a, Backprop a) => v a -> v a -> v a-addVec x y = case compare lX lY of- LT -> let (y1,y2) = VG.splitAt (lY - lX) y- in VG.zipWith add x y1 VG.++ y2- EQ -> VG.zipWith add x y- GT -> let (x1,x2) = VG.splitAt (lX - lY) x- in VG.zipWith add x1 y VG.++ x2- where- lX = VG.length x- lY = VG.length y---- | 'one' for instances of 'VG.Vector'.-oneVec :: (VG.Vector v a, Backprop a) => v a -> v a-oneVec = VG.map one-{-# INLINE oneVec #-}---- | 'zero' for instances of 'VG.Vector' when the contained type is an--- instance of 'Num'. Is potentially more performant than 'zeroVec' when--- the vectors are larger.------ See 'NumVec' for a 'Backprop' instance for 'VG.Vector' instances that--- uses this for 'zero'.------ @since 0.2.4.0-zeroVecNum :: (VG.Vector v a, Num a) => v a -> v a-zeroVecNum = flip VG.replicate 0 . VG.length-{-# INLINE zeroVecNum #-}---- | 'one' for instances of 'VG.Vector' when the contained type is an--- instance of 'Num'. Is potentially more performant than 'oneVec' when--- the vectors are larger.------ See 'NumVec' for a 'Backprop' instance for 'VG.Vector' instances that--- uses this for 'one'.------ @since 0.2.4.0-oneVecNum :: (VG.Vector v a, Num a) => v a -> v a-oneVecNum = flip VG.replicate 1 . VG.length-{-# INLINE oneVecNum #-}---- | 'zero' for 'Functor' instances.-zeroFunctor :: (Functor f, Backprop a) => f a -> f a-zeroFunctor = fmap zero-{-# INLINE zeroFunctor #-}---- | 'add' for instances of 'IsList'. Automatically pads the end of the--- "shorter" value with zeroes.-addIsList :: (IsList a, Backprop (Item a)) => a -> a -> a-addIsList = addAsList toList fromList-{-# INLINE addIsList #-}---- | 'add' for types that are isomorphic to a list.--- Automatically pads the end of the "shorter" value with zeroes.-addAsList- :: Backprop b- => (a -> [b]) -- ^ convert to list (should form isomorphism)- -> ([b] -> a) -- ^ convert from list (should form isomorphism)- -> a- -> a- -> a-addAsList f g x y = g $ go (f x) (f y)- where- go = \case- [] -> id- o@(x':xs) -> \case- [] -> o- y':ys -> add x' y' : go xs ys---- | 'one' for instances of 'Functor'.-oneFunctor :: (Functor f, Backprop a) => f a -> f a-oneFunctor = fmap one-{-# INLINE oneFunctor #-}---- | A newtype wrapper over an instance of 'Num' that gives a free--- 'Backprop' instance.------ Useful for things like /DerivingVia/, or for avoiding orphan instances.------ @since 0.2.1.0-newtype NumBP a = NumBP { runNumBP :: a }- deriving (Show, Read, Eq, Ord, Typeable, Data, Generic, Functor, Foldable, Traversable, Num, Fractional, Floating)--instance NFData a => NFData (NumBP a)--instance Applicative NumBP where- pure = NumBP- {-# INLINE pure #-}- f <*> x = NumBP $ (runNumBP f) (runNumBP x)- {-# INLINE (<*>) #-}--instance Monad NumBP where- return = NumBP- {-# INLINE return #-}- x >>= f = f (runNumBP x)- {-# INLINE (>>=) #-}--instance Num a => Backprop (NumBP a) where- zero = coerce (zeroNum :: a -> a)- {-# INLINE zero #-}- add = coerce (addNum :: a -> a -> a)- {-# INLINE add #-}- one = coerce (oneNum :: a -> a)- {-# INLINE one #-}---- | Newtype wrapper around a @v a@ for @'VG.Vector' v a@, that gives--- a more efficient 'Backprop' instance for /long/ vectors when @a@ is an--- instance of 'Num'. The normal 'Backprop' instance for vectors will map--- 'zero' or 'one' over all items; this instance will completely ignore the--- contents of the original vector and instead produce a new vector of the--- same length, with all @0@ or @1@ using the 'Num' instance of @a@--- (essentially using 'zeroVecNum' and 'oneVecNum' instead of 'zeroVec' and--- 'oneVec').------ 'add' is essentially the same as normal, but using '+' instead of the--- type's 'add'.------ @since 0.2.4.0-newtype NumVec v a = NumVec { runNumVec :: v a }- deriving (Show, Read, Eq, Ord, Typeable, Data, Generic, Functor, Applicative, Monad, Alternative, MonadPlus, Foldable, Traversable)--instance NFData (v a) => NFData (NumVec v a)--instance (VG.Vector v a, Num a) => Backprop (NumVec v a) where- zero = coerce $ zeroVecNum @v @a- add (NumVec x) (NumVec y) = NumVec $ case compare lX lY of- LT -> let (y1,y2) = VG.splitAt (lY - lX) y- in VG.zipWith (+) x y1 VG.++ y2- EQ -> VG.zipWith (+) x y- GT -> let (x1,x2) = VG.splitAt (lX - lY) x- in VG.zipWith (+) x1 y VG.++ x2- where- lX = VG.length x- lY = VG.length y- one = coerce $ oneVecNum @v @a---- | A newtype wrapper over an @f a@ for @'Applicative' f@ that gives--- a free 'Backprop' instance (as well as 'Num' etc. instances).------ Useful for performing backpropagation over functions that require some--- monadic context (like 'IO') to perform.------ @since 0.2.1.0-newtype ABP f a = ABP { runABP :: f a }- deriving (Show, Read, Eq, Ord, Typeable, Data, Generic, Functor, Applicative, Monad, Alternative, MonadPlus, Foldable, Traversable)--instance NFData (f a) => NFData (ABP f a)--instance (Applicative f, Backprop a) => Backprop (ABP f a) where- zero = fmap zero- {-# INLINE zero #-}- add = liftA2 add- {-# INLINE add #-}- one = fmap one- {-# INLINE one #-}--instance (Applicative f, Num a) => Num (ABP f a) where- (+) = liftA2 (+)- {-# INLINE (+) #-}- (-) = liftA2 (-)- {-# INLINE (-) #-}- (*) = liftA2 (*)- {-# INLINE (*) #-}- negate = fmap negate- {-# INLINE negate #-}- abs = fmap abs- {-# INLINE abs #-}- signum = fmap signum- {-# INLINE signum #-}- fromInteger = pure . fromInteger- {-# INLINE fromInteger #-}--instance (Applicative f, Fractional a) => Fractional (ABP f a) where- (/) = liftA2 (/)- {-# INLINE (/) #-}- recip = fmap recip- {-# INLINE recip #-}- fromRational = pure . fromRational- {-# INLINE fromRational #-}--instance (Applicative f, Floating a) => Floating (ABP f a) where- pi = pure pi- {-# INLINE pi #-}- exp = fmap exp- {-# INLINE exp #-}- log = fmap log- {-# INLINE log #-}- sqrt = fmap sqrt- {-# INLINE sqrt #-}- (**) = liftA2 (**)- {-# INLINE (**) #-}- logBase = liftA2 logBase- {-# INLINE logBase #-}- sin = fmap sin- {-# INLINE sin #-}- cos = fmap cos- {-# INLINE cos #-}- tan = fmap tan- {-# INLINE tan #-}- asin = fmap asin- {-# INLINE asin #-}- acos = fmap acos- {-# INLINE acos #-}- atan = fmap atan- {-# INLINE atan #-}- sinh = fmap sinh- {-# INLINE sinh #-}- cosh = fmap cosh- {-# INLINE cosh #-}- tanh = fmap tanh- {-# INLINE tanh #-}- asinh = fmap asinh- {-# INLINE asinh #-}- acosh = fmap acosh- {-# INLINE acosh #-}- atanh = fmap atanh- {-# INLINE atanh #-}----- | Helper class for automatically deriving 'zero' using GHC Generics.-class GZero f where- gzero :: f t -> f t--instance Backprop a => GZero (K1 i a) where- gzero (K1 x) = K1 (zero x)- {-# INLINE gzero #-}--instance (GZero f, GZero g) => GZero (f :*: g) where- gzero (x :*: y) = gzero x :*: gzero y- {-# INLINE gzero #-}--instance (GZero f, GZero g) => GZero (f :+: g) where- gzero (L1 x) = L1 (gzero x)- gzero (R1 x) = R1 (gzero x)- {-# INLINE gzero #-}--instance GZero V1 where- gzero = \case {}- {-# INLINE gzero #-}--instance GZero U1 where- gzero _ = U1- {-# INLINE gzero #-}--instance GZero f => GZero (M1 i c f) where- gzero (M1 x) = M1 (gzero x)- {-# INLINE gzero #-}--instance GZero f => GZero (f :.: g) where- gzero (Comp1 x) = Comp1 (gzero x)- {-# INLINE gzero #-}----- | Helper class for automatically deriving 'add' using GHC Generics.-class GAdd f where- gadd :: f t -> f t -> f t--instance Backprop a => GAdd (K1 i a) where- gadd (K1 x) (K1 y) = K1 (add x y)- {-# INLINE gadd #-}--instance (GAdd f, GAdd g) => GAdd (f :*: g) where- gadd (x1 :*: y1) (x2 :*: y2) = x3 :*: y3- where- !x3 = gadd x1 x2- !y3 = gadd y1 y2- {-# INLINE gadd #-}--instance GAdd V1 where- gadd = \case {}- {-# INLINE gadd #-}--instance GAdd U1 where- gadd _ _ = U1- {-# INLINE gadd #-}--instance GAdd f => GAdd (M1 i c f) where- gadd (M1 x) (M1 y) = M1 (gadd x y)- {-# INLINE gadd #-}--instance GAdd f => GAdd (f :.: g) where- gadd (Comp1 x) (Comp1 y) = Comp1 (gadd x y)- {-# INLINE gadd #-}----- | Helper class for automatically deriving 'one' using GHC Generics.-class GOne f where- gone :: f t -> f t--instance Backprop a => GOne (K1 i a) where- gone (K1 x) = K1 (one x)- {-# INLINE gone #-}--instance (GOne f, GOne g) => GOne (f :*: g) where- gone (x :*: y) = gone x :*: gone y- {-# INLINE gone #-}--instance (GOne f, GOne g) => GOne (f :+: g) where- gone (L1 x) = L1 (gone x)- gone (R1 x) = R1 (gone x)- {-# INLINE gone #-}--instance GOne V1 where- gone = \case {}- {-# INLINE gone #-}--instance GOne U1 where- gone _ = U1- {-# INLINE gone #-}--instance GOne f => GOne (M1 i c f) where- gone (M1 x) = M1 (gone x)- {-# INLINE gone #-}--instance GOne f => GOne (f :.: g) where- gone (Comp1 x) = Comp1 (gone x)- {-# INLINE gone #-}--instance Backprop Int where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}--instance Backprop Integer where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}---- | @since 0.2.1.0-instance Backprop Natural where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}---- | @since 0.2.2.0-instance Backprop Word8 where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}---- | @since 0.2.2.0-instance Backprop Word where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}---- | @since 0.2.2.0-instance Backprop Word16 where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}---- | @since 0.2.2.0-instance Backprop Word32 where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}---- | @since 0.2.2.0-instance Backprop Word64 where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}--instance Integral a => Backprop (Ratio a) where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}--instance RealFloat a => Backprop (Complex a) where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}--instance Backprop Float where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}--instance Backprop Double where- zero = zeroNum- {-# INLINE zero #-}- add = addNum- {-# INLINE add #-}- one = oneNum- {-# INLINE one #-}--instance Backprop a => Backprop (V.Vector a) where- zero = zeroVec- {-# INLINE zero #-}- add = addVec- {-# INLINE add #-}- one = oneVec- {-# INLINE one #-}--instance (VU.Unbox a, Backprop a) => Backprop (VU.Vector a) where- zero = zeroVec- {-# INLINE zero #-}- add = addVec- {-# INLINE add #-}- one = oneVec- {-# INLINE one #-}--instance (VS.Storable a, Backprop a) => Backprop (VS.Vector a) where- zero = zeroVec- {-# INLINE zero #-}- add = addVec- {-# INLINE add #-}- one = oneVec- {-# INLINE one #-}--instance (VP.Prim a, Backprop a) => Backprop (VP.Vector a) where- zero = zeroVec- {-# INLINE zero #-}- add = addVec- {-# INLINE add #-}- one = oneVec- {-# INLINE one #-}---- | 'add' assumes the shorter list has trailing zeroes, and the result has--- the length of the longest input.-instance Backprop a => Backprop [a] where- zero = zeroFunctor- {-# INLINE zero #-}- add = addIsList- {-# INLINE add #-}- one = oneFunctor- {-# INLINE one #-}---- | 'add' assumes the shorter list has trailing zeroes, and the result has--- the length of the longest input.-instance Backprop a => Backprop (NonEmpty a) where- zero = zeroFunctor- {-# INLINE zero #-}- add = addIsList- {-# INLINE add #-}- one = oneFunctor- {-# INLINE one #-}---- | 'add' assumes the shorter sequence has trailing zeroes, and the result--- has the length of the longest input.-instance Backprop a => Backprop (Seq.Seq a) where- zero = zeroFunctor- {-# INLINE zero #-}- add = addIsList- {-# INLINE add #-}- one = oneFunctor- {-# INLINE one #-}---- | 'Nothing' is treated the same as @'Just' 0@. However, 'zero', 'add',--- and 'one' preserve 'Nothing' if all inputs are also 'Nothing'.-instance Backprop a => Backprop (Maybe a) where- zero = zeroFunctor- {-# INLINE zero #-}- add x y = asum [ add <$> x <*> y- , x- , y- ]- {-# INLINE add #-}- one = oneFunctor- {-# INLINE one #-}---- | 'add' is strict, but 'zero' and 'one' are lazy in their arguments.-instance Backprop () where- zero _ = ()- add () () = ()- one _ = ()---- | 'add' is strict-instance (Backprop a, Backprop b) => Backprop (a, b) where- zero (x, y) = (zero x, zero y)- {-# INLINE zero #-}- add (x1, y1) (x2, y2) = (x3, y3)- where- !x3 = add x1 x2- !y3 = add y1 y2- {-# INLINE add #-}- one (x, y) = (one x, one y)- {-# INLINE one #-}---- | 'add' is strict-instance (Backprop a, Backprop b, Backprop c) => Backprop (a, b, c) where- zero (x, y, z) = (zero x, zero y, zero z)- {-# INLINE zero #-}- add (x1, y1, z1) (x2, y2, z2) = (x3, y3, z3)- where- !x3 = add x1 x2- !y3 = add y1 y2- !z3 = add z1 z2- {-# INLINE add #-}- one (x, y, z) = (one x, one y, one z)- {-# INLINE one #-}---- | 'add' is strict-instance (Backprop a, Backprop b, Backprop c, Backprop d) => Backprop (a, b, c, d) where- zero (x, y, z, w) = (zero x, zero y, zero z, zero w)- {-# INLINE zero #-}- add (x1, y1, z1, w1) (x2, y2, z2, w2) = (x3, y3, z3, w3)- where- !x3 = add x1 x2- !y3 = add y1 y2- !z3 = add z1 z2- !w3 = add w1 w2- {-# INLINE add #-}- one (x, y, z, w) = (one x, one y, one z, one w)- {-# INLINE one #-}---- | 'add' is strict-instance (Backprop a, Backprop b, Backprop c, Backprop d, Backprop e) => Backprop (a, b, c, d, e) where- zero (x, y, z, w, v) = (zero x, zero y, zero z, zero w, zero v)- {-# INLINE zero #-}- add (x1, y1, z1, w1, v1) (x2, y2, z2, w2, v2) = (x3, y3, z3, w3, v3)- where- !x3 = add x1 x2- !y3 = add y1 y2- !z3 = add z1 z2- !w3 = add w1 w2- !v3 = add v1 v2- {-# INLINE add #-}- one (x, y, z, w, v) = (one x, one y, one z, one w, one v)- {-# INLINE one #-}--instance Backprop a => Backprop (Identity a) where- zero = coerce (zero @a)- add = coerce (add @a)- one = coerce (one @a)--instance Backprop (Proxy a) where- zero _ = Proxy- {-# INLINE zero #-}- add _ _ = Proxy- {-# INLINE add #-}- one _ = Proxy- {-# INLINE one #-}---- | @since 0.2.2.0-instance Backprop w => Backprop (Const w a) where- zero = coerce (zero @w)- add = coerce (add @w)- one = coerce (one @w)--instance Backprop Void where- zero = \case {}- {-# INLINE zero #-}- add = \case {}- {-# INLINE add #-}- one = \case {}- {-# INLINE one #-}---- | 'zero' and 'one' replace all current values, and 'add' merges keys--- from both maps, adding in the case of double-occurrences.-instance (Backprop a, Ord k) => Backprop (M.Map k a) where- zero = zeroFunctor- {-# INLINE zero #-}- add = M.unionWith add- {-# INLINE add #-}- one = oneFunctor- {-# INLINE one #-}---- | 'zero' and 'one' replace all current values, and 'add' merges keys--- from both maps, adding in the case of double-occurrences.-instance (Backprop a) => Backprop (IM.IntMap a) where- zero = zeroFunctor- {-# INLINE zero #-}- add = IM.unionWith add- {-# INLINE add #-}- one = oneFunctor- {-# INLINE one #-}---- | @since 0.2.2.0-instance Backprop a => Backprop (K1 i a p) where- zero = coerce (zero @a)- add = coerce (add @a)- one = coerce (one @a)---- | @since 0.2.2.0-instance Backprop (f p) => Backprop (M1 i c f p) where- zero = coerce (zero @(f p))- add = coerce (add @(f p))- one = coerce (one @(f p))---- | @since 0.2.2.0-instance (Backprop (f p), Backprop (g p)) => Backprop ((f :*: g) p)---- | @since 0.2.6.3-instance (Backprop (f (g a))) => Backprop ((f :.: g) a) where- zero = coerce (zero @(f (g a)))- add = coerce (add @(f (g a)))- one = coerce (one @(f (g a)))---- | @since 0.2.2.0-instance Backprop (V1 p)---- | @since 0.2.2.0-instance Backprop (U1 p)---- | @since 0.2.2.0-instance Backprop a => Backprop (Sum a) where- zero = coerce (zero @a)- add = coerce (add @a)- one = coerce (one @a)---- | @since 0.2.2.0-instance Backprop a => Backprop (Product a) where- zero = coerce (zero @a)- add = coerce (add @a)- one = coerce (one @a)--#if !MIN_VERSION_base(4,16,0)--- | @since 0.2.2.0-instance Backprop a => Backprop (SG.Option a) where- zero = coerce (zero @(Maybe a))- add = coerce (add @(Maybe a))- one = coerce (one @(Maybe a))-#endif---- | @since 0.2.2.0-instance Backprop a => Backprop (SG.First a) where- zero = coerce (zero @a)- add = coerce (add @a)- one = coerce (one @a)---- | @since 0.2.2.0-instance Backprop a => Backprop (SG.Last a) where- zero = coerce (zero @a)- add = coerce (add @a)- one = coerce (one @a)---- | @since 0.2.2.0-instance Backprop a => Backprop (First a) where- zero = coerce (zero @(Maybe a))- add = coerce (add @(Maybe a))- one = coerce (one @(Maybe a))---- | @since 0.2.2.0-instance Backprop a => Backprop (Data.Monoid.Last a) where- zero = coerce (zero @(Maybe a))- add = coerce (add @(Maybe a))- one = coerce (one @(Maybe a))---- | @since 0.2.2.0-instance Backprop a => Backprop (Dual a) where- zero = coerce (zero @a)- add = coerce (add @a)- one = coerce (one @a)---- | @since 0.2.2.0-instance (Backprop a, Backprop b) => Backprop (SG.Arg a b)---- | @since 0.2.2.0-instance (Backprop (f a), Backprop (g a)) => Backprop (DFP.Product f g a)---- | @since 0.2.2.0-instance Backprop (f (g a)) => Backprop (Compose f g a) where- zero = coerce (zero @(f (g a)))- add = coerce (add @(f (g a)))- one = coerce (one @(f (g a)))---- | 'add' adds together results; 'zero' and 'one' act on results.------ @since 0.2.2.0-instance Backprop a => Backprop (r -> a) where- zero = zeroFunctor- {-# INLINE zero #-}- add = liftA2 add- {-# INLINE add #-}- one = oneFunctor- {-# INLINE one #-}---- | @since 0.2.2.0-instance (Backprop a, Applicative m) => Backprop (Arr.Kleisli m r a) where- zero (Arr.Kleisli f) = Arr.Kleisli ((fmap . fmap) zero f)- {-# INLINE zero #-}- add (Arr.Kleisli f) (Arr.Kleisli g) = Arr.Kleisli $ \x ->- add <$> f x <*> g x- {-# INLINE add #-}- one (Arr.Kleisli f) = Arr.Kleisli ((fmap . fmap) one f)- {-# INLINE one #-}---- | @since 0.2.6.3-instance (ReifyConstraint Backprop f rs, RMap rs, RApply rs) => Backprop (Rec f rs) where- zero = rmap (\case V.Compose (Dict x) -> zero x)- . reifyConstraint @Backprop- {-# INLINE zero #-}- add xs = rzipWith (\x -> \case V.Compose (Dict y) -> add x y) xs- . reifyConstraint @Backprop- {-# INLINE add #-}- one = rmap (\case V.Compose (Dict x) -> one x)- . reifyConstraint @Backprop- {-# INLINE one #-}---- | @since 0.2.6.3-#if MIN_VERSION_vinyl(0,14,2)-instance (ReifyConstraint Backprop f rs, RMap rs, RApply rs, RecApplicative rs, NatToInt (RLength rs), RPureConstrained (IndexableField rs) rs, ToARec rs)-#else-instance (ReifyConstraint Backprop f rs, RMap rs, RApply rs, RecApplicative rs, NatToInt (RLength rs), RPureConstrained (IndexableField rs) rs)-#endif- => Backprop (ARec f rs) where- zero = toARec . zero . fromARec- {-# INLINE zero #-}- add xs ys = toARec $ add (fromARec xs) (fromARec ys)- {-# INLINE add #-}- one = toARec . zero . fromARec- {-# INLINE one #-}---- | @since 0.2.6.3-instance (ReifyConstraint Backprop f rs, RMap rs, RApply rs, VS.Storable (Rec f rs))- => Backprop (SRec f rs) where- zero = toSRec . zero . fromSRec- {-# INLINE zero #-}- add xs ys = toSRec $ add (fromSRec xs) (fromSRec ys)- {-# INLINE add #-}- one = toSRec . zero . fromSRec- {-# INLINE one #-}---- | @since 0.2.6.3-instance (ReifyConstraint Backprop f rs, RMap rs, RApply rs, IsoXRec f rs)- => Backprop (XRec f rs) where- zero = toXRec . zero . fromXRec- {-# INLINE zero #-}- add xs ys = toXRec $ add (fromXRec xs) (fromXRec ys)- {-# INLINE add #-}- one = toXRec . zero . fromXRec- {-# INLINE one #-}---- | @since 0.2.6.3-instance Backprop a => Backprop (V.Identity a) where- zero = coerce (zero @a)- add = coerce (add @a)- one = coerce (one @a)---- | @since 0.2.6.3-instance Backprop a => Backprop (V.Thunk a) where- zero (V.Thunk x) = V.Thunk (zero x)- add (V.Thunk x) (V.Thunk y) = V.Thunk (add x y)- one (V.Thunk x) = V.Thunk (one x)---- | @since 0.2.6.3-instance Backprop (op (f a) (g a)) => Backprop (V.Lift op f g a) where- zero = coerce (zero @(op (f a) (g a)))- add = coerce (add @(op (f a) (g a)))- one = coerce (one @(op (f a) (g a)))---- | @since 0.2.6.3-instance Backprop t => Backprop (V.ElField '(s, t)) where- zero (V.Field x) = V.Field (zero x)- add (V.Field x) (V.Field y) = V.Field (add x y)- one (V.Field x) = V.Field (one x)---- | @since 0.2.6.3-instance Backprop (f (g a)) => Backprop (V.Compose f g a) where- zero = coerce (zero @(f (g a)))- add = coerce (add @(f (g a)))- one = coerce (one @(f (g a)))---- | @since 0.2.6.3-instance Backprop w => Backprop (V.Const w a) where- zero = coerce (zero @w)- add = coerce (add @w)- one = coerce (one @w)---- | @since 0.2.6.3-instance Backprop (V.HKD t a) => Backprop (V.XData t a) where- zero = coerce (zero @(V.HKD t a))- add = coerce (add @(V.HKD t a))- one = coerce (one @(V.HKD t a))---- | @since 0.2.6.3-instance Backprop (SField field) where- zero _ = SField- add _ _ = SField- one _ = SField---- | @since 0.2.6.3-instance Backprop (Label field) where- zero _ = Label- add _ _ = Label- one _ = Label+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DefaultSignatures #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE EmptyCase #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++-- |+-- Module : Numeric.Backprop.Class+-- Copyright : (c) Justin Le 2023+-- License : BSD3+--+-- Maintainer : justin@jle.im+-- Stability : experimental+-- Portability : non-portable+--+-- Provides the 'Backprop' typeclass, a class for values that can be used+-- for backpropagation.+--+-- This class replaces the old (version 0.1) API relying on 'Num'.+--+-- @since 0.2.0.0+module Numeric.Backprop.Class (+ -- * Backpropagatable types+ Backprop (..),++ -- * Derived methods+ zeroNum,+ addNum,+ oneNum,+ zeroVec,+ addVec,+ oneVec,+ zeroVecNum,+ oneVecNum,+ zeroFunctor,+ addIsList,+ addAsList,+ oneFunctor,+ genericZero,+ genericAdd,+ genericOne,++ -- * Newtype+ ABP (..),+ NumBP (..),+ NumVec (..),++ -- * Generics+ GZero,+ GAdd,+ GOne,+) where++import Control.Applicative+import qualified Control.Arrow as Arr+import Control.DeepSeq+import Control.Monad+import Data.Coerce+import Data.Complex+import Data.Data+import Data.Functor.Compose+import Data.Functor.Identity+import qualified Data.Functor.Product as DFP+import qualified Data.IntMap as IM+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.Map as M+import Data.Monoid+import Data.Ratio+import qualified Data.Semigroup as SG+import qualified Data.Sequence as Seq+import qualified Data.Vector as V+import qualified Data.Vector.Generic as VG+import qualified Data.Vector.Primitive as VP+import qualified Data.Vector.Storable as VS+import qualified Data.Vector.Unboxed as VU+import Data.Vinyl+import Data.Vinyl.ARec+import qualified Data.Vinyl.Functor as V+import Data.Vinyl.TypeLevel+import qualified Data.Vinyl.XRec as V+import Data.Void+import Data.Word+import GHC.Exts+import GHC.Generics+import Numeric.Natural++-- | Class of values that can be backpropagated in general.+--+-- For instances of 'Num', these methods can be given by 'zeroNum',+-- 'addNum', and 'oneNum'. There are also generic options given in+-- "Numeric.Backprop.Class" for functors, 'IsList' instances, and 'Generic'+-- instances.+--+-- @+-- instance 'Backprop' 'Double' where+-- 'zero' = 'zeroNum'+-- 'add' = 'addNum'+-- 'one' = 'oneNum'+-- @+--+-- If you leave the body of an instance declaration blank, GHC Generics+-- will be used to derive instances if the type has a single constructor+-- and each field is an instance of 'Backprop'.+--+-- To ensure that backpropagation works in a sound way, should obey the+-- laws:+--+-- [/identity/]+--+-- * @'add' x ('zero' y) = x@+--+-- * @'add' ('zero' x) y = y@+--+-- Also implies preservation of information, making @'zipWith' ('+')@ an+-- illegal implementation for lists and vectors.+--+-- This is only expected to be true up to potential "extra zeroes" in @x@+-- and @y@ in the result.+--+-- [/commutativity/]+--+-- * @'add' x y = 'add' y x@+--+-- [/associativity/]+--+-- * @'add' x ('add' y z) = 'add' ('add' x y) z@+--+-- [/idempotence/]+--+-- * @'zero' '.' 'zero' = 'zero'@+--+-- * @'one' '.' 'one' = 'one'@+--+-- [/unital/]+--+-- * @'one' = 'gradBP' 'id'@+--+-- Note that not all values in the backpropagation process needs all of+-- these methods: Only the "final result" needs 'one', for example. These+-- are all grouped under one typeclass for convenience in defining+-- instances, and also to talk about sensible laws. For fine-grained+-- control, use the "explicit" versions of library functions (for example,+-- in "Numeric.Backprop.Explicit") instead of 'Backprop' based ones.+--+-- This typeclass replaces the reliance on 'Num' of the previous API+-- (v0.1). 'Num' is strictly more powerful than 'Backprop', and is+-- a stronger constraint on types than is necessary for proper+-- backpropagating. In particular, 'fromInteger' is a problem for many+-- types, preventing useful backpropagation for lists, variable-length+-- vectors (like "Data.Vector") and variable-size matrices from linear+-- algebra libraries like /hmatrix/ and /accelerate/.+--+-- @since 0.2.0.0+class Backprop a where+ -- | "Zero out" all components of a value. For scalar values, this+ -- should just be @'const' 0@. For vectors and matrices, this should+ -- set all components to zero, the additive identity.+ --+ -- Should be idempotent:+ --+ -- * @'zero' '.' 'zero' = 'zero'@+ --+ -- Should be as /lazy/ as possible. This behavior is observed for+ -- all instances provided by this library.+ --+ -- See 'zeroNum' for a pre-built definition for instances of 'Num' and+ -- 'zeroFunctor' for a definition for instances of 'Functor'. If left+ -- blank, will automatically be 'genericZero', a pre-built definition+ -- for instances of 'GHC.Generic' whose fields are all themselves+ -- instances of 'Backprop'.+ zero :: a -> a++ -- | Add together two values of a type. To combine contributions of+ -- gradients, so should be information-preserving:+ --+ -- * @'add' x ('zero' y) = x@+ --+ -- * @'add' ('zero' x) y = y@+ --+ -- Should be as /strict/ as possible. This behavior is observed for+ -- all instances provided by this library.+ --+ -- See 'addNum' for a pre-built definition for instances of 'Num' and+ -- 'addIsList' for a definition for instances of 'IsList'. If left+ -- blank, will automatically be 'genericAdd', a pre-built definition+ -- for instances of 'GHC.Generic' with one constructor whose fields are+ -- all themselves instances of 'Backprop'.+ add :: a -> a -> a++ -- | "One" all components of a value. For scalar values, this should+ -- just be @'const' 1@. For vectors and matrices, this should set all+ -- components to one, the multiplicative identity.+ --+ -- As the library uses it, the most important law is:+ --+ -- * @'one' = 'gradBP' 'id'@+ --+ -- That is, @'one' x@ is the gradient of the identity function with+ -- respect to its input.+ --+ -- Ideally should be idempotent:+ --+ -- * @'one' '.' 'one' = 'one'@+ --+ -- Should be as /lazy/ as possible. This behavior is observed for+ -- all instances provided by this library.+ --+ -- See 'oneNum' for a pre-built definition for instances of 'Num' and+ -- 'oneFunctor' for a definition for instances of 'Functor'. If left+ -- blank, will automatically be 'genericOne', a pre-built definition+ -- for instances of 'GHC.Generic' whose fields are all themselves+ -- instances of 'Backprop'.+ one :: a -> a++ default zero :: (Generic a, GZero (Rep a)) => a -> a+ zero = genericZero+ {-# INLINE zero #-}+ default add :: (Generic a, GAdd (Rep a)) => a -> a -> a+ add = genericAdd+ {-# INLINE add #-}+ default one :: (Generic a, GOne (Rep a)) => a -> a+ one = genericOne+ {-# INLINE one #-}++-- | 'zero' using GHC Generics; works if all fields are instances of+-- 'Backprop'.+genericZero :: (Generic a, GZero (Rep a)) => a -> a+genericZero = to . gzero . from+{-# INLINE genericZero #-}++-- | 'add' using GHC Generics; works if all fields are instances of+-- 'Backprop', but only for values with single constructors.+genericAdd :: (Generic a, GAdd (Rep a)) => a -> a -> a+genericAdd x y = to $ gadd (from x) (from y)+{-# INLINE genericAdd #-}++-- | 'one' using GHC Generics; works if all fields are instaces of+-- 'Backprop'.+genericOne :: (Generic a, GOne (Rep a)) => a -> a+genericOne = to . gone . from+{-# INLINE genericOne #-}++-- | 'zero' for instances of 'Num'.+--+-- Is lazy in its argument.+zeroNum :: Num a => a -> a+zeroNum _ = 0+{-# INLINE zeroNum #-}++-- | 'add' for instances of 'Num'.+addNum :: Num a => a -> a -> a+addNum = (+)+{-# INLINE addNum #-}++-- | 'one' for instances of 'Num'.+--+-- Is lazy in its argument.+oneNum :: Num a => a -> a+oneNum _ = 1+{-# INLINE oneNum #-}++-- | 'zero' for instances of 'VG.Vector'.+zeroVec :: (VG.Vector v a, Backprop a) => v a -> v a+zeroVec = VG.map zero+{-# INLINE zeroVec #-}++-- | 'add' for instances of 'VG.Vector'. Automatically pads the end of the+-- shorter vector with zeroes.+addVec :: (VG.Vector v a, Backprop a) => v a -> v a -> v a+addVec x y = case compare lX lY of+ LT ->+ let (y1, y2) = VG.splitAt (lY - lX) y+ in VG.zipWith add x y1 VG.++ y2+ EQ -> VG.zipWith add x y+ GT ->+ let (x1, x2) = VG.splitAt (lX - lY) x+ in VG.zipWith add x1 y VG.++ x2+ where+ lX = VG.length x+ lY = VG.length y++-- | 'one' for instances of 'VG.Vector'.+oneVec :: (VG.Vector v a, Backprop a) => v a -> v a+oneVec = VG.map one+{-# INLINE oneVec #-}++-- | 'zero' for instances of 'VG.Vector' when the contained type is an+-- instance of 'Num'. Is potentially more performant than 'zeroVec' when+-- the vectors are larger.+--+-- See 'NumVec' for a 'Backprop' instance for 'VG.Vector' instances that+-- uses this for 'zero'.+--+-- @since 0.2.4.0+zeroVecNum :: (VG.Vector v a, Num a) => v a -> v a+zeroVecNum = flip VG.replicate 0 . VG.length+{-# INLINE zeroVecNum #-}++-- | 'one' for instances of 'VG.Vector' when the contained type is an+-- instance of 'Num'. Is potentially more performant than 'oneVec' when+-- the vectors are larger.+--+-- See 'NumVec' for a 'Backprop' instance for 'VG.Vector' instances that+-- uses this for 'one'.+--+-- @since 0.2.4.0+oneVecNum :: (VG.Vector v a, Num a) => v a -> v a+oneVecNum = flip VG.replicate 1 . VG.length+{-# INLINE oneVecNum #-}++-- | 'zero' for 'Functor' instances.+zeroFunctor :: (Functor f, Backprop a) => f a -> f a+zeroFunctor = fmap zero+{-# INLINE zeroFunctor #-}++-- | 'add' for instances of 'IsList'. Automatically pads the end of the+-- "shorter" value with zeroes.+addIsList :: (IsList a, Backprop (Item a)) => a -> a -> a+addIsList = addAsList toList fromList+{-# INLINE addIsList #-}++-- | 'add' for types that are isomorphic to a list.+-- Automatically pads the end of the "shorter" value with zeroes.+addAsList ::+ Backprop b =>+ -- | convert to list (should form isomorphism)+ (a -> [b]) ->+ -- | convert from list (should form isomorphism)+ ([b] -> a) ->+ a ->+ a ->+ a+addAsList f g x y = g $ go (f x) (f y)+ where+ go = \case+ [] -> id+ o@(x' : xs) -> \case+ [] -> o+ y' : ys -> add x' y' : go xs ys++-- | 'one' for instances of 'Functor'.+oneFunctor :: (Functor f, Backprop a) => f a -> f a+oneFunctor = fmap one+{-# INLINE oneFunctor #-}++-- | A newtype wrapper over an instance of 'Num' that gives a free+-- 'Backprop' instance.+--+-- Useful for things like /DerivingVia/, or for avoiding orphan instances.+--+-- @since 0.2.1.0+newtype NumBP a = NumBP {runNumBP :: a}+ deriving+ ( Show+ , Read+ , Eq+ , Ord+ , Typeable+ , Data+ , Generic+ , Functor+ , Foldable+ , Traversable+ , Num+ , Fractional+ , Floating+ )++instance NFData a => NFData (NumBP a)++instance Applicative NumBP where+ pure = NumBP+ {-# INLINE pure #-}+ f <*> x = NumBP $ runNumBP f (runNumBP x)+ {-# INLINE (<*>) #-}++instance Monad NumBP where+ x >>= f = f (runNumBP x)+ {-# INLINE (>>=) #-}++instance Num a => Backprop (NumBP a) where+ zero = coerce (zeroNum :: a -> a)+ {-# INLINE zero #-}+ add = coerce (addNum :: a -> a -> a)+ {-# INLINE add #-}+ one = coerce (oneNum :: a -> a)+ {-# INLINE one #-}++-- | Newtype wrapper around a @v a@ for @'VG.Vector' v a@, that gives+-- a more efficient 'Backprop' instance for /long/ vectors when @a@ is an+-- instance of 'Num'. The normal 'Backprop' instance for vectors will map+-- 'zero' or 'one' over all items; this instance will completely ignore the+-- contents of the original vector and instead produce a new vector of the+-- same length, with all @0@ or @1@ using the 'Num' instance of @a@+-- (essentially using 'zeroVecNum' and 'oneVecNum' instead of 'zeroVec' and+-- 'oneVec').+--+-- 'add' is essentially the same as normal, but using '+' instead of the+-- type's 'add'.+--+-- @since 0.2.4.0+newtype NumVec v a = NumVec {runNumVec :: v a}+ deriving+ ( Show+ , Read+ , Eq+ , Ord+ , Typeable+ , Data+ , Generic+ , Functor+ , Applicative+ , Monad+ , Alternative+ , MonadPlus+ , Foldable+ , Traversable+ )++instance NFData (v a) => NFData (NumVec v a)++instance (VG.Vector v a, Num a) => Backprop (NumVec v a) where+ zero = coerce $ zeroVecNum @v @a+ add (NumVec x) (NumVec y) = NumVec $ case compare lX lY of+ LT ->+ let (y1, y2) = VG.splitAt (lY - lX) y+ in VG.zipWith (+) x y1 VG.++ y2+ EQ -> VG.zipWith (+) x y+ GT ->+ let (x1, x2) = VG.splitAt (lX - lY) x+ in VG.zipWith (+) x1 y VG.++ x2+ where+ lX = VG.length x+ lY = VG.length y+ one = coerce $ oneVecNum @v @a++-- | A newtype wrapper over an @f a@ for @'Applicative' f@ that gives+-- a free 'Backprop' instance (as well as 'Num' etc. instances).+--+-- Useful for performing backpropagation over functions that require some+-- monadic context (like 'IO') to perform.+--+-- @since 0.2.1.0+newtype ABP f a = ABP {runABP :: f a}+ deriving+ ( Show+ , Read+ , Eq+ , Ord+ , Typeable+ , Data+ , Generic+ , Functor+ , Applicative+ , Monad+ , Alternative+ , MonadPlus+ , Foldable+ , Traversable+ )++instance NFData (f a) => NFData (ABP f a)++instance (Applicative f, Backprop a) => Backprop (ABP f a) where+ zero = fmap zero+ {-# INLINE zero #-}+ add = liftA2 add+ {-# INLINE add #-}+ one = fmap one+ {-# INLINE one #-}++instance (Applicative f, Num a) => Num (ABP f a) where+ (+) = liftA2 (+)+ {-# INLINE (+) #-}+ (-) = liftA2 (-)+ {-# INLINE (-) #-}+ (*) = liftA2 (*)+ {-# INLINE (*) #-}+ negate = fmap negate+ {-# INLINE negate #-}+ abs = fmap abs+ {-# INLINE abs #-}+ signum = fmap signum+ {-# INLINE signum #-}+ fromInteger = pure . fromInteger+ {-# INLINE fromInteger #-}++instance (Applicative f, Fractional a) => Fractional (ABP f a) where+ (/) = liftA2 (/)+ {-# INLINE (/) #-}+ recip = fmap recip+ {-# INLINE recip #-}+ fromRational = pure . fromRational+ {-# INLINE fromRational #-}++instance (Applicative f, Floating a) => Floating (ABP f a) where+ pi = pure pi+ {-# INLINE pi #-}+ exp = fmap exp+ {-# INLINE exp #-}+ log = fmap log+ {-# INLINE log #-}+ sqrt = fmap sqrt+ {-# INLINE sqrt #-}+ (**) = liftA2 (**)+ {-# INLINE (**) #-}+ logBase = liftA2 logBase+ {-# INLINE logBase #-}+ sin = fmap sin+ {-# INLINE sin #-}+ cos = fmap cos+ {-# INLINE cos #-}+ tan = fmap tan+ {-# INLINE tan #-}+ asin = fmap asin+ {-# INLINE asin #-}+ acos = fmap acos+ {-# INLINE acos #-}+ atan = fmap atan+ {-# INLINE atan #-}+ sinh = fmap sinh+ {-# INLINE sinh #-}+ cosh = fmap cosh+ {-# INLINE cosh #-}+ tanh = fmap tanh+ {-# INLINE tanh #-}+ asinh = fmap asinh+ {-# INLINE asinh #-}+ acosh = fmap acosh+ {-# INLINE acosh #-}+ atanh = fmap atanh+ {-# INLINE atanh #-}++-- | Helper class for automatically deriving 'zero' using GHC Generics.+class GZero f where+ gzero :: f t -> f t++instance Backprop a => GZero (K1 i a) where+ gzero (K1 x) = K1 (zero x)+ {-# INLINE gzero #-}++instance (GZero f, GZero g) => GZero (f :*: g) where+ gzero (x :*: y) = gzero x :*: gzero y+ {-# INLINE gzero #-}++instance (GZero f, GZero g) => GZero (f :+: g) where+ gzero (L1 x) = L1 (gzero x)+ gzero (R1 x) = R1 (gzero x)+ {-# INLINE gzero #-}++instance GZero V1 where+ gzero = \case {}+ {-# INLINE gzero #-}++instance GZero U1 where+ gzero _ = U1+ {-# INLINE gzero #-}++instance GZero f => GZero (M1 i c f) where+ gzero (M1 x) = M1 (gzero x)+ {-# INLINE gzero #-}++instance GZero f => GZero (f :.: g) where+ gzero (Comp1 x) = Comp1 (gzero x)+ {-# INLINE gzero #-}++-- | Helper class for automatically deriving 'add' using GHC Generics.+class GAdd f where+ gadd :: f t -> f t -> f t++instance Backprop a => GAdd (K1 i a) where+ gadd (K1 x) (K1 y) = K1 (add x y)+ {-# INLINE gadd #-}++instance (GAdd f, GAdd g) => GAdd (f :*: g) where+ gadd (x1 :*: y1) (x2 :*: y2) = x3 :*: y3+ where+ !x3 = gadd x1 x2+ !y3 = gadd y1 y2+ {-# INLINE gadd #-}++instance GAdd V1 where+ gadd = \case {}+ {-# INLINE gadd #-}++instance GAdd U1 where+ gadd _ _ = U1+ {-# INLINE gadd #-}++instance GAdd f => GAdd (M1 i c f) where+ gadd (M1 x) (M1 y) = M1 (gadd x y)+ {-# INLINE gadd #-}++instance GAdd f => GAdd (f :.: g) where+ gadd (Comp1 x) (Comp1 y) = Comp1 (gadd x y)+ {-# INLINE gadd #-}++-- | Helper class for automatically deriving 'one' using GHC Generics.+class GOne f where+ gone :: f t -> f t++instance Backprop a => GOne (K1 i a) where+ gone (K1 x) = K1 (one x)+ {-# INLINE gone #-}++instance (GOne f, GOne g) => GOne (f :*: g) where+ gone (x :*: y) = gone x :*: gone y+ {-# INLINE gone #-}++instance (GOne f, GOne g) => GOne (f :+: g) where+ gone (L1 x) = L1 (gone x)+ gone (R1 x) = R1 (gone x)+ {-# INLINE gone #-}++instance GOne V1 where+ gone = \case {}+ {-# INLINE gone #-}++instance GOne U1 where+ gone _ = U1+ {-# INLINE gone #-}++instance GOne f => GOne (M1 i c f) where+ gone (M1 x) = M1 (gone x)+ {-# INLINE gone #-}++instance GOne f => GOne (f :.: g) where+ gone (Comp1 x) = Comp1 (gone x)+ {-# INLINE gone #-}++instance Backprop Int where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++instance Backprop Integer where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++-- | @since 0.2.1.0+instance Backprop Natural where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++-- | @since 0.2.2.0+instance Backprop Word8 where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++-- | @since 0.2.2.0+instance Backprop Word where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++-- | @since 0.2.2.0+instance Backprop Word16 where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++-- | @since 0.2.2.0+instance Backprop Word32 where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++-- | @since 0.2.2.0+instance Backprop Word64 where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++instance Integral a => Backprop (Ratio a) where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++instance RealFloat a => Backprop (Complex a) where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++instance Backprop Float where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++instance Backprop Double where+ zero = zeroNum+ {-# INLINE zero #-}+ add = addNum+ {-# INLINE add #-}+ one = oneNum+ {-# INLINE one #-}++instance Backprop a => Backprop (V.Vector a) where+ zero = zeroVec+ {-# INLINE zero #-}+ add = addVec+ {-# INLINE add #-}+ one = oneVec+ {-# INLINE one #-}++instance (VU.Unbox a, Backprop a) => Backprop (VU.Vector a) where+ zero = zeroVec+ {-# INLINE zero #-}+ add = addVec+ {-# INLINE add #-}+ one = oneVec+ {-# INLINE one #-}++instance (VS.Storable a, Backprop a) => Backprop (VS.Vector a) where+ zero = zeroVec+ {-# INLINE zero #-}+ add = addVec+ {-# INLINE add #-}+ one = oneVec+ {-# INLINE one #-}++instance (VP.Prim a, Backprop a) => Backprop (VP.Vector a) where+ zero = zeroVec+ {-# INLINE zero #-}+ add = addVec+ {-# INLINE add #-}+ one = oneVec+ {-# INLINE one #-}++-- | 'add' assumes the shorter list has trailing zeroes, and the result has+-- the length of the longest input.+instance Backprop a => Backprop [a] where+ zero = zeroFunctor+ {-# INLINE zero #-}+ add = addIsList+ {-# INLINE add #-}+ one = oneFunctor+ {-# INLINE one #-}++-- | 'add' assumes the shorter list has trailing zeroes, and the result has+-- the length of the longest input.+instance Backprop a => Backprop (NonEmpty a) where+ zero = zeroFunctor+ {-# INLINE zero #-}+ add = addIsList+ {-# INLINE add #-}+ one = oneFunctor+ {-# INLINE one #-}++-- | 'add' assumes the shorter sequence has trailing zeroes, and the result+-- has the length of the longest input.+instance Backprop a => Backprop (Seq.Seq a) where+ zero = zeroFunctor+ {-# INLINE zero #-}+ add = addIsList+ {-# INLINE add #-}+ one = oneFunctor+ {-# INLINE one #-}++-- | 'Nothing' is treated the same as @'Just' 0@. However, 'zero', 'add',+-- and 'one' preserve 'Nothing' if all inputs are also 'Nothing'.+instance Backprop a => Backprop (Maybe a) where+ zero = zeroFunctor+ {-# INLINE zero #-}+ add x y = (add <$> x <*> y) <|> x <|> y+ {-# INLINE add #-}+ one = oneFunctor+ {-# INLINE one #-}++-- | 'add' is strict, but 'zero' and 'one' are lazy in their arguments.+instance Backprop () where+ zero _ = ()+ add () () = ()+ one _ = ()++-- | 'add' is strict+instance (Backprop a, Backprop b) => Backprop (a, b) where+ zero (x, y) = (zero x, zero y)+ {-# INLINE zero #-}+ add (x1, y1) (x2, y2) = (x3, y3)+ where+ !x3 = add x1 x2+ !y3 = add y1 y2+ {-# INLINE add #-}+ one (x, y) = (one x, one y)+ {-# INLINE one #-}++-- | 'add' is strict+instance (Backprop a, Backprop b, Backprop c) => Backprop (a, b, c) where+ zero (x, y, z) = (zero x, zero y, zero z)+ {-# INLINE zero #-}+ add (x1, y1, z1) (x2, y2, z2) = (x3, y3, z3)+ where+ !x3 = add x1 x2+ !y3 = add y1 y2+ !z3 = add z1 z2+ {-# INLINE add #-}+ one (x, y, z) = (one x, one y, one z)+ {-# INLINE one #-}++-- | 'add' is strict+instance (Backprop a, Backprop b, Backprop c, Backprop d) => Backprop (a, b, c, d) where+ zero (x, y, z, w) = (zero x, zero y, zero z, zero w)+ {-# INLINE zero #-}+ add (x1, y1, z1, w1) (x2, y2, z2, w2) = (x3, y3, z3, w3)+ where+ !x3 = add x1 x2+ !y3 = add y1 y2+ !z3 = add z1 z2+ !w3 = add w1 w2+ {-# INLINE add #-}+ one (x, y, z, w) = (one x, one y, one z, one w)+ {-# INLINE one #-}++-- | 'add' is strict+instance (Backprop a, Backprop b, Backprop c, Backprop d, Backprop e) => Backprop (a, b, c, d, e) where+ zero (x, y, z, w, v) = (zero x, zero y, zero z, zero w, zero v)+ {-# INLINE zero #-}+ add (x1, y1, z1, w1, v1) (x2, y2, z2, w2, v2) = (x3, y3, z3, w3, v3)+ where+ !x3 = add x1 x2+ !y3 = add y1 y2+ !z3 = add z1 z2+ !w3 = add w1 w2+ !v3 = add v1 v2+ {-# INLINE add #-}+ one (x, y, z, w, v) = (one x, one y, one z, one w, one v)+ {-# INLINE one #-}++instance Backprop a => Backprop (Identity a) where+ zero = coerce (zero @a)+ add = coerce (add @a)+ one = coerce (one @a)++instance Backprop (Proxy a) where+ zero _ = Proxy+ {-# INLINE zero #-}+ add _ _ = Proxy+ {-# INLINE add #-}+ one _ = Proxy+ {-# INLINE one #-}++-- | @since 0.2.2.0+instance Backprop w => Backprop (Const w a) where+ zero = coerce (zero @w)+ add = coerce (add @w)+ one = coerce (one @w)++instance Backprop Void where+ zero = \case {}+ {-# INLINE zero #-}+ add = \case {}+ {-# INLINE add #-}+ one = \case {}+ {-# INLINE one #-}++-- | 'zero' and 'one' replace all current values, and 'add' merges keys+-- from both maps, adding in the case of double-occurrences.+instance (Backprop a, Ord k) => Backprop (M.Map k a) where+ zero = zeroFunctor+ {-# INLINE zero #-}+ add = M.unionWith add+ {-# INLINE add #-}+ one = oneFunctor+ {-# INLINE one #-}++-- | 'zero' and 'one' replace all current values, and 'add' merges keys+-- from both maps, adding in the case of double-occurrences.+instance Backprop a => Backprop (IM.IntMap a) where+ zero = zeroFunctor+ {-# INLINE zero #-}+ add = IM.unionWith add+ {-# INLINE add #-}+ one = oneFunctor+ {-# INLINE one #-}++-- | @since 0.2.2.0+instance Backprop a => Backprop (K1 i a p) where+ zero = coerce (zero @a)+ add = coerce (add @a)+ one = coerce (one @a)++-- | @since 0.2.2.0+instance Backprop (f p) => Backprop (M1 i c f p) where+ zero = coerce (zero @(f p))+ add = coerce (add @(f p))+ one = coerce (one @(f p))++-- | @since 0.2.2.0+instance (Backprop (f p), Backprop (g p)) => Backprop ((f :*: g) p)++-- | @since 0.2.6.3+instance Backprop (f (g a)) => Backprop ((f :.: g) a) where+ zero = coerce (zero @(f (g a)))+ add = coerce (add @(f (g a)))+ one = coerce (one @(f (g a)))++-- | @since 0.2.2.0+instance Backprop (V1 p)++-- | @since 0.2.2.0+instance Backprop (U1 p)++-- | @since 0.2.2.0+instance Backprop a => Backprop (Sum a) where+ zero = coerce (zero @a)+ add = coerce (add @a)+ one = coerce (one @a)++-- | @since 0.2.2.0+instance Backprop a => Backprop (Product a) where+ zero = coerce (zero @a)+ add = coerce (add @a)+ one = coerce (one @a)++#if !MIN_VERSION_base(4,16,0)+-- | @since 0.2.2.0+instance Backprop a => Backprop (SG.Option a) where+ zero = coerce (zero @(Maybe a))+ add = coerce (add @(Maybe a))+ one = coerce (one @(Maybe a))+#endif++-- | @since 0.2.2.0+instance Backprop a => Backprop (SG.First a) where+ zero = coerce (zero @a)+ add = coerce (add @a)+ one = coerce (one @a)++-- | @since 0.2.2.0+instance Backprop a => Backprop (SG.Last a) where+ zero = coerce (zero @a)+ add = coerce (add @a)+ one = coerce (one @a)++-- | @since 0.2.2.0+instance Backprop a => Backprop (First a) where+ zero = coerce (zero @(Maybe a))+ add = coerce (add @(Maybe a))+ one = coerce (one @(Maybe a))++-- | @since 0.2.2.0+instance Backprop a => Backprop (Data.Monoid.Last a) where+ zero = coerce (zero @(Maybe a))+ add = coerce (add @(Maybe a))+ one = coerce (one @(Maybe a))++-- | @since 0.2.2.0+instance Backprop a => Backprop (Dual a) where+ zero = coerce (zero @a)+ add = coerce (add @a)+ one = coerce (one @a)++-- | @since 0.2.2.0+instance (Backprop a, Backprop b) => Backprop (SG.Arg a b)++-- | @since 0.2.2.0+instance (Backprop (f a), Backprop (g a)) => Backprop (DFP.Product f g a)++-- | @since 0.2.2.0+instance Backprop (f (g a)) => Backprop (Compose f g a) where+ zero = coerce (zero @(f (g a)))+ add = coerce (add @(f (g a)))+ one = coerce (one @(f (g a)))++-- | 'add' adds together results; 'zero' and 'one' act on results.+--+-- @since 0.2.2.0+instance Backprop a => Backprop (r -> a) where+ zero = zeroFunctor+ {-# INLINE zero #-}+ add = liftA2 add+ {-# INLINE add #-}+ one = oneFunctor+ {-# INLINE one #-}++-- | @since 0.2.2.0+instance (Backprop a, Applicative m) => Backprop (Arr.Kleisli m r a) where+ zero (Arr.Kleisli f) = Arr.Kleisli ((fmap . fmap) zero f)+ {-# INLINE zero #-}+ add (Arr.Kleisli f) (Arr.Kleisli g) = Arr.Kleisli $ \x ->+ add <$> f x <*> g x+ {-# INLINE add #-}+ one (Arr.Kleisli f) = Arr.Kleisli ((fmap . fmap) one f)+ {-# INLINE one #-}++-- | @since 0.2.6.3+instance (ReifyConstraint Backprop f rs, RMap rs, RApply rs) => Backprop (Rec f rs) where+ zero =+ rmap (\case V.Compose (Dict x) -> zero x)+ . reifyConstraint @Backprop+ {-# INLINE zero #-}+ add xs =+ rzipWith (\x -> \case V.Compose (Dict y) -> add x y) xs+ . reifyConstraint @Backprop+ {-# INLINE add #-}+ one =+ rmap (\case V.Compose (Dict x) -> one x)+ . reifyConstraint @Backprop+ {-# INLINE one #-}++-- | @since 0.2.6.3+#if MIN_VERSION_vinyl(0,14,2)+instance (ReifyConstraint Backprop f rs, RMap rs, RApply rs, RecApplicative rs, NatToInt (RLength rs), RPureConstrained (IndexableField rs) rs, ToARec rs)+ => Backprop (ARec f rs) where+ zero = toARec . zero . fromARec+ {-# INLINE zero #-}+ add xs ys = toARec $ add (fromARec xs) (fromARec ys)+ {-# INLINE add #-}+ one = toARec . zero . fromARec+ {-# INLINE one #-}+#else+instance (ReifyConstraint Backprop f rs, RMap rs, RApply rs, RecApplicative rs, NatToInt (RLength rs), RPureConstrained (IndexableField rs) rs)+ => Backprop (ARec f rs) where+ zero = toARec . zero . fromARec+ {-# INLINE zero #-}+ add xs ys = toARec $ add (fromARec xs) (fromARec ys)+ {-# INLINE add #-}+ one = toARec . zero . fromARec+ {-# INLINE one #-}+#endif++-- | @since 0.2.6.3+instance+ (ReifyConstraint Backprop f rs, RMap rs, RApply rs, VS.Storable (Rec f rs)) =>+ Backprop (SRec f rs)+ where+ zero = toSRec . zero . fromSRec+ {-# INLINE zero #-}+ add xs ys = toSRec $ add (fromSRec xs) (fromSRec ys)+ {-# INLINE add #-}+ one = toSRec . zero . fromSRec+ {-# INLINE one #-}++-- | @since 0.2.6.3+instance+ (ReifyConstraint Backprop f rs, RMap rs, RApply rs, IsoXRec f rs) =>+ Backprop (XRec f rs)+ where+ zero = toXRec . zero . fromXRec+ {-# INLINE zero #-}+ add xs ys = toXRec $ add (fromXRec xs) (fromXRec ys)+ {-# INLINE add #-}+ one = toXRec . zero . fromXRec+ {-# INLINE one #-}++-- | @since 0.2.6.3+instance Backprop a => Backprop (V.Identity a) where+ zero = coerce (zero @a)+ add = coerce (add @a)+ one = coerce (one @a)++-- | @since 0.2.6.3+instance Backprop a => Backprop (V.Thunk a) where+ zero (V.Thunk x) = V.Thunk (zero x)+ add (V.Thunk x) (V.Thunk y) = V.Thunk (add x y)+ one (V.Thunk x) = V.Thunk (one x)++-- | @since 0.2.6.3+instance Backprop (op (f a) (g a)) => Backprop (V.Lift op f g a) where+ zero = coerce (zero @(op (f a) (g a)))+ add = coerce (add @(op (f a) (g a)))+ one = coerce (one @(op (f a) (g a)))++-- | @since 0.2.6.3+instance Backprop t => Backprop (V.ElField '(s, t)) where+ zero (V.Field x) = V.Field (zero x)+ add (V.Field x) (V.Field y) = V.Field (add x y)+ one (V.Field x) = V.Field (one x)++-- | @since 0.2.6.3+instance Backprop (f (g a)) => Backprop (V.Compose f g a) where+ zero = coerce (zero @(f (g a)))+ add = coerce (add @(f (g a)))+ one = coerce (one @(f (g a)))++-- | @since 0.2.6.3+instance Backprop w => Backprop (V.Const w a) where+ zero = coerce (zero @w)+ add = coerce (add @w)+ one = coerce (one @w)++-- | @since 0.2.6.3+instance Backprop (V.HKD t a) => Backprop (V.XData t a) where+ zero = coerce (zero @(V.HKD t a))+ add = coerce (add @(V.HKD t a))+ one = coerce (one @(V.HKD t a))++-- | @since 0.2.6.3+instance Backprop (SField field) where+ zero _ = SField+ add _ _ = SField+ one _ = SField++-- | @since 0.2.6.3+instance Backprop (Label field) where+ zero _ = Label+ add _ _ = Label+ one _ = Label
src/Numeric/Backprop/Explicit.hs view
@@ -1,18 +1,16 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE EmptyCase #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE EmptyCase #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_HADDOCK not-home #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_HADDOCK not-home #-} -- | -- Module : Numeric.Backprop.Explicit@@ -41,62 +39,122 @@ -- reflect changes in underlying implementation. -- -- @since 0.2.0.0- module Numeric.Backprop.Explicit (- -- * Types- BVar, W, Backprop(..), ABP(..), NumBP(..)- -- * Explicit 'zero', 'add', and 'one'- , ZeroFunc(..), zfNum, zfNums, zeroFunc, zeroFuncs, zfFunctor- , AddFunc(..), afNum, afNums, addFunc, addFuncs- , OneFunc(..), ofNum, ofNums, oneFunc, oneFuncs, ofFunctor- -- * Running- , backprop, evalBP, gradBP, backpropWith- -- ** Multiple inputs- , evalBP0- , backprop2, evalBP2, gradBP2, backpropWith2- , backpropN, evalBPN, gradBPN, backpropWithN, RPureConstrained- -- * Manipulating 'BVar'- , constVar, auto, coerceVar- , viewVar, setVar, overVar- , sequenceVar, collectVar- , previewVar, toListOfVar- -- ** With Isomorphisms- , isoVar, isoVar2, isoVar3, isoVarN- -- ** With 'Op's- , liftOp- , liftOp1, liftOp2, liftOp3- -- ** Generics- , splitBV- , joinBV- , BVGroup- -- * 'Op'- , Op(..)- -- ** Creation- , op0, opConst, idOp- , bpOp- -- *** Giving gradients directly- , op1, op2, op3- -- *** From Isomorphisms- , opCoerce, opTup, opIso, opIsoN, opLens- -- *** No gradients- , noGrad1, noGrad- -- * Utility- , Reifies- ) where+ -- * Types+ BVar,+ W,+ Backprop (..),+ ABP (..),+ NumBP (..), -import Data.Bifunctor-import Data.Functor.Identity-import Data.Reflection-import Data.Type.Util-import Data.Vinyl.Core-import Data.Vinyl.TypeLevel-import GHC.Generics as G-import Lens.Micro-import Numeric.Backprop.Class-import Numeric.Backprop.Internal-import Numeric.Backprop.Op-import Unsafe.Coerce+ -- * Explicit 'zero', 'add', and 'one'+ ZeroFunc (..),+ zfNum,+ zfNums,+ zeroFunc,+ zeroFuncs,+ zfFunctor,+ AddFunc (..),+ afNum,+ afNums,+ addFunc,+ addFuncs,+ OneFunc (..),+ ofNum,+ ofNums,+ oneFunc,+ oneFuncs,+ ofFunctor, + -- * Running+ backprop,+ evalBP,+ gradBP,+ backpropWith,++ -- ** Multiple inputs+ evalBP0,+ backprop2,+ evalBP2,+ gradBP2,+ backpropWith2,+ backpropN,+ evalBPN,+ gradBPN,+ backpropWithN,+ RPureConstrained,++ -- * Manipulating 'BVar'+ constVar,+ auto,+ coerceVar,+ viewVar,+ setVar,+ overVar,+ sequenceVar,+ collectVar,+ previewVar,+ toListOfVar,++ -- ** With Isomorphisms+ isoVar,+ isoVar2,+ isoVar3,+ isoVarN,++ -- ** With 'Op's+ liftOp,+ liftOp1,+ liftOp2,+ liftOp3,++ -- ** Generics+ splitBV,+ joinBV,+ BVGroup,++ -- * 'Op'+ Op (..),++ -- ** Creation+ op0,+ opConst,+ idOp,+ bpOp,++ -- *** Giving gradients directly+ op1,+ op2,+ op3,++ -- *** From Isomorphisms+ opCoerce,+ opTup,+ opIso,+ opIsoN,+ opLens,++ -- *** No gradients+ noGrad1,+ noGrad,++ -- * Utility+ Reifies,+) where++import Data.Bifunctor+import Data.Functor.Identity+import Data.Reflection+import Data.Type.Util+import Data.Vinyl.Core+import Data.Vinyl.TypeLevel+import GHC.Generics as G+import Lens.Micro+import Numeric.Backprop.Class+import Numeric.Backprop.Internal+import Numeric.Backprop.Op+import Unsafe.Coerce+ -- | 'ZeroFunc's for every item in a type level list based on their -- 'Num' instances --@@ -161,42 +219,45 @@ {-# INLINE auto #-} -- | 'Numeric.Backprop.backpropN', but with explicit 'zero' and 'one'.-backpropN- :: forall as b. ()- => Rec ZeroFunc as- -> OneFunc b- -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> (b, Rec Identity as)+backpropN ::+ forall as b.+ () =>+ Rec ZeroFunc as ->+ OneFunc b ->+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ (b, Rec Identity as) backpropN zfs ob f xs = case backpropWithN zfs f xs of- (y, g) -> (y, g (runOF ob y))+ (y, g) -> (y, g (runOF ob y)) {-# INLINE backpropN #-} -- | 'Numeric.Backprop.backprop', but with explicit 'zero' and 'one'.-backprop- :: ZeroFunc a- -> OneFunc b- -> (forall s. Reifies s W => BVar s a -> BVar s b)- -> a- -> (b, a)-backprop zfa ofb f = second (\case Identity x :& RNil -> x)- . backpropN (zfa :& RNil) ofb (f . (\case x :& RNil -> x))- . (:& RNil)- . Identity+backprop ::+ ZeroFunc a ->+ OneFunc b ->+ (forall s. Reifies s W => BVar s a -> BVar s b) ->+ a ->+ (b, a)+backprop zfa ofb f =+ second (\case Identity x :& RNil -> x)+ . backpropN (zfa :& RNil) ofb (f . (\case x :& RNil -> x))+ . (:& RNil)+ . Identity {-# INLINE backprop #-} -- | 'Numeric.Backprop.backpropWith', but with explicit 'zero'. -- -- Note that argument order changed in v0.2.4.-backpropWith- :: ZeroFunc a- -> (forall s. Reifies s W => BVar s a -> BVar s b)- -> a- -> (b, b -> a)-backpropWith zfa f = second ((\case Identity x :& RNil -> x) .)- . backpropWithN (zfa :& RNil) (f . (\case x :& RNil -> x))- . (:& RNil)- . Identity+backpropWith ::+ ZeroFunc a ->+ (forall s. Reifies s W => BVar s a -> BVar s b) ->+ a ->+ (b, b -> a)+backpropWith zfa f =+ second ((\case Identity x :& RNil -> x) .)+ . backpropWithN (zfa :& RNil) (f . (\case x :& RNil -> x))+ . (:& RNil)+ . Identity {-# INLINE backpropWith #-} -- | 'evalBP' but with no arguments. Useful when everything is just given@@ -214,42 +275,45 @@ -- -- See documentation of 'Numeric.Backprop.backprop' for more information. evalBP :: (forall s. Reifies s W => BVar s a -> BVar s b) -> a -> b-evalBP f = evalBPN (f . (\case x :& RNil -> x)) . (:& RNil) . Identity+evalBP f = evalBPN (f . (\case x :& RNil -> x)) . (:& RNil) . Identity {-# INLINE evalBP #-} -- | 'Numeric.Backprop.gradBP', but with explicit 'zero' and 'one'.-gradBP- :: ZeroFunc a- -> OneFunc b- -> (forall s. Reifies s W => BVar s a -> BVar s b)- -> a- -> a+gradBP ::+ ZeroFunc a ->+ OneFunc b ->+ (forall s. Reifies s W => BVar s a -> BVar s b) ->+ a ->+ a gradBP zfa ofb f = snd . backprop zfa ofb f {-# INLINE gradBP #-} -- | 'Numeric.Backprop.gradBP', Nbut with explicit 'zero' and 'one'.-gradBPN- :: Rec ZeroFunc as- -> OneFunc b- -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> Rec Identity as+gradBPN ::+ Rec ZeroFunc as ->+ OneFunc b ->+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ Rec Identity as gradBPN zfas ofb f = snd . backpropN zfas ofb f {-# INLINE gradBPN #-} -- | 'Numeric.Backprop.backprop2', but with explicit 'zero' and 'one'.-backprop2- :: ZeroFunc a- -> ZeroFunc b- -> OneFunc c- -> (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> (c, (a, b))-backprop2 zfa zfb ofc f x y = second (\(Identity dx :& Identity dy :& RNil) -> (dx, dy)) $- backpropN (zfa :& zfb :& RNil) ofc- (\(x' :& y' :& RNil) -> f x' y')- (Identity x :& Identity y :& RNil)+backprop2 ::+ ZeroFunc a ->+ ZeroFunc b ->+ OneFunc c ->+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ (c, (a, b))+backprop2 zfa zfb ofc f x y =+ second (\(Identity dx :& Identity dy :& RNil) -> (dx, dy)) $+ backpropN+ (zfa :& zfb :& RNil)+ ofc+ (\(x' :& y' :& RNil) -> f x' y')+ (Identity x :& Identity y :& RNil) {-# INLINE backprop2 #-} -- | 'Numeric.Backprop.backpropWith2', but with explicit 'zero'.@@ -257,114 +321,118 @@ -- Note that argument order changed in v0.2.4. -- -- @since 0.2.0.0-backpropWith2- :: ZeroFunc a- -> ZeroFunc b- -> (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> (c, c -> (a, b))-backpropWith2 zfa zfb f x y = second ((\(Identity dx :& Identity dy :& RNil) -> (dx, dy)) .) $- backpropWithN (zfa :& zfb :& RNil)- (\(x' :& y' :& RNil) -> f x' y')- (Identity x :& Identity y :& RNil)+backpropWith2 ::+ ZeroFunc a ->+ ZeroFunc b ->+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ (c, c -> (a, b))+backpropWith2 zfa zfb f x y =+ second ((\(Identity dx :& Identity dy :& RNil) -> (dx, dy)) .) $+ backpropWithN+ (zfa :& zfb :& RNil)+ (\(x' :& y' :& RNil) -> f x' y')+ (Identity x :& Identity y :& RNil) {-# INLINE backpropWith2 #-} -- | 'evalBP' for a two-argument function. See -- 'Numeric.Backprop.backprop2' for notes.-evalBP2- :: (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> c-evalBP2 f x y = evalBPN (\(x' :& y' :& RNil) -> f x' y') $ Identity x- :& Identity y- :& RNil+evalBP2 ::+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ c+evalBP2 f x y =+ evalBPN (\(x' :& y' :& RNil) -> f x' y') $+ Identity x+ :& Identity y+ :& RNil {-# INLINE evalBP2 #-} -- | 'Numeric.Backprop.gradBP2' with explicit 'zero' and 'one'.-gradBP2- :: ZeroFunc a- -> ZeroFunc b- -> OneFunc c- -> (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> (a, b)+gradBP2 ::+ ZeroFunc a ->+ ZeroFunc b ->+ OneFunc c ->+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ (a, b) gradBP2 zfa zfb ofc f x = snd . backprop2 zfa zfb ofc f x {-# INLINE gradBP2 #-} -- | 'Numeric.Backprop.bpOp' with explicit 'zero'.-bpOp- :: Rec ZeroFunc as- -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Op as b+bpOp ::+ Rec ZeroFunc as ->+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Op as b bpOp zfs f = Op (backpropWithN zfs f) {-# INLINE bpOp #-} -- | 'Numeric.Backprop.overVar' with explicit 'add' and 'zero'. -- -- @since 0.2.4.0-overVar- :: Reifies s W- => AddFunc a- -> AddFunc b- -> ZeroFunc a- -> ZeroFunc b- -> Lens' b a- -> (BVar s a -> BVar s a)- -> BVar s b- -> BVar s b+overVar ::+ Reifies s W =>+ AddFunc a ->+ AddFunc b ->+ ZeroFunc a ->+ ZeroFunc b ->+ Lens' b a ->+ (BVar s a -> BVar s a) ->+ BVar s b ->+ BVar s b overVar afa afb zfa zfb l f x = setVar afa afb zfa l (f (viewVar afa zfb l x)) x {-# INLINE overVar #-} -- | 'Numeric.Backprop.isoVar' with explicit 'add' and 'zero'.-isoVar- :: Reifies s W- => AddFunc a- -> (a -> b)- -> (b -> a)- -> BVar s a- -> BVar s b+isoVar ::+ Reifies s W =>+ AddFunc a ->+ (a -> b) ->+ (b -> a) ->+ BVar s a ->+ BVar s b isoVar af f g = liftOp1 af (opIso f g) {-# INLINE isoVar #-} -- | 'Numeric.Backprop.isoVar2' with explicit 'add' and 'zero'.-isoVar2- :: Reifies s W- => AddFunc a- -> AddFunc b- -> (a -> b -> c)- -> (c -> (a, b))- -> BVar s a- -> BVar s b- -> BVar s c+isoVar2 ::+ Reifies s W =>+ AddFunc a ->+ AddFunc b ->+ (a -> b -> c) ->+ (c -> (a, b)) ->+ BVar s a ->+ BVar s b ->+ BVar s c isoVar2 afa afb f g = liftOp2 afa afb (opIso2 f g) {-# INLINE isoVar2 #-} -- | 'Numeric.Backprop.isoVar3' with explicit 'add' and 'zero'.-isoVar3- :: Reifies s W- => AddFunc a- -> AddFunc b- -> AddFunc c- -> (a -> b -> c -> d)- -> (d -> (a, b, c))- -> BVar s a- -> BVar s b- -> BVar s c- -> BVar s d+isoVar3 ::+ Reifies s W =>+ AddFunc a ->+ AddFunc b ->+ AddFunc c ->+ (a -> b -> c -> d) ->+ (d -> (a, b, c)) ->+ BVar s a ->+ BVar s b ->+ BVar s c ->+ BVar s d isoVar3 afa afb afc f g = liftOp3 afa afb afc (opIso3 f g) {-# INLINE isoVar3 #-} -- | 'Numeric.Backprop.isoVarN' with explicit 'add' and 'zero'.-isoVarN- :: Reifies s W- => Rec AddFunc as- -> (Rec Identity as -> b)- -> (b -> Rec Identity as)- -> Rec (BVar s) as- -> BVar s b+isoVarN ::+ Reifies s W =>+ Rec AddFunc as ->+ (Rec Identity as -> b) ->+ (b -> Rec Identity as) ->+ Rec (BVar s) as ->+ BVar s b isoVarN afs f g = liftOp afs (opIsoN f g) {-# INLINE isoVarN #-} @@ -379,132 +447,155 @@ -- -- @since 0.2.2.0 class BVGroup s as i o | o -> i, i -> as where- -- | Helper method for generically "splitting" 'BVar's out of- -- constructors inside a 'BVar'. See 'splitBV'.- gsplitBV :: Rec AddFunc as -> Rec ZeroFunc as -> BVar s (i ()) -> o ()- -- | Helper method for generically "joining" 'BVar's inside- -- a constructor into a 'BVar'. See 'joinBV'.- gjoinBV :: Rec AddFunc as -> Rec ZeroFunc as -> o () -> BVar s (i ())+ -- | Helper method for generically "splitting" 'BVar's out of+ -- constructors inside a 'BVar'. See 'splitBV'.+ gsplitBV :: Rec AddFunc as -> Rec ZeroFunc as -> BVar s (i ()) -> o () + -- | Helper method for generically "joining" 'BVar's inside+ -- a constructor into a 'BVar'. See 'joinBV'.+ gjoinBV :: Rec AddFunc as -> Rec ZeroFunc as -> o () -> BVar s (i ())+ instance BVGroup s '[] (K1 i a) (K1 i (BVar s a)) where- gsplitBV _ _ = K1 . coerceVar- {-# INLINE gsplitBV #-}- gjoinBV _ _ = coerceVar . unK1- {-# INLINE gjoinBV #-}+ gsplitBV _ _ = K1 . coerceVar+ {-# INLINE gsplitBV #-}+ gjoinBV _ _ = coerceVar . unK1+ {-# INLINE gjoinBV #-} -instance BVGroup s as i o- => BVGroup s as (M1 p c i) (M1 p c o) where- gsplitBV afs zfs = M1 . gsplitBV afs zfs . coerceVar @_ @(i ())- {-# INLINE gsplitBV #-}- gjoinBV afs zfs = coerceVar @(i ()) . gjoinBV afs zfs . unM1- {-# INLINE gjoinBV #-}+instance+ BVGroup s as i o =>+ BVGroup s as (M1 p c i) (M1 p c o)+ where+ gsplitBV afs zfs = M1 . gsplitBV afs zfs . coerceVar @_ @(i ())+ {-# INLINE gsplitBV #-}+ gjoinBV afs zfs = coerceVar @(i ()) . gjoinBV afs zfs . unM1+ {-# INLINE gjoinBV #-} instance BVGroup s '[] V1 V1 where- gsplitBV _ _ = unsafeCoerce- {-# INLINE gsplitBV #-}- gjoinBV _ _ = \case- {-# INLINE gjoinBV #-}+ gsplitBV _ _ = unsafeCoerce+ {-# INLINE gsplitBV #-}+ gjoinBV _ _ = \case {}+ {-# INLINE gjoinBV #-} instance BVGroup s '[] U1 U1 where- gsplitBV _ _ _ = U1- {-# INLINE gsplitBV #-}- gjoinBV _ _ _ = constVar U1- {-# INLINE gjoinBV #-}+ gsplitBV _ _ _ = U1+ {-# INLINE gsplitBV #-}+ gjoinBV _ _ _ = constVar U1+ {-# INLINE gjoinBV #-} -instance ( Reifies s W- , BVGroup s as i1 o1- , BVGroup s bs i2 o2- , cs ~ (as ++ bs)- , RecApplicative as- ) => BVGroup s (i1 () ': i2 () ': cs) (i1 :*: i2) (o1 :*: o2) where- gsplitBV (afa :& afb :& afs) (zfa :& zfb :& zfs) xy = x :*: y- where- (afas, afbs) = splitRec afs- (zfas, zfbs) = splitRec zfs- zfab = ZF $ \(xx :*: yy) -> runZF zfa xx :*: runZF zfb yy- x = gsplitBV afas zfas . viewVar afa zfab p1 $ xy- y = gsplitBV afbs zfbs . viewVar afb zfab p2 $ xy- {-# INLINE gsplitBV #-}- gjoinBV (afa :& afb :& afs) (_ :& _ :& zfs) (x :*: y)- = isoVar2 afa afb (:*:) unP- (gjoinBV afas zfas x)- (gjoinBV afbs zfbs y)- where- (afas, afbs) = splitRec afs- (zfas, zfbs) = splitRec zfs- unP (xx :*: yy) = (xx, yy)- {-# INLINE gjoinBV #-}+instance+ ( Reifies s W+ , BVGroup s as i1 o1+ , BVGroup s bs i2 o2+ , cs ~ (as ++ bs)+ , RecApplicative as+ ) =>+ BVGroup s (i1 () ': i2 () ': cs) (i1 :*: i2) (o1 :*: o2)+ where+ gsplitBV (afa :& afb :& afs) (zfa :& zfb :& zfs) xy = x :*: y+ where+ (afas, afbs) = splitRec afs+ (zfas, zfbs) = splitRec zfs+ zfab = ZF $ \(xx :*: yy) -> runZF zfa xx :*: runZF zfb yy+ x = gsplitBV afas zfas . viewVar afa zfab p1 $ xy+ y = gsplitBV afbs zfbs . viewVar afb zfab p2 $ xy+ {-# INLINE gsplitBV #-}+ gjoinBV (afa :& afb :& afs) (_ :& _ :& zfs) (x :*: y) =+ isoVar2+ afa+ afb+ (:*:)+ unP+ (gjoinBV afas zfas x)+ (gjoinBV afbs zfbs y)+ where+ (afas, afbs) = splitRec afs+ (zfas, zfbs) = splitRec zfs+ unP (xx :*: yy) = (xx, yy)+ {-# INLINE gjoinBV #-} -- | This instance is possible but it is not clear when it would be useful-instance ( Reifies s W- , BVGroup s as i1 o1- , BVGroup s bs i2 o2- , cs ~ (as ++ bs)- , RecApplicative as- ) => BVGroup s (i1 () ': i2 () ': cs) (i1 :+: i2) (o1 :+: o2) where- gsplitBV (afa :& afb :& afs) (zfa :& zfb :& zfs) xy =- case previewVar afa zf s1 xy of- Just x -> L1 $ gsplitBV afas zfas x- Nothing -> case previewVar afb zf s2 xy of- Just y -> R1 $ gsplitBV afbs zfbs y- Nothing -> error "Numeric.Backprop.gsplitBV: Internal error occurred"- where- zf = ZF $ \case- L1 xx -> L1 $ runZF zfa xx- R1 yy -> R1 $ runZF zfb yy- (afas, afbs) = splitRec afs- (zfas, zfbs) = splitRec zfs- {-# INLINE gsplitBV #-}- gjoinBV (afa :& afb :& afs) (zfa :& zfb :& zfs) = \case- L1 x -> liftOp1 afa (op1 (\xx -> (L1 xx, \case L1 d -> d; R1 _ -> runZF zfa xx)))- (gjoinBV afas zfas x)- R1 y -> liftOp1 afb (op1 (\yy -> (R1 yy, \case L1 _ -> runZF zfb yy; R1 d -> d)))- (gjoinBV afbs zfbs y)- where- (afas, afbs) = splitRec afs- (zfas, zfbs) = splitRec zfs- {-# INLINE gjoinBV #-}+instance+ ( Reifies s W+ , BVGroup s as i1 o1+ , BVGroup s bs i2 o2+ , cs ~ (as ++ bs)+ , RecApplicative as+ ) =>+ BVGroup s (i1 () ': i2 () ': cs) (i1 :+: i2) (o1 :+: o2)+ where+ gsplitBV (afa :& afb :& afs) (zfa :& zfb :& zfs) xy =+ case previewVar afa zf s1 xy of+ Just x -> L1 $ gsplitBV afas zfas x+ Nothing -> case previewVar afb zf s2 xy of+ Just y -> R1 $ gsplitBV afbs zfbs y+ Nothing -> error "Numeric.Backprop.gsplitBV: Internal error occurred"+ where+ zf = ZF $ \case+ L1 xx -> L1 $ runZF zfa xx+ R1 yy -> R1 $ runZF zfb yy+ (afas, afbs) = splitRec afs+ (zfas, zfbs) = splitRec zfs+ {-# INLINE gsplitBV #-}+ gjoinBV (afa :& afb :& afs) (zfa :& zfb :& zfs) = \case+ L1 x ->+ liftOp1+ afa+ (op1 (\xx -> (L1 xx, \case L1 d -> d; R1 _ -> runZF zfa xx)))+ (gjoinBV afas zfas x)+ R1 y ->+ liftOp1+ afb+ (op1 (\yy -> (R1 yy, \case L1 _ -> runZF zfb yy; R1 d -> d)))+ (gjoinBV afbs zfbs y)+ where+ (afas, afbs) = splitRec afs+ (zfas, zfbs) = splitRec zfs+ {-# INLINE gjoinBV #-} -- | 'Numeric.Backprop.splitBV' with explicit 'add' and 'zero'. -- -- @since 0.2.2.0-splitBV- :: forall z f s as.- ( Generic (z f)- , Generic (z (BVar s))- , BVGroup s as (Rep (z f)) (Rep (z (BVar s)))- , Reifies s W- )- => AddFunc (Rep (z f) ())- -> Rec AddFunc as- -> ZeroFunc (z f)- -> Rec ZeroFunc as- -> BVar s (z f) -- ^ 'BVar' of value- -> z (BVar s) -- ^ 'BVar's of fields+splitBV ::+ forall z f s as.+ ( Generic (z f)+ , Generic (z (BVar s))+ , BVGroup s as (Rep (z f)) (Rep (z (BVar s)))+ , Reifies s W+ ) =>+ AddFunc (Rep (z f) ()) ->+ Rec AddFunc as ->+ ZeroFunc (z f) ->+ Rec ZeroFunc as ->+ -- | 'BVar' of value+ BVar s (z f) ->+ -- | 'BVar's of fields+ z (BVar s) splitBV af afs zf zfs =- G.to- . gsplitBV afs zfs- . viewVar af zf (lens (from @(z f) @()) (const G.to))+ G.to+ . gsplitBV afs zfs+ . viewVar af zf (lens (from @(z f) @()) (const G.to)) {-# INLINE splitBV #-} -- | 'Numeric.Backprop.joinBV' with explicit 'add' and 'zero'. -- -- @since 0.2.2.0-joinBV- :: forall z f s as.- ( Generic (z f)- , Generic (z (BVar s))- , BVGroup s as (Rep (z f)) (Rep (z (BVar s)))- , Reifies s W- )- => AddFunc (z f)- -> Rec AddFunc as- -> ZeroFunc (Rep (z f) ())- -> Rec ZeroFunc as- -> z (BVar s) -- ^ 'BVar's of fields- -> BVar s (z f) -- ^ 'BVar' of combined value+joinBV ::+ forall z f s as.+ ( Generic (z f)+ , Generic (z (BVar s))+ , BVGroup s as (Rep (z f)) (Rep (z (BVar s)))+ , Reifies s W+ ) =>+ AddFunc (z f) ->+ Rec AddFunc as ->+ ZeroFunc (Rep (z f) ()) ->+ Rec ZeroFunc as ->+ -- | 'BVar's of fields+ z (BVar s) ->+ -- | 'BVar' of combined value+ BVar s (z f) joinBV af afs zf zfs =- viewVar af zf (lens G.to (const from))- . gjoinBV afs zfs- . from @(z (BVar s)) @()+ viewVar af zf (lens G.to (const from))+ . gjoinBV afs zfs+ . from @(z (BVar s)) @() {-# INLINE joinBV #-}
src/Numeric/Backprop/Internal.hs view
@@ -1,873 +1,974 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE EmptyCase #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeInType #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ViewPatterns #-}-{-# OPTIONS_HADDOCK not-home #-}---- |--- Module : Numeric.Backprop.Internal--- Copyright : (c) Justin Le 2023--- License : BSD3------ Maintainer : justin@jle.im--- Stability : experimental--- Portability : non-portable------ Provides the types and instances used for the graph--- building/back-propagation for the library.--module Numeric.Backprop.Internal (- BVar- , W- , backpropWithN, evalBPN- , constVar- , liftOp, liftOp1, liftOp2, liftOp3- , viewVar, setVar, sequenceVar, collectVar, previewVar, toListOfVar- , coerceVar- -- * Func wrappers- , ZeroFunc(..), zfNum, zeroFunc- , AddFunc(..), afNum, addFunc- , OneFunc(..), ofNum, oneFunc- -- * Debug- , debugSTN- , debugIR- ) where--import Control.DeepSeq-import Control.Exception-import Control.Monad-import Control.Monad.ST-import Control.Monad.Trans.State-import Data.Bifunctor-import Data.Coerce-import Data.Foldable-import Data.Function-import Data.Functor.Identity-import Data.IORef-import Data.Kind-import Data.Maybe-import Data.Monoid hiding (Any(..))-import Data.Proxy-import Data.Reflection-import Data.Type.Util-import Data.Typeable-import Data.Vinyl.Core-import GHC.Exts (Any)-import GHC.Generics as G-import Lens.Micro-import Lens.Micro.Extras-import Numeric.Backprop.Class-import Numeric.Backprop.Op-import System.IO.Unsafe-import Unsafe.Coerce-import qualified Data.Vector as V-import qualified Data.Vector.Mutable as MV-import qualified Data.Vinyl.Recursive as VR-import qualified Data.Vinyl.XRec as X---- | "Zero out" all components of a value. For scalar values, this should--- just be @'const' 0@. For vectors and matrices, this should set all--- components to zero, the additive identity.------ Should be idempotent: Applying the function twice is the same as--- applying it just once.------ Each type should ideally only have one 'ZeroFunc'. This coherence--- constraint is given by the typeclass 'Backprop'.------ @since 0.2.0.0-newtype ZeroFunc a = ZF { runZF :: a -> a }---- | Add together two values of a type. To combine contributions of--- gradients, so should ideally be information-preserving.------ See laws for 'Backprop' for the laws this should be expected to--- preserve. Namely, it should be commutative and associative, with an--- identity for a valid 'ZeroFunc'.------ Each type should ideally only have one 'AddFunc'. This coherence--- constraint is given by the typeclass 'Backprop'.------ @since 0.2.0.0-newtype AddFunc a = AF { runAF :: a -> a -> a }---- | "One" all components of a value. For scalar values, this should--- just be @'const' 1@. For vectors and matrices, this should set all--- components to one, the multiplicative identity.------ Should be idempotent: Applying the function twice is the same as--- applying it just once.------ Each type should ideally only have one 'OneFunc'. This coherence--- constraint is given by the typeclass 'Backprop'.------ @since 0.2.0.0-newtype OneFunc a = OF { runOF :: a -> a }---- | If a type has a 'Num' instance, this is the canonical 'ZeroFunc'.------ @since 0.2.0.0-zfNum :: Num a => ZeroFunc a-zfNum = ZF (const 0)-{-# INLINE zfNum #-}---- | If a type has a 'Num' instance, this is the canonical 'AddFunc'.------ @since 0.2.0.0-afNum :: Num a => AddFunc a-afNum = AF (+)-{-# INLINE afNum #-}---- | If a type has a 'Num' instance, this is the canonical 'OneFunc'.------ @since 0.2.0.0-ofNum :: Num a => OneFunc a-ofNum = OF (const 1)-{-# INLINE ofNum #-}---- | A @'BVar' s a@ is a value of type @a@ that can be "backpropagated".------ Functions referring to 'BVar's are tracked by the library and can be--- automatically differentiated to get their gradients and results.------ For simple numeric values, you can use its 'Num', 'Fractional', and--- 'Floating' instances to manipulate them as if they were the numbers they--- represent.------ If @a@ contains items, the items can be accessed and extracted using--- lenses. A @'Lens'' b a@ can be used to access an @a@ inside a @b@, using--- '^^.' ('Numeric.Backprop.viewVar'):------ @--- ('^.') :: a -> 'Lens'' a b -> b--- ('^^.') :: 'BVar' s a -> 'Lens'' a b -> 'BVar' s b--- @------ There is also '^^?' ('Numeric.Backprop.previewVar'), to use a 'Prism''--- or 'Traversal'' to extract a target that may or may not be present--- (which can implement pattern matching), '^^..'--- ('Numeric.Backprop.toListOfVar') to use a 'Traversal'' to extract /all/--- targets inside a 'BVar', and '.~~' ('setVar') to set and update values--- inside a 'BVar'.------ If you have control over your data type definitions, you can also use--- 'Numeric.Backprop.splitBV' and 'Numeric.Backprop.joinBV' to manipulate--- data types by easily extracting fields out of a 'BVar' of data types and--- creating 'BVar's of data types out of 'BVar's of their fields. See--- "Numeric.Backprop#hkd" for a tutorial on this use pattern.------ For more complex operations, libraries can provide functions on 'BVar's--- using 'Numeric.Backprop.liftOp' and related functions. This is how you--- can create primitive functions that users can use to manipulate your--- library's values. See--- <https://backprop.jle.im/08-equipping-your-library.html> for a detailed--- guide.------ For example, the /hmatrix/ library has a matrix-vector multiplication--- function, @#> :: L m n -> R n -> L m@.------ A library could instead provide a function @#> :: 'BVar' (L m n) -> BVar--- (R n) -> BVar (R m)@, which the user can then use to manipulate their--- 'BVar's of @L m n@s and @R n@s, etc.------ See "Numeric.Backprop#liftops" and documentation for--- 'Numeric.Backprop.liftOp' for more information.----data BVar s a = BV { _bvRef :: !(BRef s)- , _bvVal :: !a- }---- | @since 0.1.5.1-deriving instance Typeable (BVar s a)---- | @since 0.2.6.3-instance X.IsoHKD (BVar s) a--data BRef (s :: Type) = BRInp !Int- | BRIx !Int- | BRC- deriving (Generic, Show)--instance NFData (BRef s)---- | This will force the value inside, as well.-instance NFData a => NFData (BVar s a) where- rnf (BV r v) = force r `seq` force v `seq` ()---- | Project out a constant value if the 'BVar' refers to one.-bvConst :: BVar s a -> Maybe a-bvConst (BV BRC !x) = Just x-bvConst _ = Nothing-{-# INLINE bvConst #-}--forceBVar :: BVar s a -> ()-forceBVar (BV r !_) = force r `seq` ()-{-# INLINE forceBVar #-}--data InpRef :: Type -> Type where- IR :: { _irIx :: !(BVar s b)- , _irAdd :: !(a -> b -> b)- , _irEmbed :: !(a -> b)- }- -> InpRef a--forceInpRef :: InpRef a -> ()-forceInpRef (IR v !_ !_) = forceBVar v `seq` ()-{-# INLINE forceInpRef #-}---- | Debugging string for an 'InpRef'.-debugIR :: InpRef a -> String-debugIR IR{..} = show (_bvRef _irIx)--data TapeNode :: Type -> Type where- TN :: { _tnInputs :: !(Rec InpRef as)- , _tnGrad :: !(a -> Rec Identity as)- }- -> TapeNode a--forceTapeNode :: TapeNode a -> ()-forceTapeNode (TN inps !_) = VR.rfoldMap forceInpRef inps `seq` ()-{-# INLINE forceTapeNode #-}--data SomeTapeNode :: Type where- STN :: { _stnNode :: !(TapeNode a)- }- -> SomeTapeNode--forceSomeTapeNode :: SomeTapeNode -> ()-forceSomeTapeNode (STN n) = forceTapeNode n---- | Debugging string for a 'SomeTapeMode'.-debugSTN :: SomeTapeNode -> String-debugSTN (STN TN{..}) = show . VR.rfoldMap ((:[]) . debugIR) $ _tnInputs---- | An ephemeral Wengert Tape in the environment. Used internally to--- track of the computational graph of variables.------ For the end user, one can just imagine @'Reifies' s 'W'@ as a required--- constraint on @s@ that allows backpropagation to work.-newtype W = W { wRef :: IORef (Int, [SomeTapeNode]) }--initWengert :: IO W-initWengert = W <$> newIORef (0,[])-{-# INLINE initWengert #-}--insertNode- :: TapeNode a- -> a -- ^ val- -> W- -> IO (BVar s a)-insertNode tn !x !w = fmap ((`BV` x) . BRIx) . atomicModifyIORef' (wRef w) $ \(!n,!t) ->- let n' = n + 1- t' = STN tn : t- in forceTapeNode tn `seq` n' `seq` t' `seq` ((n', t'), n)-{-# INLINE insertNode #-}---- | Lift a value into a 'BVar' representing a constant value.------ This value will not be considered an input, and its gradients will not--- be backpropagated.-constVar :: a -> BVar s a-constVar = BV BRC-{-# INLINE constVar #-}--liftOp_- :: forall s as b. Reifies s W- => Rec AddFunc as- -> Op as b- -> Rec (BVar s) as- -> IO (BVar s b)-liftOp_ afs o !vs = case rtraverse (fmap Identity . bvConst) vs of- Just xs -> return $ constVar (evalOp o xs)- Nothing -> insertNode tn y (reflect (Proxy @s))- where- (y,g) = runOpWith o (VR.rmap (Identity . _bvVal) vs)- tn = TN { _tnInputs = VR.rzipWith go afs vs- , _tnGrad = g- }- go :: forall a. AddFunc a -> BVar s a -> InpRef a- go af !v = forceBVar v `seq` IR v (runAF af) id- {-# INLINE go #-}-{-# INLINE liftOp_ #-}---- | 'Numeric.Backprop.liftOp', but with explicit 'add' and 'zero'.-liftOp- :: forall as b s. Reifies s W- => Rec AddFunc as- -> Op as b- -> Rec (BVar s) as- -> BVar s b-liftOp afs o !vs = unsafePerformIO $ liftOp_ afs o vs-{-# INLINE liftOp #-}--liftOp1_- :: forall a b s. Reifies s W- => AddFunc a- -> Op '[a] b- -> BVar s a- -> IO (BVar s b)-liftOp1_ _ o (bvConst->Just x) = return . constVar . evalOp o $ (Identity x :& RNil)-liftOp1_ af o v = forceBVar v `seq` insertNode tn y (reflect (Proxy @s))- where- (y,g) = runOpWith o (Identity (_bvVal v) :& RNil)- tn = TN { _tnInputs = IR v (runAF af) id :& RNil- , _tnGrad = g- }-{-# INLINE liftOp1_ #-}---- | 'Numeric.Backprop.liftOp1', but with explicit 'add' and 'zero'.-liftOp1- :: forall a b s. Reifies s W- => AddFunc a- -> Op '[a] b- -> BVar s a- -> BVar s b-liftOp1 af o !v = unsafePerformIO $ liftOp1_ af o v-{-# INLINE liftOp1 #-}--liftOp2_- :: forall a b c s. Reifies s W- => AddFunc a- -> AddFunc b- -> Op '[a,b] c- -> BVar s a- -> BVar s b- -> IO (BVar s c)-liftOp2_ _ _ o (bvConst->Just x) (bvConst->Just y)- = return . constVar . evalOp o $ Identity x :& Identity y :& RNil-liftOp2_ afa afb o v u = forceBVar v- `seq` forceBVar u- `seq` insertNode tn y (reflect (Proxy @s))- where- (y,g) = runOpWith o $ Identity (_bvVal v)- :& Identity (_bvVal u)- :& RNil- tn = TN { _tnInputs = IR v (runAF afa) id :& IR u (runAF afb) id :& RNil- , _tnGrad = g- }-{-# INLINE liftOp2_ #-}---- | 'Numeric.Backprop.liftOp2', but with explicit 'add' and 'zero'.-liftOp2- :: forall a b c s. Reifies s W- => AddFunc a- -> AddFunc b- -> Op '[a,b] c- -> BVar s a- -> BVar s b- -> BVar s c-liftOp2 afa afb o !v !u = unsafePerformIO $ liftOp2_ afa afb o v u-{-# INLINE liftOp2 #-}--liftOp3_- :: forall a b c d s. Reifies s W- => AddFunc a- -> AddFunc b- -> AddFunc c- -> Op '[a,b,c] d- -> BVar s a- -> BVar s b- -> BVar s c- -> IO (BVar s d)-liftOp3_ _ _ _ o (bvConst->Just x) (bvConst->Just y) (bvConst->Just z)- = return . constVar . evalOp o $ Identity x- :& Identity y- :& Identity z- :& RNil-liftOp3_ afa afb afc o v u w = forceBVar v- `seq` forceBVar u- `seq` forceBVar w- `seq` insertNode tn y (reflect (Proxy @s))- where- (y, g) = runOpWith o $ Identity (_bvVal v)- :& Identity (_bvVal u)- :& Identity (_bvVal w)- :& RNil- tn = TN { _tnInputs = IR v (runAF afa) id- :& IR u (runAF afb) id- :& IR w (runAF afc) id- :& RNil- , _tnGrad = g- }-{-# INLINE liftOp3_ #-}---- | 'Numeric.Backprop.liftOp3', but with explicit 'add' and 'zero'.-liftOp3- :: forall a b c d s. Reifies s W- => AddFunc a- -> AddFunc b- -> AddFunc c- -> Op '[a,b,c] d- -> BVar s a- -> BVar s b- -> BVar s c- -> BVar s d-liftOp3 afa afb afc o !v !u !w = unsafePerformIO $ liftOp3_ afa afb afc o v u w-{-# INLINE liftOp3 #-}---- TODO: can we get the zero and add func from the bvar?-viewVar_- :: forall a b s. Reifies s W- => AddFunc a- -> ZeroFunc b- -> Lens' b a- -> BVar s b- -> IO (BVar s a)-viewVar_ af z l v = forceBVar v `seq` insertNode tn y (reflect (Proxy @s))- where- x = _bvVal v- y = x ^. l- tn = TN { _tnInputs = IR v (over l . runAF af) (\g -> set l g (runZF z x))- :& RNil- , _tnGrad = (:& RNil) . Identity- }-{-# INLINE viewVar_ #-}---- | 'Numeric.Backprop.viewVar', but with explicit 'add' and 'zero'.-viewVar- :: forall a b s. Reifies s W- => AddFunc a- -> ZeroFunc b- -> Lens' b a- -> BVar s b- -> BVar s a-viewVar af z l !v = unsafePerformIO $ viewVar_ af z l v-{-# INLINE viewVar #-}---- TODO: can zero and add func be gotten from the input bvars?-setVar_- :: forall a b s. Reifies s W- => AddFunc a- -> AddFunc b- -> ZeroFunc a- -> Lens' b a- -> BVar s a- -> BVar s b- -> IO (BVar s b)-setVar_ afa afb za l w v = forceBVar v- `seq` forceBVar w- `seq` insertNode tn y (reflect (Proxy @s))- where- y = _bvVal v & l .~ _bvVal w- tn = TN { _tnInputs = IR w (runAF afa) id- :& IR v (runAF afb) id- :& RNil- , _tnGrad = \d -> let (dw,dv) = l (\x -> (x, runZF za x)) d- in Identity dw :& Identity dv :& RNil- }-{-# INLINE setVar_ #-}---- | 'Numeric.Backprop.setVar', but with explicit 'add' and 'zero'.-setVar- :: forall a b s. Reifies s W- => AddFunc a- -> AddFunc b- -> ZeroFunc a- -> Lens' b a- -> BVar s a- -> BVar s b- -> BVar s b-setVar afa afb za l !w !v = unsafePerformIO $ setVar_ afa afb za l w v-{-# INLINE setVar #-}---- | 'Numeric.Backprop.sequenceVar', but with explicit 'add' and 'zero'.-sequenceVar- :: forall t a s. (Reifies s W, Traversable t)- => AddFunc a- -> ZeroFunc a- -> BVar s (t a)- -> t (BVar s a)-sequenceVar af z !v = unsafePerformIO $- traverseVar' af (ZF (fmap (runZF z))) id traverse v-{-# INLINE sequenceVar #-}---- TODO: can add funcs and zeros be had from bvars and Functor instance?-collectVar_- :: forall t a s. (Reifies s W, Foldable t, Functor t)- => AddFunc a- -> ZeroFunc a- -> t (BVar s a)- -> IO (BVar s (t a))-collectVar_ af z !vs = withVec (toList vs) $ \(vVec :: VecT n (BVar s) a) -> do- let tn :: TapeNode (t a)- tn = TN- { _tnInputs = vecToRec (vmap (\v -> IR v (runAF af) id) vVec)- , _tnGrad = vecToRec- . zipVecList (\v -> Identity . fromMaybe (runZF z (_bvVal v))) vVec- . toList- }- traverse_ (evaluate . forceBVar) vs- insertNode tn (_bvVal <$> vs) (reflect (Proxy @s))-{-# INLINE collectVar_ #-}---- | 'Numeric.Backprop.collectVar', but with explicit 'add' and 'zero'.-collectVar- :: forall t a s. (Reifies s W, Foldable t, Functor t)- => AddFunc a- -> ZeroFunc a- -> t (BVar s a)- -> BVar s (t a)-collectVar af z !vs = unsafePerformIO $ collectVar_ af z vs-{-# INLINE collectVar #-}--traverseVar'- :: forall b a f s. (Reifies s W, Traversable f)- => AddFunc a- -> ZeroFunc b- -> (b -> f a)- -> Traversal' b a- -> BVar s b- -> IO (f (BVar s a))-traverseVar' af z f t v = forceBVar v- `seq` itraverse go (f x)- where- x = _bvVal v- go :: Int -> a -> IO (BVar s a)- go i y = insertNode tn y (reflect (Proxy @s))- where- tn = TN { _tnInputs = IR v (over (ixt t i) . runAF af)- (\g -> set (ixt t i) g (runZF z x))- :& RNil- , _tnGrad = (:& RNil) . Identity- }- {-# INLINE go #-}-{-# INLINE traverseVar' #-}---- | 'Numeric.Backprop.previewVar', but with explicit 'add' and 'zero'.-previewVar- :: forall b a s. Reifies s W- => AddFunc a- -> ZeroFunc b- -> Traversal' b a- -> BVar s b- -> Maybe (BVar s a)-previewVar af z t !v = unsafePerformIO $- traverseVar' af z (preview t) t v-{-# INLINE previewVar #-}---- | 'Numeric.Backprop.toListOfVar', but with explicit 'add' and 'zero'.-toListOfVar- :: forall b a s. Reifies s W- => AddFunc a- -> ZeroFunc b- -> Traversal' b a- -> BVar s b- -> [BVar s a]-toListOfVar af z t !v = unsafePerformIO $- traverseVar' af z (toListOf t) t v-{-# INLINE toListOfVar #-}---- | Coerce a 'BVar' contents. Useful for things like newtype wrappers.------ @since 0.1.5.2-coerceVar- :: Coercible a b- => BVar s a- -> BVar s b-coerceVar v@(BV r x) = forceBVar v `seq` BV r (coerce x)--data Runner s = R { _rDelta :: !(MV.MVector s (Maybe Any))- , _rInputs :: !(MV.MVector s (Maybe Any))- }--initRunner- :: (Int, [SomeTapeNode])- -> (Int, [Maybe Any])- -> ST s (Runner s)-initRunner (n, stns) (nx,xs) = do- delts <- MV.new n- for_ (zip [n-1,n-2..] stns) $ \(i, STN (TN{} :: TapeNode c)) ->- MV.write delts i $ unsafeCoerce (Nothing @c)- inps <- MV.new nx- for_ (zip [0..] xs) . uncurry $ \i z ->- MV.write inps i z- return $ R delts inps-{-# INLINE initRunner #-}--gradRunner- :: forall b s. ()- => b -- ^ one- -> Runner s- -> (Int, [SomeTapeNode])- -> ST s ()-gradRunner o R{..} (n,stns) = do- when (n > 0) $- MV.write _rDelta (n - 1) (unsafeCoerce (Just o))- zipWithM_ go [n-1,n-2..] stns- where- go :: Int -> SomeTapeNode -> ST s ()- go i (STN (TN{..} :: TapeNode c)) = do- delt <- MV.read _rDelta i- forM_ delt $ \d -> do- let gs = _tnGrad (unsafeCoerce d)- rzipWithM_ propagate _tnInputs gs- {-# INLINE go #-}- propagate :: forall x. InpRef x -> Identity x -> ST s ()- propagate (IR v (+*) e) (Identity d) = case _bvRef v of- BRInp i -> flip (MV.modify _rInputs) i $- unsafeCoerce . bumpMaybe d (+*) e . unsafeCoerce- BRIx i -> flip (MV.modify _rDelta) i $- unsafeCoerce . bumpMaybe d (+*) e . unsafeCoerce- BRC -> return ()- {-# INLINE propagate #-}-{-# INLINE gradRunner #-}--bumpMaybe- :: a -- ^ val- -> (a -> b -> b) -- ^ add- -> (a -> b) -- ^ embed- -> Maybe b- -> Maybe b-bumpMaybe x (+*) e = \case- Nothing -> Just (e x)- Just y -> Just (x +* y)-{-# INLINE bumpMaybe #-}--seqEither :: Either a (b, [SomeTapeNode]) -> Either a (b, [SomeTapeNode])-seqEither e@(Left !_) = e-seqEither e@(Right (!_,foldMap forceSomeTapeNode->(!_))) = e-{-# INLINE seqEither #-}---- | 'Numeric.Backprop.backpropWithN', but with explicit 'zero' and 'one'.------ Note that argument order changed in v0.2.4.------ @since 0.2.0.0-backpropWithN- :: forall as b. ()- => Rec ZeroFunc as- -> (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> (b, b -> Rec Identity as)-backpropWithN zfs f !xs = (y, g')- where- !(seqEither->(!tp0),!y) = unsafePerformIO $ fillWengert f xs- g' :: b -> Rec Identity as- g' = case tp0 of- Left i -> setInput i- Right tp -> g tp- {-# INLINE g' #-}- g :: (Int, [SomeTapeNode]) -> b -> Rec Identity as- g tp o = runST $ do- r <- initRunner tp . bimap getSum (`appEndo` [])- . VR.rfoldMap go -- TODO: use strict tuple?- $ xs- gradRunner o r tp- delts <- toList <$> V.freeze (_rInputs r)- return . fromMaybe (internalError "backpropN") $- fillRec (\z -> maybe z (Identity . unsafeCoerce))- (VR.rzipWith (fmap . runZF) zfs xs)- delts- where- go :: forall a. Identity a -> (Sum Int, Endo [Maybe Any])- go _ = (1, Endo (unsafeCoerce (Nothing @a) :))- {-# INLINE go #-}- setInput :: Int -> b -> Rec Identity as- setInput !i !x = go zfs xs 0- where- go :: Rec ZeroFunc bs -> Rec Identity bs -> Int -> Rec Identity bs- go = \case- RNil -> \_ _ -> RNil- z :& zs -> \case- q :& qs -> \(!j) ->- if j == i- then Identity (unsafeCoerce x) :& VR.rzipWith coerce zs qs- else coerce z q :& go zs qs (j + 1)- {-# INLINE setInput #-}-{-# INLINE backpropWithN #-}---- | 'evalBP' generalized to multiple inputs of different types. See--- documentation for 'Numeric.Backprop.backpropN' for more details.-evalBPN- :: forall as b. ()- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> b-evalBPN f = snd . unsafePerformIO . fillWengert f-{-# INLINE evalBPN #-}--fillWengert- :: forall as b. ()- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> IO (Either Int (Int, [SomeTapeNode]), b)-fillWengert f xs = do- w <- initWengert- (i, o) <- reify w $ \(Proxy :: Proxy s) -> do- let oVar = f (inpRec @s)- evaluate (forceBVar oVar)- let isInput = case _bvRef oVar of- BRInp i -> Just i- _ -> Nothing- pure (isInput, _bvVal oVar)- t <- case i of- Nothing -> Right <$> readIORef (wRef w)- Just i' -> pure $ Left i'- pure (t, o)- where- inpRec :: forall s. Rec (BVar s) as- inpRec = evalState (rtraverse (state . go . runIdentity) xs) 0- where- go :: a -> Int -> (BVar s a, Int)- go x i = (BV (BRInp i) x, i + 1)- {-# INLINE go #-}- {-# INLINE inpRec #-}-{-# INLINE fillWengert #-}---instance (Num a, Reifies s W) => Num (BVar s a) where- (+) = liftOp2 afNum afNum (+.)- {-# INLINE (+) #-}- (-) = liftOp2 afNum afNum (-.)- {-# INLINE (-) #-}- (*) = liftOp2 afNum afNum (*.)- {-# INLINE (*) #-}- negate = liftOp1 afNum negateOp- {-# INLINE negate #-}- signum = liftOp1 afNum signumOp- {-# INLINE signum #-}- abs = liftOp1 afNum absOp- {-# INLINE abs #-}- fromInteger = constVar . fromInteger- {-# INLINE fromInteger #-}--instance (Fractional a, Reifies s W) => Fractional (BVar s a) where- (/) = liftOp2 afNum afNum (/.)- {-# INLINE (/) #-}- recip = liftOp1 afNum recipOp- {-# INLINE recip #-}- fromRational = constVar . fromRational- {-# INLINE fromRational #-}--instance (Floating a, Reifies s W) => Floating (BVar s a) where- pi = constVar pi- {-# INLINE pi #-}- exp = liftOp1 afNum expOp- {-# INLINE exp #-}- log = liftOp1 afNum logOp- {-# INLINE log #-}- sqrt = liftOp1 afNum sqrtOp- {-# INLINE sqrt #-}- (**) = liftOp2 afNum afNum (**.)- {-# INLINE (**) #-}- logBase = liftOp2 afNum afNum logBaseOp- {-# INLINE logBase #-}- sin = liftOp1 afNum sinOp- {-# INLINE sin #-}- cos = liftOp1 afNum cosOp- {-# INLINE cos #-}- tan = liftOp1 afNum tanOp- {-# INLINE tan #-}- asin = liftOp1 afNum asinOp- {-# INLINE asin #-}- acos = liftOp1 afNum acosOp- {-# INLINE acos #-}- atan = liftOp1 afNum atanOp- {-# INLINE atan #-}- sinh = liftOp1 afNum sinhOp- {-# INLINE sinh #-}- cosh = liftOp1 afNum coshOp- {-# INLINE cosh #-}- tanh = liftOp1 afNum tanhOp- {-# INLINE tanh #-}- asinh = liftOp1 afNum asinhOp- {-# INLINE asinh #-}- acosh = liftOp1 afNum acoshOp- {-# INLINE acosh #-}- atanh = liftOp1 afNum atanhOp- {-# INLINE atanh #-}---- | Compares the values inside the 'BVar'.------ @since 0.1.5.0-instance Eq a => Eq (BVar s a) where- (==) = (==) `on` _bvVal- (/=) = (/=) `on` _bvVal---- | Compares the values inside the 'BVar'.------ @since 0.1.5.0-instance Ord a => Ord (BVar s a) where- compare = compare `on` _bvVal- (<) = (<) `on` _bvVal- (<=) = (<=) `on` _bvVal- (>) = (>) `on` _bvVal- (>=) = (>=) `on` _bvVal---- Some utility functions to get around a lens dependency-itraverse- :: forall t a b f. (Traversable t, Monad f)- => (Int -> a -> f b) -> t a -> f (t b)-itraverse f xs = evalStateT (traverse (StateT . go) xs) 0- where- go :: a -> Int -> f (b, Int)- go x i = (,i+1) <$> f i x-{-# INLINE itraverse #-}--ixi :: Int -> Lens' [a] a-ixi _ _ [] = internalError "ixi"-ixi 0 f (x:xs) = (:xs) <$> f x-ixi n f (x:xs) = (x:) <$> ixi (n - 1) f xs-{-# INLINE ixi #-}--ixt :: forall b a. Traversal' b a -> Int -> Lens' b a-ixt t i f xs = stuff <$> ixi i f contents- where- contents = xs ^.. t- stuff = evalState (traverseOf t (state . const go) xs)- where- go :: [a] -> (a, [a])- go [] = internalError "ixt"- go (y:ys) = (y, ys)-{-# INLINE ixt #-}---- | @since 0.2.2.0-instance (Backprop a, Reifies s W) => Backprop (BVar s a) where- zero = liftOp1 addFunc . op1 $ \x -> (zero x, zero)- {-# INLINE zero #-}- add = liftOp2 addFunc addFunc . op2 $ \x y ->- ( add x y- , \d -> (d, d)- )- {-# INLINE add #-}- one = liftOp1 addFunc . op1 $ \x -> (one x, zero)- {-# INLINE one #-}---- | The canonical 'ZeroFunc' for instances of 'Backprop'.------ @since 0.2.0.0-zeroFunc :: Backprop a => ZeroFunc a-zeroFunc = ZF zero-{-# INLINE zeroFunc #-}---- | The canonical 'AddFunc' for instances of 'Backprop'.------ @since 0.2.0.0-addFunc :: Backprop a => AddFunc a-addFunc = AF add-{-# INLINE addFunc #-}---- | The canonical 'OneFunc' for instances of 'Backprop'.------ @since 0.2.0.0-oneFunc :: Backprop a => OneFunc a-oneFunc = OF one-{-# INLINE oneFunc #-}--internalError :: String -> a-internalError m = errorWithoutStackTrace $+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeInType #-}+{-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_HADDOCK not-home #-}++-- |+-- Module : Numeric.Backprop.Internal+-- Copyright : (c) Justin Le 2023+-- License : BSD3+--+-- Maintainer : justin@jle.im+-- Stability : experimental+-- Portability : non-portable+--+-- Provides the types and instances used for the graph+-- building/back-propagation for the library.+--+-- Do not import this unless you want to mess with the internals and know what+-- you're doing. Otherwise, use "Numeric.Backprop", "Numeric.Backprop.Op",+-- etc.+--+-- @since 0.2.7.0+module Numeric.Backprop.Internal (+ BVar,+ W,+ backpropWithN,+ evalBPN,+ constVar,+ liftOp,+ liftOp1,+ liftOp2,+ liftOp3,+ viewVar,+ setVar,+ sequenceVar,+ collectVar,+ previewVar,+ toListOfVar,+ coerceVar,++ -- * Func wrappers+ ZeroFunc (..),+ zfNum,+ zeroFunc,+ AddFunc (..),+ afNum,+ addFunc,+ OneFunc (..),+ ofNum,+ oneFunc,++ -- * Debug+ debugSTN,+ debugIR,+) where++import Control.DeepSeq+import Control.Exception+import Control.Monad+import Control.Monad.ST+import Control.Monad.Trans.State+import Data.Bifunctor+import Data.Coerce+import Data.Foldable+import Data.Function+import Data.Functor.Identity+import Data.IORef+import Data.Kind+import Data.Maybe+import Data.Monoid hiding (Any (..))+import Data.Proxy+import Data.Reflection+import Data.Type.Util+import Data.Typeable+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as MV+import Data.Vinyl.Core+import qualified Data.Vinyl.Recursive as VR+import qualified Data.Vinyl.XRec as X+import GHC.Exts (Any)+import GHC.Generics as G+import Lens.Micro+import Lens.Micro.Extras+import Numeric.Backprop.Class+import Numeric.Backprop.Op+import System.IO.Unsafe+import Unsafe.Coerce++-- | "Zero out" all components of a value. For scalar values, this should+-- just be @'const' 0@. For vectors and matrices, this should set all+-- components to zero, the additive identity.+--+-- Should be idempotent: Applying the function twice is the same as+-- applying it just once.+--+-- Each type should ideally only have one 'ZeroFunc'. This coherence+-- constraint is given by the typeclass 'Backprop'.+--+-- @since 0.2.0.0+newtype ZeroFunc a = ZF {runZF :: a -> a}++-- | Add together two values of a type. To combine contributions of+-- gradients, so should ideally be information-preserving.+--+-- See laws for 'Backprop' for the laws this should be expected to+-- preserve. Namely, it should be commutative and associative, with an+-- identity for a valid 'ZeroFunc'.+--+-- Each type should ideally only have one 'AddFunc'. This coherence+-- constraint is given by the typeclass 'Backprop'.+--+-- @since 0.2.0.0+newtype AddFunc a = AF {runAF :: a -> a -> a}++-- | "One" all components of a value. For scalar values, this should+-- just be @'const' 1@. For vectors and matrices, this should set all+-- components to one, the multiplicative identity.+--+-- Should be idempotent: Applying the function twice is the same as+-- applying it just once.+--+-- Each type should ideally only have one 'OneFunc'. This coherence+-- constraint is given by the typeclass 'Backprop'.+--+-- @since 0.2.0.0+newtype OneFunc a = OF {runOF :: a -> a}++-- | If a type has a 'Num' instance, this is the canonical 'ZeroFunc'.+--+-- @since 0.2.0.0+zfNum :: Num a => ZeroFunc a+zfNum = ZF (const 0)+{-# INLINE zfNum #-}++-- | If a type has a 'Num' instance, this is the canonical 'AddFunc'.+--+-- @since 0.2.0.0+afNum :: Num a => AddFunc a+afNum = AF (+)+{-# INLINE afNum #-}++-- | If a type has a 'Num' instance, this is the canonical 'OneFunc'.+--+-- @since 0.2.0.0+ofNum :: Num a => OneFunc a+ofNum = OF (const 1)+{-# INLINE ofNum #-}++-- | A @'BVar' s a@ is a value of type @a@ that can be "backpropagated".+--+-- Functions referring to 'BVar's are tracked by the library and can be+-- automatically differentiated to get their gradients and results.+--+-- For simple numeric values, you can use its 'Num', 'Fractional', and+-- 'Floating' instances to manipulate them as if they were the numbers they+-- represent.+--+-- If @a@ contains items, the items can be accessed and extracted using+-- lenses. A @'Lens'' b a@ can be used to access an @a@ inside a @b@, using+-- '^^.' ('Numeric.Backprop.viewVar'):+--+-- @+-- ('^.') :: a -> 'Lens'' a b -> b+-- ('^^.') :: 'BVar' s a -> 'Lens'' a b -> 'BVar' s b+-- @+--+-- There is also '^^?' ('Numeric.Backprop.previewVar'), to use a 'Prism''+-- or 'Traversal'' to extract a target that may or may not be present+-- (which can implement pattern matching), '^^..'+-- ('Numeric.Backprop.toListOfVar') to use a 'Traversal'' to extract /all/+-- targets inside a 'BVar', and '.~~' ('setVar') to set and update values+-- inside a 'BVar'.+--+-- If you have control over your data type definitions, you can also use+-- 'Numeric.Backprop.splitBV' and 'Numeric.Backprop.joinBV' to manipulate+-- data types by easily extracting fields out of a 'BVar' of data types and+-- creating 'BVar's of data types out of 'BVar's of their fields. See+-- "Numeric.Backprop#hkd" for a tutorial on this use pattern.+--+-- For more complex operations, libraries can provide functions on 'BVar's+-- using 'Numeric.Backprop.liftOp' and related functions. This is how you+-- can create primitive functions that users can use to manipulate your+-- library's values. See+-- <https://backprop.jle.im/08-equipping-your-library.html> for a detailed+-- guide.+--+-- For example, the /hmatrix/ library has a matrix-vector multiplication+-- function, @#> :: L m n -> R n -> L m@.+--+-- A library could instead provide a function @#> :: 'BVar' (L m n) -> BVar+-- (R n) -> BVar (R m)@, which the user can then use to manipulate their+-- 'BVar's of @L m n@s and @R n@s, etc.+--+-- See "Numeric.Backprop#liftops" and documentation for+-- 'Numeric.Backprop.liftOp' for more information.+data BVar s a = BV+ { _bvRef :: !(BRef s)+ , _bvVal :: !a+ }++-- | @since 0.1.5.1+deriving instance Typeable (BVar s a)++-- | @since 0.2.6.3+instance X.IsoHKD (BVar s) a++data BRef (s :: Type)+ = BRInp !Int+ | BRIx !Int+ | BRC+ deriving (Generic, Show)++instance NFData (BRef s)++-- | This will force the value inside, as well.+instance NFData a => NFData (BVar s a) where+ rnf (BV r v) = force r `seq` force v `seq` ()++-- | Project out a constant value if the 'BVar' refers to one.+bvConst :: BVar s a -> Maybe a+bvConst (BV BRC !x) = Just x+bvConst _ = Nothing+{-# INLINE bvConst #-}++forceBVar :: BVar s a -> ()+forceBVar (BV r !_) = force r `seq` ()+{-# INLINE forceBVar #-}++data InpRef :: Type -> Type where+ IR ::+ { _irIx :: !(BVar s b)+ , _irAdd :: !(a -> b -> b)+ , _irEmbed :: !(a -> b)+ } ->+ InpRef a++forceInpRef :: InpRef a -> ()+forceInpRef (IR v !_ !_) = forceBVar v `seq` ()+{-# INLINE forceInpRef #-}++-- | Debugging string for an 'InpRef'.+debugIR :: InpRef a -> String+debugIR IR{..} = show (_bvRef _irIx)++data TapeNode :: Type -> Type where+ TN ::+ { _tnInputs :: !(Rec InpRef as)+ , _tnGrad :: !(a -> Rec Identity as)+ } ->+ TapeNode a++forceTapeNode :: TapeNode a -> ()+forceTapeNode (TN inps !_) = VR.rfoldMap forceInpRef inps `seq` ()+{-# INLINE forceTapeNode #-}++data SomeTapeNode :: Type where+ STN ::+ { _stnNode :: !(TapeNode a)+ } ->+ SomeTapeNode++forceSomeTapeNode :: SomeTapeNode -> ()+forceSomeTapeNode (STN n) = forceTapeNode n++-- | Debugging string for a 'SomeTapeMode'.+debugSTN :: SomeTapeNode -> String+debugSTN (STN TN{..}) = show . VR.rfoldMap ((: []) . debugIR) $ _tnInputs++-- | An ephemeral Wengert Tape in the environment. Used internally to+-- track of the computational graph of variables.+--+-- For the end user, one can just imagine @'Reifies' s 'W'@ as a required+-- constraint on @s@ that allows backpropagation to work.+newtype W = W {wRef :: IORef (Int, [SomeTapeNode])}++initWengert :: IO W+initWengert = W <$> newIORef (0, [])+{-# INLINE initWengert #-}++insertNode ::+ TapeNode a ->+ -- | val+ a ->+ W ->+ IO (BVar s a)+insertNode tn !x !w = fmap ((`BV` x) . BRIx) . atomicModifyIORef' (wRef w) $ \(!n, !t) ->+ let n' = n + 1+ t' = STN tn : t+ in forceTapeNode tn `seq` n' `seq` t' `seq` ((n', t'), n)+{-# INLINE insertNode #-}++-- | Lift a value into a 'BVar' representing a constant value.+--+-- This value will not be considered an input, and its gradients will not+-- be backpropagated.+constVar :: a -> BVar s a+constVar = BV BRC+{-# INLINE constVar #-}++liftOp_ ::+ forall s as b.+ Reifies s W =>+ Rec AddFunc as ->+ Op as b ->+ Rec (BVar s) as ->+ IO (BVar s b)+liftOp_ afs o !vs = case rtraverse (fmap Identity . bvConst) vs of+ Just xs -> return $ constVar (evalOp o xs)+ Nothing -> insertNode tn y (reflect (Proxy @s))+ where+ (y, g) = runOpWith o (VR.rmap (Identity . _bvVal) vs)+ tn =+ TN+ { _tnInputs = VR.rzipWith go afs vs+ , _tnGrad = g+ }+ go :: forall a. AddFunc a -> BVar s a -> InpRef a+ go af !v = forceBVar v `seq` IR v (runAF af) id+ {-# INLINE go #-}+{-# INLINE liftOp_ #-}++-- | 'Numeric.Backprop.liftOp', but with explicit 'add' and 'zero'.+liftOp ::+ forall as b s.+ Reifies s W =>+ Rec AddFunc as ->+ Op as b ->+ Rec (BVar s) as ->+ BVar s b+liftOp afs o !vs = unsafePerformIO $ liftOp_ afs o vs+{-# INLINE liftOp #-}++liftOp1_ ::+ forall a b s.+ Reifies s W =>+ AddFunc a ->+ Op '[a] b ->+ BVar s a ->+ IO (BVar s b)+liftOp1_ _ o (bvConst -> Just x) = return . constVar . evalOp o $ (Identity x :& RNil)+liftOp1_ af o v = forceBVar v `seq` insertNode tn y (reflect (Proxy @s))+ where+ (y, g) = runOpWith o (Identity (_bvVal v) :& RNil)+ tn =+ TN+ { _tnInputs = IR v (runAF af) id :& RNil+ , _tnGrad = g+ }+{-# INLINE liftOp1_ #-}++-- | 'Numeric.Backprop.liftOp1', but with explicit 'add' and 'zero'.+liftOp1 ::+ forall a b s.+ Reifies s W =>+ AddFunc a ->+ Op '[a] b ->+ BVar s a ->+ BVar s b+liftOp1 af o !v = unsafePerformIO $ liftOp1_ af o v+{-# INLINE liftOp1 #-}++liftOp2_ ::+ forall a b c s.+ Reifies s W =>+ AddFunc a ->+ AddFunc b ->+ Op '[a, b] c ->+ BVar s a ->+ BVar s b ->+ IO (BVar s c)+liftOp2_ _ _ o (bvConst -> Just x) (bvConst -> Just y) =+ return . constVar . evalOp o $ Identity x :& Identity y :& RNil+liftOp2_ afa afb o v u =+ forceBVar v `seq`+ forceBVar u `seq`+ insertNode tn y (reflect (Proxy @s))+ where+ (y, g) =+ runOpWith o $+ Identity (_bvVal v)+ :& Identity (_bvVal u)+ :& RNil+ tn =+ TN+ { _tnInputs = IR v (runAF afa) id :& IR u (runAF afb) id :& RNil+ , _tnGrad = g+ }+{-# INLINE liftOp2_ #-}++-- | 'Numeric.Backprop.liftOp2', but with explicit 'add' and 'zero'.+liftOp2 ::+ forall a b c s.+ Reifies s W =>+ AddFunc a ->+ AddFunc b ->+ Op '[a, b] c ->+ BVar s a ->+ BVar s b ->+ BVar s c+liftOp2 afa afb o !v !u = unsafePerformIO $ liftOp2_ afa afb o v u+{-# INLINE liftOp2 #-}++liftOp3_ ::+ forall a b c d s.+ Reifies s W =>+ AddFunc a ->+ AddFunc b ->+ AddFunc c ->+ Op '[a, b, c] d ->+ BVar s a ->+ BVar s b ->+ BVar s c ->+ IO (BVar s d)+liftOp3_ _ _ _ o (bvConst -> Just x) (bvConst -> Just y) (bvConst -> Just z) =+ return . constVar . evalOp o $+ Identity x+ :& Identity y+ :& Identity z+ :& RNil+liftOp3_ afa afb afc o v u w =+ forceBVar v `seq`+ forceBVar u `seq`+ forceBVar w `seq`+ insertNode tn y (reflect (Proxy @s))+ where+ (y, g) =+ runOpWith o $+ Identity (_bvVal v)+ :& Identity (_bvVal u)+ :& Identity (_bvVal w)+ :& RNil+ tn =+ TN+ { _tnInputs =+ IR v (runAF afa) id+ :& IR u (runAF afb) id+ :& IR w (runAF afc) id+ :& RNil+ , _tnGrad = g+ }+{-# INLINE liftOp3_ #-}++-- | 'Numeric.Backprop.liftOp3', but with explicit 'add' and 'zero'.+liftOp3 ::+ forall a b c d s.+ Reifies s W =>+ AddFunc a ->+ AddFunc b ->+ AddFunc c ->+ Op '[a, b, c] d ->+ BVar s a ->+ BVar s b ->+ BVar s c ->+ BVar s d+liftOp3 afa afb afc o !v !u !w = unsafePerformIO $ liftOp3_ afa afb afc o v u w+{-# INLINE liftOp3 #-}++-- TODO: can we get the zero and add func from the bvar?+viewVar_ ::+ forall a b s.+ Reifies s W =>+ AddFunc a ->+ ZeroFunc b ->+ Lens' b a ->+ BVar s b ->+ IO (BVar s a)+viewVar_ af z l v = forceBVar v `seq` insertNode tn y (reflect (Proxy @s))+ where+ x = _bvVal v+ y = x ^. l+ tn =+ TN+ { _tnInputs =+ IR v (over l . runAF af) (\g -> set l g (runZF z x))+ :& RNil+ , _tnGrad = (:& RNil) . Identity+ }+{-# INLINE viewVar_ #-}++-- | 'Numeric.Backprop.viewVar', but with explicit 'add' and 'zero'.+viewVar ::+ forall a b s.+ Reifies s W =>+ AddFunc a ->+ ZeroFunc b ->+ Lens' b a ->+ BVar s b ->+ BVar s a+viewVar af z l !v = unsafePerformIO $ viewVar_ af z l v+{-# INLINE viewVar #-}++-- TODO: can zero and add func be gotten from the input bvars?+setVar_ ::+ forall a b s.+ Reifies s W =>+ AddFunc a ->+ AddFunc b ->+ ZeroFunc a ->+ Lens' b a ->+ BVar s a ->+ BVar s b ->+ IO (BVar s b)+setVar_ afa afb za l w v =+ forceBVar v `seq`+ forceBVar w `seq`+ insertNode tn y (reflect (Proxy @s))+ where+ y = _bvVal v & l .~ _bvVal w+ tn =+ TN+ { _tnInputs =+ IR w (runAF afa) id+ :& IR v (runAF afb) id+ :& RNil+ , _tnGrad = \d ->+ let (dw, dv) = l (\x -> (x, runZF za x)) d+ in Identity dw :& Identity dv :& RNil+ }+{-# INLINE setVar_ #-}++-- | 'Numeric.Backprop.setVar', but with explicit 'add' and 'zero'.+setVar ::+ forall a b s.+ Reifies s W =>+ AddFunc a ->+ AddFunc b ->+ ZeroFunc a ->+ Lens' b a ->+ BVar s a ->+ BVar s b ->+ BVar s b+setVar afa afb za l !w !v = unsafePerformIO $ setVar_ afa afb za l w v+{-# INLINE setVar #-}++-- | 'Numeric.Backprop.sequenceVar', but with explicit 'add' and 'zero'.+sequenceVar ::+ forall t a s.+ (Reifies s W, Traversable t) =>+ AddFunc a ->+ ZeroFunc a ->+ BVar s (t a) ->+ t (BVar s a)+sequenceVar af z !v =+ unsafePerformIO $+ traverseVar' af (ZF (fmap (runZF z))) id traverse v+{-# INLINE sequenceVar #-}++-- TODO: can add funcs and zeros be had from bvars and Functor instance?+collectVar_ ::+ forall t a s.+ (Reifies s W, Foldable t, Functor t) =>+ AddFunc a ->+ ZeroFunc a ->+ t (BVar s a) ->+ IO (BVar s (t a))+collectVar_ af z !vs = withVec (toList vs) $ \(vVec :: VecT n (BVar s) a) -> do+ let tn :: TapeNode (t a)+ tn =+ TN+ { _tnInputs = vecToRec (vmap (\v -> IR v (runAF af) id) vVec)+ , _tnGrad =+ vecToRec+ . zipVecList (\v -> Identity . fromMaybe (runZF z (_bvVal v))) vVec+ . toList+ }+ traverse_ (evaluate . forceBVar) vs+ insertNode tn (_bvVal <$> vs) (reflect (Proxy @s))+{-# INLINE collectVar_ #-}++-- | 'Numeric.Backprop.collectVar', but with explicit 'add' and 'zero'.+collectVar ::+ forall t a s.+ (Reifies s W, Foldable t, Functor t) =>+ AddFunc a ->+ ZeroFunc a ->+ t (BVar s a) ->+ BVar s (t a)+collectVar af z !vs = unsafePerformIO $ collectVar_ af z vs+{-# INLINE collectVar #-}++traverseVar' ::+ forall b a f s.+ (Reifies s W, Traversable f) =>+ AddFunc a ->+ ZeroFunc b ->+ (b -> f a) ->+ Traversal' b a ->+ BVar s b ->+ IO (f (BVar s a))+traverseVar' af z f t v =+ forceBVar v `seq`+ itraverse go (f x)+ where+ x = _bvVal v+ go :: Int -> a -> IO (BVar s a)+ go i y = insertNode tn y (reflect (Proxy @s))+ where+ tn =+ TN+ { _tnInputs =+ IR+ v+ (over (ixt t i) . runAF af)+ (\g -> set (ixt t i) g (runZF z x))+ :& RNil+ , _tnGrad = (:& RNil) . Identity+ }+ {-# INLINE go #-}+{-# INLINE traverseVar' #-}++-- | 'Numeric.Backprop.previewVar', but with explicit 'add' and 'zero'.+previewVar ::+ forall b a s.+ Reifies s W =>+ AddFunc a ->+ ZeroFunc b ->+ Traversal' b a ->+ BVar s b ->+ Maybe (BVar s a)+previewVar af z t !v =+ unsafePerformIO $+ traverseVar' af z (preview t) t v+{-# INLINE previewVar #-}++-- | 'Numeric.Backprop.toListOfVar', but with explicit 'add' and 'zero'.+toListOfVar ::+ forall b a s.+ Reifies s W =>+ AddFunc a ->+ ZeroFunc b ->+ Traversal' b a ->+ BVar s b ->+ [BVar s a]+toListOfVar af z t !v =+ unsafePerformIO $+ traverseVar' af z (toListOf t) t v+{-# INLINE toListOfVar #-}++-- | Coerce a 'BVar' contents. Useful for things like newtype wrappers.+--+-- @since 0.1.5.2+coerceVar ::+ Coercible a b =>+ BVar s a ->+ BVar s b+coerceVar v@(BV r x) = forceBVar v `seq` BV r (coerce x)++data Runner s = R+ { _rDelta :: !(MV.MVector s (Maybe Any))+ , _rInputs :: !(MV.MVector s (Maybe Any))+ }++initRunner ::+ (Int, [SomeTapeNode]) ->+ (Int, [Maybe Any]) ->+ ST s (Runner s)+initRunner (n, stns) (nx, xs) = do+ delts <- MV.new n+ for_ (zip [n - 1, n - 2 ..] stns) $ \(i, STN (TN{} :: TapeNode c)) ->+ MV.write delts i $ unsafeCoerce (Nothing @c)+ inps <- MV.new nx+ itraverse_ (MV.write inps) xs+ return $ R delts inps+{-# INLINE initRunner #-}++gradRunner ::+ forall b s.+ () =>+ -- | one+ b ->+ Runner s ->+ (Int, [SomeTapeNode]) ->+ ST s ()+gradRunner o R{..} (n, stns) = do+ when (n > 0) $+ MV.write _rDelta (n - 1) (unsafeCoerce (Just o))+ zipWithM_ go [n - 1, n - 2 ..] stns+ where+ go :: Int -> SomeTapeNode -> ST s ()+ go i (STN (TN{..} :: TapeNode c)) = do+ delt <- MV.read _rDelta i+ forM_ delt $ \d -> do+ let gs = _tnGrad (unsafeCoerce d)+ rzipWithM_ propagate _tnInputs gs+ {-# INLINE go #-}+ propagate :: forall x. InpRef x -> Identity x -> ST s ()+ propagate (IR v (+*) e) (Identity d) = case _bvRef v of+ BRInp i ->+ flip (MV.modify _rInputs) i $+ unsafeCoerce . bumpMaybe d (+*) e . unsafeCoerce+ BRIx i ->+ flip (MV.modify _rDelta) i $+ unsafeCoerce . bumpMaybe d (+*) e . unsafeCoerce+ BRC -> return ()+ {-# INLINE propagate #-}+{-# INLINE gradRunner #-}++bumpMaybe ::+ -- | val+ a ->+ -- | add+ (a -> b -> b) ->+ -- | embed+ (a -> b) ->+ Maybe b ->+ Maybe b+bumpMaybe x (+*) e = \case+ Nothing -> Just (e x)+ Just y -> Just (x +* y)+{-# INLINE bumpMaybe #-}++seqEither :: Either a (b, [SomeTapeNode]) -> Either a (b, [SomeTapeNode])+seqEither e@(Left !_) = e+seqEither e@(Right (!_, foldMap forceSomeTapeNode -> (!_))) = e+{-# INLINE seqEither #-}++-- | 'Numeric.Backprop.backpropWithN', but with explicit 'zero' and 'one'.+--+-- Note that argument order changed in v0.2.4.+--+-- @since 0.2.0.0+backpropWithN ::+ forall as b.+ () =>+ Rec ZeroFunc as ->+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ (b, b -> Rec Identity as)+backpropWithN zfs f !xs = (y, g')+ where+ !(seqEither -> (!tp0), !y) = unsafePerformIO $ fillWengert f xs+ g' :: b -> Rec Identity as+ g' = case tp0 of+ Left i -> setInput i+ Right tp -> g tp+ {-# INLINE g' #-}+ g :: (Int, [SomeTapeNode]) -> b -> Rec Identity as+ g tp o = runST $ do+ r <-+ initRunner tp+ . bimap getSum (`appEndo` [])+ . VR.rfoldMap go -- TODO: use strict tuple?+ $ xs+ gradRunner o r tp+ delts <- toList <$> V.freeze (_rInputs r)+ return . fromMaybe (internalError "backpropN") $+ fillRec+ (\z -> maybe z (Identity . unsafeCoerce))+ (VR.rzipWith (fmap . runZF) zfs xs)+ delts+ where+ go :: forall a. Identity a -> (Sum Int, Endo [Maybe Any])+ go _ = (1, Endo (unsafeCoerce (Nothing @a) :))+ {-# INLINE go #-}+ setInput :: Int -> b -> Rec Identity as+ setInput !i !x = go zfs xs 0+ where+ go :: Rec ZeroFunc bs -> Rec Identity bs -> Int -> Rec Identity bs+ go = \case+ RNil -> \_ _ -> RNil+ z :& zs -> \case+ q :& qs -> \(!j) ->+ if j == i+ then Identity (unsafeCoerce x) :& VR.rzipWith coerce zs qs+ else coerce z q :& go zs qs (j + 1)+ {-# INLINE setInput #-}+{-# INLINE backpropWithN #-}++-- | 'evalBP' generalized to multiple inputs of different types. See+-- documentation for 'Numeric.Backprop.backpropN' for more details.+evalBPN ::+ forall as b.+ () =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ b+evalBPN f = snd . unsafePerformIO . fillWengert f+{-# INLINE evalBPN #-}++fillWengert ::+ forall as b.+ () =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ IO (Either Int (Int, [SomeTapeNode]), b)+fillWengert f xs = do+ w <- initWengert+ (i, o) <- reify w $ \(Proxy :: Proxy s) -> do+ let oVar = f (inpRec @s)+ evaluate (forceBVar oVar)+ let isInput = case _bvRef oVar of+ BRInp i -> Just i+ _ -> Nothing+ pure (isInput, _bvVal oVar)+ t <- case i of+ Nothing -> Right <$> readIORef (wRef w)+ Just i' -> pure $ Left i'+ pure (t, o)+ where+ inpRec :: forall s. Rec (BVar s) as+ inpRec = evalState (rtraverse (state . go . runIdentity) xs) 0+ where+ go :: a -> Int -> (BVar s a, Int)+ go x i = (BV (BRInp i) x, i + 1)+ {-# INLINE go #-}+ {-# INLINE inpRec #-}+{-# INLINE fillWengert #-}++instance (Num a, Reifies s W) => Num (BVar s a) where+ (+) = liftOp2 afNum afNum (+.)+ {-# INLINE (+) #-}+ (-) = liftOp2 afNum afNum (-.)+ {-# INLINE (-) #-}+ (*) = liftOp2 afNum afNum (*.)+ {-# INLINE (*) #-}+ negate = liftOp1 afNum negateOp+ {-# INLINE negate #-}+ signum = liftOp1 afNum signumOp+ {-# INLINE signum #-}+ abs = liftOp1 afNum absOp+ {-# INLINE abs #-}+ fromInteger = constVar . fromInteger+ {-# INLINE fromInteger #-}++instance (Fractional a, Reifies s W) => Fractional (BVar s a) where+ (/) = liftOp2 afNum afNum (/.)+ {-# INLINE (/) #-}+ recip = liftOp1 afNum recipOp+ {-# INLINE recip #-}+ fromRational = constVar . fromRational+ {-# INLINE fromRational #-}++instance (Floating a, Reifies s W) => Floating (BVar s a) where+ pi = constVar pi+ {-# INLINE pi #-}+ exp = liftOp1 afNum expOp+ {-# INLINE exp #-}+ log = liftOp1 afNum logOp+ {-# INLINE log #-}+ sqrt = liftOp1 afNum sqrtOp+ {-# INLINE sqrt #-}+ (**) = liftOp2 afNum afNum (**.)+ {-# INLINE (**) #-}+ logBase = liftOp2 afNum afNum logBaseOp+ {-# INLINE logBase #-}+ sin = liftOp1 afNum sinOp+ {-# INLINE sin #-}+ cos = liftOp1 afNum cosOp+ {-# INLINE cos #-}+ tan = liftOp1 afNum tanOp+ {-# INLINE tan #-}+ asin = liftOp1 afNum asinOp+ {-# INLINE asin #-}+ acos = liftOp1 afNum acosOp+ {-# INLINE acos #-}+ atan = liftOp1 afNum atanOp+ {-# INLINE atan #-}+ sinh = liftOp1 afNum sinhOp+ {-# INLINE sinh #-}+ cosh = liftOp1 afNum coshOp+ {-# INLINE cosh #-}+ tanh = liftOp1 afNum tanhOp+ {-# INLINE tanh #-}+ asinh = liftOp1 afNum asinhOp+ {-# INLINE asinh #-}+ acosh = liftOp1 afNum acoshOp+ {-# INLINE acosh #-}+ atanh = liftOp1 afNum atanhOp+ {-# INLINE atanh #-}++-- | Compares the values inside the 'BVar'.+--+-- @since 0.1.5.0+instance Eq a => Eq (BVar s a) where+ (==) = (==) `on` _bvVal+ (/=) = (/=) `on` _bvVal++-- | Compares the values inside the 'BVar'.+--+-- @since 0.1.5.0+instance Ord a => Ord (BVar s a) where+ compare = compare `on` _bvVal+ (<) = (<) `on` _bvVal+ (<=) = (<=) `on` _bvVal+ (>) = (>) `on` _bvVal+ (>=) = (>=) `on` _bvVal++-- Some utility functions to get around a lens dependency+itraverse ::+ forall t a b f.+ (Traversable t, Monad f) =>+ (Int -> a -> f b) -> t a -> f (t b)+itraverse f xs = evalStateT (traverse (StateT . go) xs) 0+ where+ go :: a -> Int -> f (b, Int)+ go x i = (,i + 1) <$> f i x+{-# INLINE itraverse #-}++-- Some utility functions to get around a lens dependency+itraverse_ ::+ forall t a b f.+ (Foldable t, Monad f) =>+ (Int -> a -> f b) -> t a -> f ()+itraverse_ f xs = traverse_ (uncurry f) (zip [0 ..] (toList xs))+{-# INLINE itraverse_ #-}++ixi :: Int -> Lens' [a] a+ixi _ _ [] = internalError "ixi"+ixi 0 f (x : xs) = (: xs) <$> f x+ixi n f (x : xs) = (x :) <$> ixi (n - 1) f xs+{-# INLINE ixi #-}++ixt :: forall b a. Traversal' b a -> Int -> Lens' b a+ixt t i f xs = stuff <$> ixi i f contents+ where+ contents = xs ^.. t+ stuff = evalState (traverseOf t (state . const go) xs)+ where+ go :: [a] -> (a, [a])+ go [] = internalError "ixt"+ go (y : ys) = (y, ys)+{-# INLINE ixt #-}++-- | @since 0.2.2.0+instance (Backprop a, Reifies s W) => Backprop (BVar s a) where+ zero = liftOp1 addFunc . op1 $ \x -> (zero x, zero)+ {-# INLINE zero #-}+ add = liftOp2 addFunc addFunc . op2 $ \x y ->+ ( add x y+ , \d -> (d, d)+ )+ {-# INLINE add #-}+ one = liftOp1 addFunc . op1 $ \x -> (one x, zero)+ {-# INLINE one #-}++-- | The canonical 'ZeroFunc' for instances of 'Backprop'.+--+-- @since 0.2.0.0+zeroFunc :: Backprop a => ZeroFunc a+zeroFunc = ZF zero+{-# INLINE zeroFunc #-}++-- | The canonical 'AddFunc' for instances of 'Backprop'.+--+-- @since 0.2.0.0+addFunc :: Backprop a => AddFunc a+addFunc = AF add+{-# INLINE addFunc #-}++-- | The canonical 'OneFunc' for instances of 'Backprop'.+--+-- @since 0.2.0.0+oneFunc :: Backprop a => OneFunc a+oneFunc = OF one+{-# INLINE oneFunc #-}++internalError :: String -> a+internalError m =+ errorWithoutStackTrace $ "Numeric.Backprop.Internal." ++ m ++ ": unexpected shape involved in gradient computation"
src/Numeric/Backprop/Num.hs view
@@ -1,9 +1,8 @@-{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE RankNTypes #-}-{-# OPTIONS_HADDOCK not-home #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RankNTypes #-}+{-# OPTIONS_HADDOCK not-home #-} -- | -- Module : Numeric.Backprop.Num@@ -43,50 +42,95 @@ -- functions. -- -- @since 0.2.0.0- module Numeric.Backprop.Num (- -- * Types- BVar, W- -- * Running- , backprop, E.evalBP, gradBP, backpropWith- -- ** Multiple inputs- , E.evalBP0- , backprop2, E.evalBP2, gradBP2, backpropWith2- , backpropN, E.evalBPN, gradBPN, backpropWithN- -- * Manipulating 'BVar'- , E.constVar, E.auto, E.coerceVar- , (^^.), (.~~), (%~~), (^^?), (^^..), (^^?!)- , viewVar, setVar, overVar- , sequenceVar, collectVar- , previewVar, toListOfVar- -- ** With Isomorphisms- , isoVar, isoVar2, isoVar3, isoVarN- -- ** With 'Op's- , liftOp- , liftOp1, liftOp2, liftOp3- -- * 'Op'- , Op(..)- -- ** Creation- , op0, opConst, idOp- , bpOp- -- *** Giving gradients directly- , op1, op2, op3- -- *** From Isomorphisms- , opCoerce, opTup, opIso, opIsoN, opLens- -- *** No gradients- , noGrad1, noGrad- -- * Utility- , Reifies- ) where+ -- * Types+ BVar,+ W, -import Data.Functor.Identity-import Data.Maybe-import Data.Reflection-import Data.Vinyl-import Lens.Micro-import Numeric.Backprop.Explicit (BVar, W)-import Numeric.Backprop.Op+ -- * Running+ backprop,+ E.evalBP,+ gradBP,+ backpropWith,++ -- ** Multiple inputs+ E.evalBP0,+ backprop2,+ E.evalBP2,+ gradBP2,+ backpropWith2,+ backpropN,+ E.evalBPN,+ gradBPN,+ backpropWithN,++ -- * Manipulating 'BVar'+ E.constVar,+ E.auto,+ E.coerceVar,+ (^^.),+ (.~~),+ (%~~),+ (^^?),+ (^^..),+ (^^?!),+ viewVar,+ setVar,+ overVar,+ sequenceVar,+ collectVar,+ previewVar,+ toListOfVar,++ -- ** With Isomorphisms+ isoVar,+ isoVar2,+ isoVar3,+ isoVarN,++ -- ** With 'Op's+ liftOp,+ liftOp1,+ liftOp2,+ liftOp3,++ -- * 'Op'+ Op (..),++ -- ** Creation+ op0,+ opConst,+ idOp,+ bpOp,++ -- *** Giving gradients directly+ op1,+ op2,+ op3,++ -- *** From Isomorphisms+ opCoerce,+ opTup,+ opIso,+ opIsoN,+ opLens,++ -- *** No gradients+ noGrad1,+ noGrad,++ -- * Utility+ Reifies,+) where++import Data.Functor.Identity+import Data.Maybe+import Data.Reflection+import Data.Vinyl+import Lens.Micro+import Numeric.Backprop.Explicit (BVar, W) import qualified Numeric.Backprop.Explicit as E+import Numeric.Backprop.Op -- | 'Numeric.Backprop.backpropN', but with 'Num' constraints instead of -- 'Backprop' constraints.@@ -99,12 +143,11 @@ -- If you stick to /concerete/, monomorphic usage of this (with specific -- types, typed into source code, known at compile-time), then -- @'AllPureConstrained' 'Num' as@ should be fulfilled automatically.----backpropN- :: (RPureConstrained Num as, Num b)- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> (b, Rec Identity as)+backpropN ::+ (RPureConstrained Num as, Num b) =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ (b, Rec Identity as) backpropN = E.backpropN E.zfNums E.ofNum {-# INLINE backpropN #-} @@ -116,11 +159,11 @@ -- Note that argument order changed in v0.2.4. -- -- @since 0.2.0.0-backpropWithN- :: RPureConstrained Num as- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> (b, b -> Rec Identity as)+backpropWithN ::+ RPureConstrained Num as =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ (b, b -> Rec Identity as) backpropWithN = E.backpropWithN E.zfNums {-# INLINE backpropWithN #-} @@ -129,11 +172,11 @@ -- -- See module documentation for "Numeric.Backprop.Num" for information on -- using this with tuples.-backprop- :: (Num a, Num b)- => (forall s. Reifies s W => BVar s a -> BVar s b)- -> a- -> (b, a)+backprop ::+ (Num a, Num b) =>+ (forall s. Reifies s W => BVar s a -> BVar s b) ->+ a ->+ (b, a) backprop = E.backprop E.zfNum E.ofNum {-# INLINE backprop #-} @@ -146,42 +189,42 @@ -- Note that argument order changed in v0.2.4. -- -- @since 0.2.0.0-backpropWith- :: Num a- => (forall s. Reifies s W => BVar s a -> BVar s b)- -> a- -> (b, b -> a)+backpropWith ::+ Num a =>+ (forall s. Reifies s W => BVar s a -> BVar s b) ->+ a ->+ (b, b -> a) backpropWith = E.backpropWith E.zfNum {-# INLINE backpropWith #-} -- | 'Numeric.Backprop.gradBP', but with 'Num' constraints instead of -- 'Backprop' constraints.-gradBP- :: (Num a, Num b)- => (forall s. Reifies s W => BVar s a -> BVar s b)- -> a- -> a+gradBP ::+ (Num a, Num b) =>+ (forall s. Reifies s W => BVar s a -> BVar s b) ->+ a ->+ a gradBP = E.gradBP E.zfNum E.ofNum {-# INLINE gradBP #-} -- | 'Numeric.Backprop.gradBPN', but with 'Num' constraints instead of -- 'Backprop' constraints.-gradBPN- :: (RPureConstrained Num as, Num b)- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Rec Identity as- -> Rec Identity as+gradBPN ::+ (RPureConstrained Num as, Num b) =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Rec Identity as ->+ Rec Identity as gradBPN = E.gradBPN E.zfNums E.ofNum {-# INLINE gradBPN #-} -- | 'Numeric.Backprop.backprop2', but with 'Num' constraints instead of -- 'Backprop' constraints.-backprop2- :: (Num a, Num b, Num c)- => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> (c, (a, b))+backprop2 ::+ (Num a, Num b, Num c) =>+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ (c, (a, b)) backprop2 = E.backprop2 E.zfNum E.zfNum E.ofNum {-# INLINE backprop2 #-} @@ -191,77 +234,82 @@ -- Note that argument order changed in v0.2.4. -- -- @since 0.2.0.0-backpropWith2- :: (Num a, Num b)- => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> (c, c -> (a, b)) -- ^ Takes function giving gradient of final result given the output of function+backpropWith2 ::+ (Num a, Num b) =>+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ -- | Takes function giving gradient of final result given the output of function+ (c, c -> (a, b)) backpropWith2 = E.backpropWith2 E.zfNum E.zfNum {-# INLINE backpropWith2 #-} -- | 'Numeric.Backprop.gradBP2', but with 'Num' constraints instead of -- 'Backprop' constraints.-gradBP2- :: (Num a, Num b, Num c)- => (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c)- -> a- -> b- -> (a, b)+gradBP2 ::+ (Num a, Num b, Num c) =>+ (forall s. Reifies s W => BVar s a -> BVar s b -> BVar s c) ->+ a ->+ b ->+ (a, b) gradBP2 = E.gradBP2 E.zfNum E.zfNum E.ofNum {-# INLINE gradBP2 #-} -- | 'Numeric.Backprop.bpOp', but with 'Num' constraints instead of -- 'Backprop' constraints.-bpOp- :: RPureConstrained Num as- => (forall s. Reifies s W => Rec (BVar s) as -> BVar s b)- -> Op as b+bpOp ::+ RPureConstrained Num as =>+ (forall s. Reifies s W => Rec (BVar s) as -> BVar s b) ->+ Op as b bpOp = E.bpOp E.zfNums {-# INLINE bpOp #-} -- | 'Numeric.Backprop.^^.', but with 'Num' constraints instead of -- 'Backprop' constraints.-(^^.)- :: forall b a s. (Num a, Num b, Reifies s W)- => BVar s b- -> Lens' b a- -> BVar s a+(^^.) ::+ forall b a s.+ (Num a, Num b, Reifies s W) =>+ BVar s b ->+ Lens' b a ->+ BVar s a x ^^. l = viewVar l x+ infixl 8 ^^. {-# INLINE (^^.) #-} -- | 'Numeric.Backprop.viewVar', but with 'Num' constraints instead of -- 'Backprop' constraints.-viewVar- :: forall b a s. (Num a, Num b, Reifies s W)- => Lens' b a- -> BVar s b- -> BVar s a+viewVar ::+ forall b a s.+ (Num a, Num b, Reifies s W) =>+ Lens' b a ->+ BVar s b ->+ BVar s a viewVar = E.viewVar E.afNum E.zfNum {-# INLINE viewVar #-} - -- | 'Numeric.Backprop..~~', but with 'Num' constraints instead of -- 'Backprop' constraints.-(.~~)- :: (Num a, Num b, Reifies s W)- => Lens' b a- -> BVar s a- -> BVar s b- -> BVar s b+(.~~) ::+ (Num a, Num b, Reifies s W) =>+ Lens' b a ->+ BVar s a ->+ BVar s b ->+ BVar s b l .~~ x = setVar l x+ infixl 8 .~~ {-# INLINE (.~~) #-} -- | 'Numeric.Backprop.setVar', but with 'Num' constraints instead of -- 'Backprop' constraints.-setVar- :: forall a b s. (Num a, Num b, Reifies s W)- => Lens' b a- -> BVar s a- -> BVar s b- -> BVar s b+setVar ::+ forall a b s.+ (Num a, Num b, Reifies s W) =>+ Lens' b a ->+ BVar s a ->+ BVar s b ->+ BVar s b setVar = E.setVar E.afNum E.afNum E.zfNum {-# INLINE setVar #-} @@ -269,14 +317,14 @@ -- 'Backprop' constraints. -- -- @since 0.2.4.0----(%~~)- :: (Num a, Num b, Reifies s W)- => Lens' b a- -> (BVar s a -> BVar s a)- -> BVar s b- -> BVar s b+(%~~) ::+ (Num a, Num b, Reifies s W) =>+ Lens' b a ->+ (BVar s a -> BVar s a) ->+ BVar s b ->+ BVar s b l %~~ f = overVar l f+ infixr 4 %~~ {-# INLINE (%~~) #-} @@ -284,12 +332,12 @@ -- 'Backprop' constraints. -- -- @since 0.2.4.0-overVar- :: (Num a, Num b, Reifies s W)- => Lens' b a- -> (BVar s a -> BVar s a)- -> BVar s b- -> BVar s b+overVar ::+ (Num a, Num b, Reifies s W) =>+ Lens' b a ->+ (BVar s a -> BVar s a) ->+ BVar s b ->+ BVar s b overVar = E.overVar E.afNum E.afNum E.zfNum E.zfNum {-# INLINE overVar #-} @@ -311,12 +359,14 @@ -- myPrism :: 'Prism'' c (a, b) -- myPrism . 'iso' 'tupT2' 't2Tup' :: 'Prism'' c ('T2' a b) -- @-(^^?)- :: forall b a s. (Num b, Num a, Reifies s W)- => BVar s b- -> Traversal' b a- -> Maybe (BVar s a)+(^^?) ::+ forall b a s.+ (Num b, Num a, Reifies s W) =>+ BVar s b ->+ Traversal' b a ->+ Maybe (BVar s a) v ^^? t = previewVar t v+ infixl 8 ^^? {-# INLINE (^^?) #-} @@ -326,14 +376,16 @@ -- Like 'Numeric.Backprop.^^?!', is *UNSAFE*. -- -- @since 0.2.1.0-(^^?!)- :: forall b a s. (Num b, Num a, Reifies s W)- => BVar s b- -> Traversal' b a- -> BVar s a+(^^?!) ::+ forall b a s.+ (Num b, Num a, Reifies s W) =>+ BVar s b ->+ Traversal' b a ->+ BVar s a v ^^?! t = fromMaybe (error e) (previewVar t v) where e = "Numeric.Backprop.Num.^^?!: Empty traversal"+ infixl 8 ^^?! {-# INLINE (^^?!) #-} @@ -341,31 +393,34 @@ -- 'Backprop' constraints. -- -- See documentation for '^^?' for more information and important notes.-previewVar- :: forall b a s. (Num b, Num a, Reifies s W)- => Traversal' b a- -> BVar s b- -> Maybe (BVar s a)+previewVar ::+ forall b a s.+ (Num b, Num a, Reifies s W) =>+ Traversal' b a ->+ BVar s b ->+ Maybe (BVar s a) previewVar = E.previewVar E.afNum E.zfNum {-# INLINE previewVar #-} -- | 'Numeric.Backprop.^^..', but with 'Num' constraints instead of -- 'Backprop' constraints.-(^^..)- :: forall b a s. (Num b, Num a, Reifies s W)- => BVar s b- -> Traversal' b a- -> [BVar s a]+(^^..) ::+ forall b a s.+ (Num b, Num a, Reifies s W) =>+ BVar s b ->+ Traversal' b a ->+ [BVar s a] v ^^.. t = toListOfVar t v {-# INLINE (^^..) #-} -- | 'Numeric.Backprop.toListOfVar', but with 'Num' constraints instead of -- 'Backprop' constraints.-toListOfVar- :: forall b a s. (Num b, Num a, Reifies s W)- => Traversal' b a- -> BVar s b- -> [BVar s a]+toListOfVar ::+ forall b a s.+ (Num b, Num a, Reifies s W) =>+ Traversal' b a ->+ BVar s b ->+ [BVar s a] toListOfVar = E.toListOfVar E.afNum E.zfNum {-# INLINE toListOfVar #-} @@ -373,10 +428,10 @@ -- 'Backprop' constraints. -- -- Since v0.2.4, requires a 'Num' constraint on @t a@.-sequenceVar- :: (Traversable t, Num a, Reifies s W)- => BVar s (t a)- -> t (BVar s a)+sequenceVar ::+ (Traversable t, Num a, Reifies s W) =>+ BVar s (t a) ->+ t (BVar s a) sequenceVar = E.sequenceVar E.afNum E.zfNum {-# INLINE sequenceVar #-} @@ -384,99 +439,99 @@ -- 'Backprop' constraints. -- -- Prior to v0.2.3, required a 'Num' constraint on @t a@.-collectVar- :: (Foldable t, Functor t, Num a, Reifies s W)- => t (BVar s a)- -> BVar s (t a)+collectVar ::+ (Foldable t, Functor t, Num a, Reifies s W) =>+ t (BVar s a) ->+ BVar s (t a) collectVar = E.collectVar E.afNum E.zfNum {-# INLINE collectVar #-} -- | 'Numeric.Backprop.liftOp', but with 'Num' constraints instead of -- 'Backprop' constraints.-liftOp- :: (RPureConstrained Num as, Reifies s W)- => Op as b- -> Rec (BVar s) as- -> BVar s b+liftOp ::+ (RPureConstrained Num as, Reifies s W) =>+ Op as b ->+ Rec (BVar s) as ->+ BVar s b liftOp = E.liftOp E.afNums {-# INLINE liftOp #-} -- | 'Numeric.Backprop.liftOp1', but with 'Num' constraints instead of -- 'Backprop' constraints.-liftOp1- :: (Num a, Reifies s W)- => Op '[a] b- -> BVar s a- -> BVar s b+liftOp1 ::+ (Num a, Reifies s W) =>+ Op '[a] b ->+ BVar s a ->+ BVar s b liftOp1 = E.liftOp1 E.afNum {-# INLINE liftOp1 #-} -- | 'Numeric.Backprop.liftOp2', but with 'Num' constraints instead of -- 'Backprop' constraints.-liftOp2- :: (Num a, Num b, Reifies s W)- => Op '[a,b] c- -> BVar s a- -> BVar s b- -> BVar s c+liftOp2 ::+ (Num a, Num b, Reifies s W) =>+ Op '[a, b] c ->+ BVar s a ->+ BVar s b ->+ BVar s c liftOp2 = E.liftOp2 E.afNum E.afNum {-# INLINE liftOp2 #-} -- | 'Numeric.Backprop.liftOp3', but with 'Num' constraints instead of -- 'Backprop' constraints.-liftOp3- :: (Num a, Num b, Num c, Reifies s W)- => Op '[a,b,c] d- -> BVar s a- -> BVar s b- -> BVar s c- -> BVar s d+liftOp3 ::+ (Num a, Num b, Num c, Reifies s W) =>+ Op '[a, b, c] d ->+ BVar s a ->+ BVar s b ->+ BVar s c ->+ BVar s d liftOp3 = E.liftOp3 E.afNum E.afNum E.afNum {-# INLINE liftOp3 #-} -- | 'Numeric.Backprop.isoVar', but with 'Num' constraints instead of -- 'Backprop' constraints.-isoVar- :: (Num a, Reifies s W)- => (a -> b)- -> (b -> a)- -> BVar s a- -> BVar s b+isoVar ::+ (Num a, Reifies s W) =>+ (a -> b) ->+ (b -> a) ->+ BVar s a ->+ BVar s b isoVar = E.isoVar E.afNum {-# INLINE isoVar #-} -- | 'Numeric.Backprop.isoVar', but with 'Num' constraints instead of -- 'Backprop' constraints.-isoVar2- :: (Num a, Num b, Reifies s W)- => (a -> b -> c)- -> (c -> (a, b))- -> BVar s a- -> BVar s b- -> BVar s c+isoVar2 ::+ (Num a, Num b, Reifies s W) =>+ (a -> b -> c) ->+ (c -> (a, b)) ->+ BVar s a ->+ BVar s b ->+ BVar s c isoVar2 = E.isoVar2 E.afNum E.afNum {-# INLINE isoVar2 #-} -- | 'Numeric.Backprop.isoVar3', but with 'Num' constraints instead of -- 'Backprop' constraints.-isoVar3- :: (Num a, Num b, Num c, Reifies s W)- => (a -> b -> c -> d)- -> (d -> (a, b, c))- -> BVar s a- -> BVar s b- -> BVar s c- -> BVar s d+isoVar3 ::+ (Num a, Num b, Num c, Reifies s W) =>+ (a -> b -> c -> d) ->+ (d -> (a, b, c)) ->+ BVar s a ->+ BVar s b ->+ BVar s c ->+ BVar s d isoVar3 = E.isoVar3 E.afNum E.afNum E.afNum {-# INLINE isoVar3 #-} -- | 'Numeric.Backprop.isoVarN', but with 'Num' constraints instead of -- 'Backprop' constraints.-isoVarN- :: (RPureConstrained Num as, Reifies s W)- => (Rec Identity as -> b)- -> (b -> Rec Identity as)- -> Rec (BVar s) as- -> BVar s b+isoVarN ::+ (RPureConstrained Num as, Reifies s W) =>+ (Rec Identity as -> b) ->+ (b -> Rec Identity as) ->+ Rec (BVar s) as ->+ BVar s b isoVarN = E.isoVarN E.afNums {-# INLINE isoVarN #-}
src/Numeric/Backprop/Op.hs view
@@ -1,12 +1,12 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE TypeApplications #-} {-# LANGUAGE UndecidableInstances #-} -- |@@ -42,51 +42,92 @@ -- -- See also <https://backprop.jle.im/06-manual-gradients.html this guide> -- for writing Ops manually on your own numerical functions.---- module Numeric.Backprop.Op ( -- * Implementation -- $opdoc- -- * Types- -- ** Op and Synonyms- Op(..)+ Op (..),+ -- ** Tuple Types#prod# -- $prod- , Rec(..)+ Rec (..),+ -- * Running+ -- ** Pure- , runOp, evalOp, gradOp, gradOpWith+ runOp,+ evalOp,+ gradOp,+ gradOpWith,+ -- * Creation- , op0, opConst, idOp- , opLens+ op0,+ opConst,+ idOp,+ opLens,+ -- ** Giving gradients directly- , op1, op2, op3+ op1,+ op2,+ op3,+ -- ** From Isomorphisms- , opCoerce, opTup, opIso, opIso2, opIso3, opIsoN+ opCoerce,+ opTup,+ opIso,+ opIso2,+ opIso3,+ opIsoN,+ -- ** No gradient- , noGrad1, noGrad+ noGrad1,+ noGrad,+ -- * Manipulation- , composeOp, composeOp1, (~.)+ composeOp,+ composeOp1,+ (~.),+ -- * Utility+ -- ** Numeric Ops#numops# -- $numops- , (+.), (-.), (*.), negateOp, absOp, signumOp- , (/.), recipOp- , expOp, logOp, sqrtOp, (**.), logBaseOp- , sinOp, cosOp, tanOp, asinOp, acosOp, atanOp- , sinhOp, coshOp, tanhOp, asinhOp, acoshOp, atanhOp- ) where+ (+.),+ (-.),+ (*.),+ negateOp,+ absOp,+ signumOp,+ (/.),+ recipOp,+ expOp,+ logOp,+ sqrtOp,+ (**.),+ logBaseOp,+ sinOp,+ cosOp,+ tanOp,+ asinOp,+ acosOp,+ atanOp,+ sinhOp,+ coshOp,+ tanhOp,+ asinhOp,+ acoshOp,+ atanhOp,+) where -import Control.Applicative-import Data.Bifunctor-import Data.Coerce-import Data.Functor.Identity-import Data.List-import Data.Type.Util-import Data.Vinyl.Core-import Lens.Micro-import Lens.Micro.Extras-import qualified Data.Vinyl.Recursive as VR+import Control.Applicative+import Data.Bifunctor+import Data.Coerce+import Data.Functor.Identity+import Data.List (foldl')+import Data.Type.Util+import Data.Vinyl.Core+import qualified Data.Vinyl.Recursive as VR+import Lens.Micro+import Lens.Micro.Extras -- $opdoc -- 'Op's contain information on a function as well as its gradient, but@@ -181,61 +222,71 @@ -- -- To /use/ an 'Op' with the backprop library, see 'liftOp', 'liftOp1', -- 'liftOp2', and 'liftOp3'.-newtype Op as a =- -- | Construct an 'Op' by giving a function creating the+newtype Op as a+ = -- | Construct an 'Op' by giving a function creating the -- result, and also a continuation on how to create the gradient, given -- the total derivative of @a@. -- -- See the module documentation for "Numeric.Backprop.Op" for more -- details on the function that this constructor and 'Op' expect.- Op { -- | Run the function that the 'Op' encodes, returning- -- a continuation to compute the gradient, given the total- -- derivative of @a@. See documentation for "Numeric.Backprop.Op"- -- for more information.- runOpWith :: Rec Identity as -> (a, a -> Rec Identity as)- }+ Op+ { runOpWith :: Rec Identity as -> (a, a -> Rec Identity as)+ -- ^ Run the function that the 'Op' encodes, returning+ -- a continuation to compute the gradient, given the total+ -- derivative of @a@. See documentation for "Numeric.Backprop.Op"+ -- for more information.+ } -- | Helper wrapper used for the implementation of 'composeOp'.-newtype OpCont as a = OC { runOpCont :: a -> Rec Identity as }+newtype OpCont as a = OC {runOpCont :: a -> Rec Identity as} -- | Compose 'Op's together, like 'sequence' for functions, or @liftAN@. -- -- That is, given an @'Op' as b1@, an @'Op' as b2@, and an @'Op' as b3@, it -- can compose them with an @'Op' '[b1,b2,b3] c@ to create an @'Op' as -- c@.-composeOp- :: forall as bs c. (RPureConstrained Num as)- => Rec (Op as) bs -- ^ 'Rec' of 'Op's taking @as@ and returning- -- different @b@ in @bs@- -> Op bs c -- ^ 'OpM' taking eac of the @bs@ from the- -- input 'Rec'.- -> Op as c -- ^ Composed 'Op'+composeOp ::+ forall as bs c.+ RPureConstrained Num as =>+ -- | 'Rec' of 'Op's taking @as@ and returning+ -- different @b@ in @bs@+ Rec (Op as) bs ->+ -- | 'OpM' taking eac of the @bs@ from the+ -- input 'Rec'.+ Op bs c ->+ -- | Composed 'Op'+ Op as c composeOp os o = Op $ \xs ->- let (ys, conts) = runzipWith (bimap Identity OC . flip runOpWith xs) os- (z, gFz) = runOpWith o ys- gFunc g0 =- let g1 = gFz g0- g2s :: Rec (Const (Rec Identity as)) bs- g2s = VR.rzipWith (\oc (Identity g) -> Const $ runOpCont oc g)- conts g1- in VR.rmap (\(Dict x) -> Identity x)- . foldl' (VR.rzipWith (\(Dict !x) (Identity y) ->- let q = x + y in q `seq` Dict q- )- )- (rpureConstrained @Num (Dict @Num 0))- . VR.rfoldMap ((:[]) . getConst)- $ g2s- in (z, gFunc)+ let (ys, conts) = runzipWith (bimap Identity OC . flip runOpWith xs) os+ (z, gFz) = runOpWith o ys+ gFunc g0 =+ let g1 = gFz g0+ g2s :: Rec (Const (Rec Identity as)) bs+ g2s =+ VR.rzipWith+ (\oc (Identity g) -> Const $ runOpCont oc g)+ conts+ g1+ in VR.rmap (\(Dict x) -> Identity x)+ . foldl'+ ( VR.rzipWith+ ( \(Dict !x) (Identity y) ->+ let q = x + y in q `seq` Dict q+ )+ )+ (rpureConstrained @Num (Dict @Num 0))+ . VR.rfoldMap ((: []) . getConst)+ $ g2s+ in (z, gFunc) -- | Convenient wrapper over 'composeOp' for the case where the second -- function only takes one input, so the two 'Op's can be directly piped -- together, like for '.'.-composeOp1- :: RPureConstrained Num as- => Op as b- -> Op '[b] c- -> Op as c+composeOp1 ::+ RPureConstrained Num as =>+ Op as b ->+ Op '[b] c ->+ Op as c composeOp1 = composeOp . (:& RNil) -- | Convenient infix synonym for (flipped) 'composeOp1'. Meant to be used@@ -248,15 +299,15 @@ -- f '~.' g :: Op '[a, a] c -- @ infixr 9 ~.-(~.)- :: (RPureConstrained Num as)- => Op '[b] c- -> Op as b- -> Op as c++(~.) ::+ RPureConstrained Num as =>+ Op '[b] c ->+ Op as b ->+ Op as c (~.) = flip composeOp1 {-# INLINE (~.) #-} - -- | Run the function that an 'Op' encodes, to get the result. -- -- >>> runOp (op2 (*)) (3 :& 5 :& RNil)@@ -279,11 +330,15 @@ -- -- See the module documentaiton for "Numeric.Backprop.Op" for more -- information.-gradOpWith- :: Op as a -- ^ 'Op' to run- -> Rec Identity as -- ^ Inputs to run it with- -> a -- ^ The total derivative of the result.- -> Rec Identity as -- ^ The gradient+gradOpWith ::+ -- | 'Op' to run+ Op as a ->+ -- | Inputs to run it with+ Rec Identity as ->+ -- | The total derivative of the result.+ a ->+ -- | The gradient+ Rec Identity as gradOpWith o = snd . runOpWith o {-# INLINE gradOpWith #-} @@ -297,7 +352,6 @@ -- @ -- 'gradOp' o xs = 'gradOpWith' o xs 1 -- @--- gradOp :: Num a => Op as a -> Rec Identity as -> Rec Identity as gradOp o i = gradOpWith o i 1 {-# INLINE gradOp #-}@@ -330,9 +384,9 @@ -- @since 0.1.3.0 noGrad1 :: (a -> b) -> Op '[a] b noGrad1 f = op1 $ \x ->- ( f x- , \_ -> errorWithoutStackTrace "Numeric.Backprop.Op.noGrad1: no gradient defined"- )+ ( f x+ , \_ -> errorWithoutStackTrace "Numeric.Backprop.Op.noGrad1: no gradient defined"+ ) {-# INLINE noGrad1 #-} -- | Create an 'Op' with no gradient. Can be evaluated with 'evalOp', but@@ -350,9 +404,9 @@ -- @since 0.1.3.0 noGrad :: (Rec Identity as -> b) -> Op as b noGrad f = Op $ \xs ->- ( f xs- , \_ -> errorWithoutStackTrace "Numeric.Backprop.Op.noGrad: no gradient defined"- )+ ( f xs+ , \_ -> errorWithoutStackTrace "Numeric.Backprop.Op.noGrad: no gradient defined"+ ) {-# INLINE noGrad #-} -- | An 'Op' that just returns whatever it receives. The identity@@ -362,7 +416,7 @@ -- 'idOp' = 'opIso' 'id' 'id' -- @ idOp :: Op '[a] a-idOp = op1 $ \x -> (x, id)+idOp = op1 (,id) {-# INLINE idOp #-} -- | An 'Op' that takes @as@ and returns exactly the input tuple.@@ -370,7 +424,7 @@ -- >>> gradOp' opTup (1 :& 2 :& 3 :& RNil) -- (1 :& 2 :& 3 :& RNil, 1 :& 1 :& 1 :& RNil) opTup :: Op as (Rec Identity as)-opTup = Op $ \xs -> (xs, id)+opTup = Op (,id) {-# INLINE opTup #-} -- | An 'Op' that runs the input value through an isomorphism.@@ -378,7 +432,7 @@ -- Warning: This is unsafe! It assumes that the isomorphisms themselves -- have derivative 1, so will break for things like 'exp' & 'log'. -- Basically, don't use this for any "numeric" isomorphisms.-opIso :: (a -> b) -> (b -> a) -> Op '[ a ] b+opIso :: (a -> b) -> (b -> a) -> Op '[a] b opIso to' from' = op1 $ \x -> (to' x, from') {-# INLINE opIso #-} @@ -414,7 +468,7 @@ -- Warning: This is unsafe! It assumes that it extracts a specific value -- unchanged, with derivative 1, so will break for things that numerically -- manipulate things before returning them.-opLens :: Num a => Lens' a b -> Op '[ a ] b+opLens :: Num a => Lens' a b -> Op '[a] b opLens l = op1 $ \x -> (view l x, \d -> set l d 0) {-# INLINE opLens #-} @@ -423,12 +477,15 @@ -- -- >>> gradOp' (opConst 10) (1 :& 2 :& 3 :& RNil) -- (10, 0 :& 0 :& 0 :& RNil)-opConst- :: forall as a. RPureConstrained Num as- => a- -> Op as a-opConst x = Op $ const- (x, const $ rpureConstrained @Num 0)+opConst ::+ forall as a.+ RPureConstrained Num as =>+ a ->+ Op as a+opConst x =+ Op $+ const+ (x, const $ rpureConstrained @Num 0) {-# INLINE opConst #-} -- | Create an 'Op' that takes no inputs and always returns the given@@ -444,7 +501,7 @@ -- 'opConst''. op0 :: a -> Op '[] a op0 x = Op $ \case- RNil -> (x, const RNil)+ RNil -> (x, const RNil) {-# INLINE op0 #-} -- | Create an 'Op' of a function taking one input, by giving its explicit@@ -482,13 +539,13 @@ -- -- Remember that, generally, end users shouldn't directly construct 'Op's; -- they should be provided by libraries or generated automatically.-op1- :: (a -> (b, b -> a))- -> Op '[a] b+op1 ::+ (a -> (b, b -> a)) ->+ Op '[a] b op1 f = Op $ \case- Identity x :& RNil ->- let (y, dx) = f x- in (y, \(!d) -> (:& RNil) . Identity . dx $ d)+ Identity x :& RNil ->+ let (y, dx) = f x+ in (y, \(!d) -> (:& RNil) . Identity . dx $ d) {-# INLINE op1 #-} -- | Create an 'Op' of a function taking two inputs, by giving its explicit@@ -528,86 +585,86 @@ -- -- Remember that, generally, end users shouldn't directly construct 'Op's; -- they should be provided by libraries or generated automatically.-op2- :: (a -> b -> (c, c -> (a, b)))- -> Op '[a,b] c+op2 ::+ (a -> b -> (c, c -> (a, b))) ->+ Op '[a, b] c op2 f = Op $ \case- Identity x :& Identity y :& RNil ->- let (z, dxdy) = f x y- in (z, (\(!dx,!dy) -> Identity dx :& Identity dy :& RNil) . dxdy)+ Identity x :& Identity y :& RNil ->+ let (z, dxdy) = f x y+ in (z, (\(!dx, !dy) -> Identity dx :& Identity dy :& RNil) . dxdy) {-# INLINE op2 #-} -- | Create an 'Op' of a function taking three inputs, by giving its explicit -- gradient. See documentation for 'op2' for more details.-op3- :: (a -> b -> c -> (d, d -> (a, b, c)))- -> Op '[a,b,c] d+op3 ::+ (a -> b -> c -> (d, d -> (a, b, c))) ->+ Op '[a, b, c] d op3 f = Op $ \case- Identity x :& Identity y :& Identity z :& RNil ->- let (q, dxdydz) = f x y z- in (q, (\(!dx, !dy, !dz) -> Identity dx :& Identity dy :& Identity dz :& RNil) . dxdydz)+ Identity x :& Identity y :& Identity z :& RNil ->+ let (q, dxdydz) = f x y z+ in (q, (\(!dx, !dy, !dz) -> Identity dx :& Identity dy :& Identity dz :& RNil) . dxdydz) {-# INLINE op3 #-} instance (RPureConstrained Num as, Num a) => Num (Op as a) where- o1 + o2 = composeOp (o1 :& o2 :& RNil) (+.)- {-# INLINE (+) #-}- o1 - o2 = composeOp (o1 :& o2 :& RNil) (-.)- {-# INLINE (-) #-}- o1 * o2 = composeOp (o1 :& o2 :& RNil) (*.)- {-# INLINE (*) #-}- negate o = composeOp (o :& RNil) negateOp- {-# INLINE negate #-}- signum o = composeOp (o :& RNil) signumOp- {-# INLINE signum #-}- abs o = composeOp (o :& RNil) absOp- {-# INLINE abs #-}- fromInteger x = opConst (fromInteger x)- {-# INLINE fromInteger #-}+ o1 + o2 = composeOp (o1 :& o2 :& RNil) (+.)+ {-# INLINE (+) #-}+ o1 - o2 = composeOp (o1 :& o2 :& RNil) (-.)+ {-# INLINE (-) #-}+ o1 * o2 = composeOp (o1 :& o2 :& RNil) (*.)+ {-# INLINE (*) #-}+ negate o = composeOp (o :& RNil) negateOp+ {-# INLINE negate #-}+ signum o = composeOp (o :& RNil) signumOp+ {-# INLINE signum #-}+ abs o = composeOp (o :& RNil) absOp+ {-# INLINE abs #-}+ fromInteger x = opConst (fromInteger x)+ {-# INLINE fromInteger #-} instance (RPureConstrained Num as, Fractional a) => Fractional (Op as a) where- o1 / o2 = composeOp (o1 :& o2 :& RNil) (/.)- recip o = composeOp (o :& RNil) recipOp- {-# INLINE recip #-}- fromRational x = opConst (fromRational x)- {-# INLINE fromRational #-}+ o1 / o2 = composeOp (o1 :& o2 :& RNil) (/.)+ recip o = composeOp (o :& RNil) recipOp+ {-# INLINE recip #-}+ fromRational x = opConst (fromRational x)+ {-# INLINE fromRational #-} instance (RPureConstrained Num as, Floating a) => Floating (Op as a) where- pi = opConst pi- {-# INLINE pi #-}- exp o = composeOp (o :& RNil) expOp- {-# INLINE exp #-}- log o = composeOp (o :& RNil) logOp- {-# INLINE log #-}- sqrt o = composeOp (o :& RNil) sqrtOp- {-# INLINE sqrt #-}- o1 ** o2 = composeOp (o1 :& o2 :& RNil) (**.)- {-# INLINE (**) #-}- logBase o1 o2 = composeOp (o1 :& o2 :& RNil) logBaseOp- {-# INLINE logBase #-}- sin o = composeOp (o :& RNil) sinOp- {-# INLINE sin #-}- cos o = composeOp (o :& RNil) cosOp- {-# INLINE cos #-}- tan o = composeOp (o :& RNil) tanOp- {-# INLINE tan #-}- asin o = composeOp (o :& RNil) asinOp- {-# INLINE asin #-}- acos o = composeOp (o :& RNil) acosOp- {-# INLINE acos #-}- atan o = composeOp (o :& RNil) atanOp- {-# INLINE atan #-}- sinh o = composeOp (o :& RNil) sinhOp- {-# INLINE sinh #-}- cosh o = composeOp (o :& RNil) coshOp- {-# INLINE cosh #-}- tanh o = composeOp (o :& RNil) tanhOp- {-# INLINE tanh #-}- asinh o = composeOp (o :& RNil) asinhOp- {-# INLINE asinh #-}- acosh o = composeOp (o :& RNil) acoshOp- {-# INLINE acosh #-}- atanh o = composeOp (o :& RNil) atanhOp- {-# INLINE atanh #-}+ pi = opConst pi+ {-# INLINE pi #-}+ exp o = composeOp (o :& RNil) expOp+ {-# INLINE exp #-}+ log o = composeOp (o :& RNil) logOp+ {-# INLINE log #-}+ sqrt o = composeOp (o :& RNil) sqrtOp+ {-# INLINE sqrt #-}+ o1 ** o2 = composeOp (o1 :& o2 :& RNil) (**.)+ {-# INLINE (**) #-}+ logBase o1 o2 = composeOp (o1 :& o2 :& RNil) logBaseOp+ {-# INLINE logBase #-}+ sin o = composeOp (o :& RNil) sinOp+ {-# INLINE sin #-}+ cos o = composeOp (o :& RNil) cosOp+ {-# INLINE cos #-}+ tan o = composeOp (o :& RNil) tanOp+ {-# INLINE tan #-}+ asin o = composeOp (o :& RNil) asinOp+ {-# INLINE asin #-}+ acos o = composeOp (o :& RNil) acosOp+ {-# INLINE acos #-}+ atan o = composeOp (o :& RNil) atanOp+ {-# INLINE atan #-}+ sinh o = composeOp (o :& RNil) sinhOp+ {-# INLINE sinh #-}+ cosh o = composeOp (o :& RNil) coshOp+ {-# INLINE cosh #-}+ tanh o = composeOp (o :& RNil) tanhOp+ {-# INLINE tanh #-}+ asinh o = composeOp (o :& RNil) asinhOp+ {-# INLINE asinh #-}+ acosh o = composeOp (o :& RNil) acoshOp+ {-# INLINE acosh #-}+ atanh o = composeOp (o :& RNil) atanhOp+ {-# INLINE atanh #-} -- $numops --@@ -632,32 +689,33 @@ -- | 'Op' for multiplication (*.) :: Num a => Op '[a, a] a-(*.) = op2 $ \x y -> (x * y, \g -> (y*g, x*g))+(*.) = op2 $ \x y -> (x * y, \g -> (y * g, x * g)) {-# INLINE (*.) #-} -- | 'Op' for division (/.) :: Fractional a => Op '[a, a] a-(/.) = op2 $ \x y -> (x / y, \g -> (g/y, -g*x/(y*y)))+(/.) = op2 $ \x y -> (x / y, \g -> (g / y, -(g * x / (y * y)))) {-# INLINE (/.) #-} -- | 'Op' for exponentiation (**.) :: Floating a => Op '[a, a] a-(**.) = op2 $ \x y -> ( x ** y- , let dx = y*x**(y-1)- dy = x**y*log x- in \g -> (g*dx, g*dy)- )+(**.) = op2 $ \x y ->+ ( x ** y+ , let dx = y * x ** (y - 1)+ dy = x ** y * log x+ in \g -> (g * dx, g * dy)+ ) {-# INLINE (**.) #-} -- | 'Op' for negation negateOp :: Num a => Op '[a] a negateOp = op1 $ \x -> (negate x, negate)-{-# INLINE negateOp #-}+{-# INLINE negateOp #-} -- | 'Op' for 'signum' signumOp :: Num a => Op '[a] a signumOp = op1 $ \x -> (signum x, const 0)-{-# INLINE signumOp #-}+{-# INLINE signumOp #-} -- | 'Op' for absolute value absOp :: Num a => Op '[a] a@@ -666,7 +724,7 @@ -- | 'Op' for multiplicative inverse recipOp :: Fractional a => Op '[a] a-recipOp = op1 $ \x -> (recip x, (/(x*x)) . negate)+recipOp = op1 $ \x -> (recip x, (/ (x * x)) . negate) {-# INLINE recipOp #-} -- | 'Op' for 'exp'@@ -676,7 +734,7 @@ -- | 'Op' for the natural logarithm logOp :: Floating a => Op '[a] a-logOp = op1 $ \x -> (log x, (/x))+logOp = op1 $ \x -> (log x, (/ x)) {-# INLINE logOp #-} -- | 'Op' for square root@@ -686,10 +744,11 @@ -- | 'Op' for 'logBase' logBaseOp :: Floating a => Op '[a, a] a-logBaseOp = op2 $ \x y -> ( logBase x y- , let dx = - logBase x y / (log x * x)- in \g -> (g*dx, g/(y * log x))- )+logBaseOp = op2 $ \x y ->+ ( logBase x y+ , let dx = -(logBase x y / (log x * x))+ in \g -> (g * dx, g / (y * log x))+ ) {-# INLINE logBaseOp #-} -- | 'Op' for sine@@ -704,22 +763,22 @@ -- | 'Op' for tangent tanOp :: Floating a => Op '[a] a-tanOp = op1 $ \x -> (tan x, (/ cos x^(2::Int)))+tanOp = op1 $ \x -> (tan x, (/ cos x ^ (2 :: Int))) {-# INLINE tanOp #-} -- | 'Op' for arcsine asinOp :: Floating a => Op '[a] a-asinOp = op1 $ \x -> (asin x, (/ sqrt(1 - x*x)))+asinOp = op1 $ \x -> (asin x, (/ sqrt (1 - x * x))) {-# INLINE asinOp #-} -- | 'Op' for arccosine acosOp :: Floating a => Op '[a] a-acosOp = op1 $ \x -> (acos x, (/ sqrt (1 - x*x)) . negate)+acosOp = op1 $ \x -> (acos x, (/ sqrt (1 - x * x)) . negate) {-# INLINE acosOp #-} -- | 'Op' for arctangent atanOp :: Floating a => Op '[a] a-atanOp = op1 $ \x -> (atan x, (/ (x*x + 1)))+atanOp = op1 $ \x -> (atan x, (/ (x * x + 1))) {-# INLINE atanOp #-} -- | 'Op' for hyperbolic sine@@ -734,22 +793,22 @@ -- | 'Op' for hyperbolic tangent tanhOp :: Floating a => Op '[a] a-tanhOp = op1 $ \x -> (tanh x, (/ cosh x^(2::Int)))+tanhOp = op1 $ \x -> (tanh x, (/ cosh x ^ (2 :: Int))) {-# INLINE tanhOp #-} -- | 'Op' for hyperbolic arcsine asinhOp :: Floating a => Op '[a] a-asinhOp = op1 $ \x -> (asinh x, (/ sqrt (x*x + 1)))+asinhOp = op1 $ \x -> (asinh x, (/ sqrt (x * x + 1))) {-# INLINE asinhOp #-} -- | 'Op' for hyperbolic arccosine acoshOp :: Floating a => Op '[a] a-acoshOp = op1 $ \x -> (acosh x, (/ sqrt (x*x - 1)))+acoshOp = op1 $ \x -> (acosh x, (/ sqrt (x * x - 1))) {-# INLINE acoshOp #-} -- | 'Op' for hyperbolic arctangent atanhOp :: Floating a => Op '[a] a-atanhOp = op1 $ \x -> (atanh x, (/ (1 - x*x)))+atanhOp = op1 $ \x -> (atanh x, (/ (1 - x * x))) {-# INLINE atanhOp #-} -- $prod@@ -776,4 +835,3 @@ -- z :: f c -- x :& y :& z :& RNil :: Rec f '[a, b, c] -- @---
src/Prelude/Backprop.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleContexts #-} -- | -- Module : Prelude.Backprop@@ -20,87 +20,101 @@ -- allowing you to provide 'zero', 'add', and 'one' explicitly. -- -- @since 0.1.3.0---- module Prelude.Backprop ( -- * Foldable and Traversable- sum- , product- , length- , minimum- , maximum- , traverse- , toList- , mapAccumL- , mapAccumR- , foldr, foldl'+ sum,+ product,+ length,+ minimum,+ maximum,+ traverse,+ toList,+ mapAccumL,+ mapAccumR,+ foldr,+ foldl',+ -- * Functor and Applicative- , fmap, fmapConst- , (<$>), (<$), ($>)- , pure- , liftA2- , liftA3+ fmap,+ fmapConst,+ (<$>),+ (<$),+ ($>),+ pure,+ liftA2,+ liftA3,+ -- * Numeric- , fromIntegral- , realToFrac- , round- , fromIntegral'+ fromIntegral,+ realToFrac,+ round,+ fromIntegral',+ -- * Misc- , E.coerce- ) where+ E.coerce,+) where -import Numeric.Backprop-import Prelude (Num(..), Fractional(..), Ord(..), Functor, Foldable, Traversable, Applicative)+import Numeric.Backprop import qualified Numeric.Backprop.Explicit as E-import qualified Prelude as P import qualified Prelude.Backprop.Explicit as E+import Prelude (+ Applicative,+ Foldable,+ Fractional (..),+ Functor,+ Num (..),+ Ord (..),+ Traversable,+ )+import qualified Prelude as P -- | Lifted 'P.sum'. More efficient than going through 'toList'.-sum :: (Foldable t, Functor t, Backprop (t a), Num a, Reifies s W)- => BVar s (t a)- -> BVar s a+sum ::+ (Foldable t, Functor t, Backprop (t a), Num a, Reifies s W) =>+ BVar s (t a) ->+ BVar s a sum = E.sum E.addFunc {-# INLINE sum #-} -- | Lifted 'P.pure'.-pure- :: (Foldable t, Applicative t, Backprop a, Reifies s W)- => BVar s a- -> BVar s (t a)+pure ::+ (Foldable t, Applicative t, Backprop a, Reifies s W) =>+ BVar s a ->+ BVar s (t a) pure = E.pure E.addFunc E.zeroFunc {-# INLINE pure #-} -- | Lifted 'P.product'. More efficient than going through 'toList'.-product- :: (Foldable t, Functor t, Backprop (t a), Fractional a, Reifies s W)- => BVar s (t a)- -> BVar s a+product ::+ (Foldable t, Functor t, Backprop (t a), Fractional a, Reifies s W) =>+ BVar s (t a) ->+ BVar s a product = E.product E.addFunc {-# INLINE product #-} -- | Lifted 'P.length'. More efficient than going through 'toList'.-length- :: (Foldable t, Backprop (t a), Num b, Reifies s W)- => BVar s (t a)- -> BVar s b+length ::+ (Foldable t, Backprop (t a), Num b, Reifies s W) =>+ BVar s (t a) ->+ BVar s b length = E.length E.addFunc E.zeroFunc {-# INLINE length #-} -- | Lifted 'P.minimum'. Undefined for situations where 'P.minimum' would -- be undefined. More efficient than going through 'toList'.-minimum- :: (Foldable t, Functor t, Backprop a, Ord a, Backprop (t a), Reifies s W)- => BVar s (t a)- -> BVar s a+minimum ::+ (Foldable t, Functor t, Backprop a, Ord a, Backprop (t a), Reifies s W) =>+ BVar s (t a) ->+ BVar s a minimum = E.minimum E.addFunc E.zeroFunc {-# INLINE minimum #-} -- | Lifted 'P.maximum'. Undefined for situations where 'P.maximum' would -- be undefined. More efficient than going through 'toList'.-maximum- :: (Foldable t, Functor t, Backprop a, Ord a, Backprop (t a), Reifies s W)- => BVar s (t a)- -> BVar s a+maximum ::+ (Foldable t, Functor t, Backprop a, Ord a, Backprop (t a), Reifies s W) =>+ BVar s (t a) ->+ BVar s a maximum = E.maximum E.addFunc E.zeroFunc {-# INLINE maximum #-} @@ -108,12 +122,12 @@ -- list 'P.foldr', and is only here for convenience. -- -- @since 0.2.3.0-foldr- :: (Traversable t, Backprop a, Reifies s W)- => (BVar s a -> BVar s b -> BVar s b)- -> BVar s b- -> BVar s (t a)- -> BVar s b+foldr ::+ (Traversable t, Backprop a, Reifies s W) =>+ (BVar s a -> BVar s b -> BVar s b) ->+ BVar s b ->+ BVar s (t a) ->+ BVar s b foldr = E.foldr E.addFunc E.zeroFunc {-# INLINE foldr #-} @@ -121,22 +135,22 @@ -- list 'P.foldl'', and is only here for convenience. -- -- @since 0.2.3.0-foldl'- :: (Traversable t, Backprop a, Reifies s W)- => (BVar s b -> BVar s a -> BVar s b)- -> BVar s b- -> BVar s (t a)- -> BVar s b+foldl' ::+ (Traversable t, Backprop a, Reifies s W) =>+ (BVar s b -> BVar s a -> BVar s b) ->+ BVar s b ->+ BVar s (t a) ->+ BVar s b foldl' = E.foldl' E.addFunc E.zeroFunc {-# INLINE foldl' #-} -- | Lifted 'P.fmap'. Lifts backpropagatable functions to be -- backpropagatable functions on 'Traversable' 'Functor's.-fmap- :: (Traversable f, Backprop a, Backprop b, Reifies s W)- => (BVar s a -> BVar s b)- -> BVar s (f a)- -> BVar s (f b)+fmap ::+ (Traversable f, Backprop a, Backprop b, Reifies s W) =>+ (BVar s a -> BVar s b) ->+ BVar s (f a) ->+ BVar s (f b) fmap = E.fmap E.addFunc E.addFunc E.zeroFunc E.zeroFunc {-# INLINE fmap #-} @@ -150,108 +164,136 @@ -- but much more efficient. -- -- @since 0.2.4.0-fmapConst- :: (Functor f, Foldable f, Backprop b, Backprop (f a), Reifies s W)- => BVar s b- -> BVar s (f a)- -> BVar s (f b)+fmapConst ::+ (Functor f, Foldable f, Backprop b, Backprop (f a), Reifies s W) =>+ BVar s b ->+ BVar s (f a) ->+ BVar s (f b) fmapConst = E.fmapConst E.addFunc E.addFunc E.zeroFunc E.zeroFunc {-# INLINE fmapConst #-} -- | Alias for 'fmap'.-(<$>)- :: (Traversable f, Backprop a, Backprop b, Reifies s W)- => (BVar s a -> BVar s b)- -> BVar s (f a)- -> BVar s (f b)+(<$>) ::+ (Traversable f, Backprop a, Backprop b, Reifies s W) =>+ (BVar s a -> BVar s b) ->+ BVar s (f a) ->+ BVar s (f b) (<$>) = fmap+ infixl 4 <$> {-# INLINE (<$>) #-} -- | Alias for 'fmapConst'. -- -- @since 0.2.4.0-(<$)- :: (Traversable f, Backprop b, Backprop (f a), Reifies s W)- => BVar s b- -> BVar s (f a)- -> BVar s (f b)+(<$) ::+ (Traversable f, Backprop b, Backprop (f a), Reifies s W) =>+ BVar s b ->+ BVar s (f a) ->+ BVar s (f b) (<$) = fmapConst+ infixl 4 <$ {-# INLINE (<$) #-} -- | Alias for @'flip' 'fmapConst'@. -- -- @since 0.2.4.0-($>)- :: (Traversable f, Backprop b, Backprop (f a), Reifies s W)- => BVar s (f a)- -> BVar s b- -> BVar s (f b)+($>) ::+ (Traversable f, Backprop b, Backprop (f a), Reifies s W) =>+ BVar s (f a) ->+ BVar s b ->+ BVar s (f b) xs $> x = x <$ xs+ infixl 4 $> {-# INLINE ($>) #-} -- | Lifted 'P.traverse'. Lifts backpropagatable functions to be -- backpropagatable functions on 'Traversable' 'Functor's.-traverse- :: (Traversable t, Applicative f, Foldable f, Backprop a, Backprop b, Backprop (t b), Reifies s W)- => (BVar s a -> f (BVar s b))- -> BVar s (t a)- -> BVar s (f (t b))-traverse = E.traverse E.addFunc E.addFunc E.addFunc- E.zeroFunc E.zeroFunc+traverse ::+ (Traversable t, Applicative f, Foldable f, Backprop a, Backprop b, Backprop (t b), Reifies s W) =>+ (BVar s a -> f (BVar s b)) ->+ BVar s (t a) ->+ BVar s (f (t b))+traverse =+ E.traverse+ E.addFunc+ E.addFunc+ E.addFunc+ E.zeroFunc+ E.zeroFunc {-# INLINE traverse #-} -- | Lifted 'P.liftA2'. Lifts backpropagatable functions to be -- backpropagatable functions on 'Traversable' 'Applicative's.-liftA2- :: ( Traversable f, Applicative f- , Backprop a, Backprop b, Backprop c- , Reifies s W- )- => (BVar s a -> BVar s b -> BVar s c)- -> BVar s (f a)- -> BVar s (f b)- -> BVar s (f c)-liftA2 = E.liftA2 E.addFunc E.addFunc E.addFunc- E.zeroFunc E.zeroFunc E.zeroFunc+liftA2 ::+ ( Traversable f+ , Applicative f+ , Backprop a+ , Backprop b+ , Backprop c+ , Reifies s W+ ) =>+ (BVar s a -> BVar s b -> BVar s c) ->+ BVar s (f a) ->+ BVar s (f b) ->+ BVar s (f c)+liftA2 =+ E.liftA2+ E.addFunc+ E.addFunc+ E.addFunc+ E.zeroFunc+ E.zeroFunc+ E.zeroFunc {-# INLINE liftA2 #-} -- | Lifted 'P.liftA3'. Lifts backpropagatable functions to be -- backpropagatable functions on 'Traversable' 'Applicative's.-liftA3- :: ( Traversable f- , Applicative f- , Backprop a, Backprop b, Backprop c, Backprop d- , Reifies s W- )- => (BVar s a -> BVar s b -> BVar s c -> BVar s d)- -> BVar s (f a)- -> BVar s (f b)- -> BVar s (f c)- -> BVar s (f d)-liftA3 = E.liftA3 E.addFunc E.addFunc E.addFunc E.addFunc- E.zeroFunc E.zeroFunc E.zeroFunc E.zeroFunc+liftA3 ::+ ( Traversable f+ , Applicative f+ , Backprop a+ , Backprop b+ , Backprop c+ , Backprop d+ , Reifies s W+ ) =>+ (BVar s a -> BVar s b -> BVar s c -> BVar s d) ->+ BVar s (f a) ->+ BVar s (f b) ->+ BVar s (f c) ->+ BVar s (f d)+liftA3 =+ E.liftA3+ E.addFunc+ E.addFunc+ E.addFunc+ E.addFunc+ E.zeroFunc+ E.zeroFunc+ E.zeroFunc+ E.zeroFunc {-# INLINE liftA3 #-} -- | Lifted conversion between two 'P.Integral' instances. -- -- @since 0.2.1.0-fromIntegral- :: (Backprop a, P.Integral a, P.Integral b, Reifies s W)- => BVar s a- -> BVar s b+fromIntegral ::+ (Backprop a, P.Integral a, P.Integral b, Reifies s W) =>+ BVar s a ->+ BVar s b fromIntegral = E.fromIntegral E.addFunc {-# INLINE fromIntegral #-} -- | Lifted conversion between two 'Fractional' and 'P.Real' instances. -- -- @since 0.2.1.0-realToFrac- :: (Backprop a, Fractional a, P.Real a, Fractional b, P.Real b, Reifies s W)- => BVar s a- -> BVar s b+realToFrac ::+ (Backprop a, Fractional a, P.Real a, Fractional b, P.Real b, Reifies s W) =>+ BVar s a ->+ BVar s b realToFrac = E.realToFrac E.addFunc {-# INLINE realToFrac #-} @@ -261,10 +303,10 @@ -- but does not do this for convenience reasons. -- -- @since 0.2.3.0-round- :: (P.RealFrac a, P.Integral b, Reifies s W)- => BVar s a- -> BVar s b+round ::+ (P.RealFrac a, P.Integral b, Reifies s W) =>+ BVar s a ->+ BVar s b round = E.round E.afNum {-# INLINE round #-} @@ -277,10 +319,10 @@ -- reasons. -- -- @since 0.2.3.0-fromIntegral'- :: (P.Integral a, P.RealFrac b, Reifies s W)- => BVar s a- -> BVar s b+fromIntegral' ::+ (P.Integral a, P.RealFrac b, Reifies s W) =>+ BVar s a ->+ BVar s b fromIntegral' = E.fromIntegral' E.afNum {-# INLINE fromIntegral' #-} @@ -293,10 +335,10 @@ -- @'P.minimum' . 'toList'.@ -- -- @since 0.2.2.0-toList- :: (Traversable t, Backprop a, Reifies s W)- => BVar s (t a)- -> [BVar s a]+toList ::+ (Traversable t, Backprop a, Reifies s W) =>+ BVar s (t a) ->+ [BVar s a] toList = E.toList E.addFunc E.zeroFunc {-# INLINE toList #-} @@ -305,12 +347,12 @@ -- Prior to v0.2.3, required a 'Backprop' constraint on @t b@. -- -- @since 0.2.2.0-mapAccumL- :: (Traversable t, Backprop b, Backprop c, Reifies s W)- => (BVar s a -> BVar s b -> (BVar s a, BVar s c))- -> BVar s a- -> BVar s (t b)- -> (BVar s a, BVar s (t c))+mapAccumL ::+ (Traversable t, Backprop b, Backprop c, Reifies s W) =>+ (BVar s a -> BVar s b -> (BVar s a, BVar s c)) ->+ BVar s a ->+ BVar s (t b) ->+ (BVar s a, BVar s (t c)) mapAccumL = E.mapAccumL E.addFunc E.addFunc E.zeroFunc E.zeroFunc {-# INLINE mapAccumL #-} @@ -319,12 +361,11 @@ -- Prior to v0.2.3, required a 'Backprop' constraint on @t b@. -- -- @since 0.2.2.0-mapAccumR- :: (Traversable t, Backprop b, Backprop c, Reifies s W)- => (BVar s a -> BVar s b -> (BVar s a, BVar s c))- -> BVar s a- -> BVar s (t b)- -> (BVar s a, BVar s (t c))+mapAccumR ::+ (Traversable t, Backprop b, Backprop c, Reifies s W) =>+ (BVar s a -> BVar s b -> (BVar s a, BVar s c)) ->+ BVar s a ->+ BVar s (t b) ->+ (BVar s a, BVar s (t c)) mapAccumR = E.mapAccumR E.addFunc E.addFunc E.zeroFunc E.zeroFunc {-# INLINE mapAccumR #-}-
src/Prelude/Backprop/Explicit.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE FlexibleContexts #-}-{-# OPTIONS_HADDOCK not-home #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_HADDOCK not-home #-} -- | -- Module : Prelude.Backprop.Explicit@@ -20,252 +20,271 @@ -- reflect changes in underlying implementation. -- -- @since 0.2.0.0- module Prelude.Backprop.Explicit ( -- * Foldable and Traversable- sum- , product- , length- , minimum- , maximum- , traverse- , toList- , mapAccumL- , mapAccumR- , foldr, foldl'+ sum,+ product,+ length,+ minimum,+ maximum,+ traverse,+ toList,+ mapAccumL,+ mapAccumR,+ foldr,+ foldl',+ -- * Functor and Applicative- , fmap, fmapConst- , pure- , liftA2- , liftA3+ fmap,+ fmapConst,+ pure,+ liftA2,+ liftA3,+ -- * Numeric- , fromIntegral- , realToFrac- , round- , fromIntegral'+ fromIntegral,+ realToFrac,+ round,+ fromIntegral',+ -- * Misc- , coerce- ) where+ coerce,+) where -import Data.Bifunctor-import Numeric.Backprop.Explicit-import Prelude (Num(..), Fractional(..), Eq(..), Ord(..), Functor, Foldable, Traversable, Applicative, (.), ($))-import qualified Control.Applicative as P-import qualified Data.Coerce as C-import qualified Data.Foldable as P-import qualified Data.Traversable as P-import qualified Prelude as P+import qualified Control.Applicative as P+import Data.Bifunctor+import qualified Data.Coerce as C+import qualified Data.Foldable as P+import qualified Data.Traversable as P+import Numeric.Backprop.Explicit+import Prelude (+ Applicative,+ Eq (..),+ Foldable,+ Fractional (..),+ Functor,+ Num (..),+ Ord (..),+ Traversable,+ ($),+ (.),+ )+import qualified Prelude as P -- | 'Prelude.Backprop.sum', but taking explicit 'add' and 'zero'.-sum :: (Foldable t, Functor t, Num a, Reifies s W)- => AddFunc (t a)- -> BVar s (t a)- -> BVar s a+sum ::+ (Foldable t, Functor t, Num a, Reifies s W) =>+ AddFunc (t a) ->+ BVar s (t a) ->+ BVar s a sum af = liftOp1 af . op1 $ \xs ->- ( P.sum xs- , (P.<$ xs)- )+ ( P.sum xs+ , (P.<$ xs)+ ) {-# INLINE sum #-} -- | 'Prelude.Backprop.pure', but taking explicit 'add' and 'zero'.-pure- :: (Foldable t, Applicative t, Reifies s W)- => AddFunc a- -> ZeroFunc a- -> BVar s a- -> BVar s (t a)+pure ::+ (Foldable t, Applicative t, Reifies s W) =>+ AddFunc a ->+ ZeroFunc a ->+ BVar s a ->+ BVar s (t a) pure af zfa = liftOp1 af . op1 $ \x ->- ( P.pure x- , \d -> case P.toList d of- [] -> runZF zfa x- e:es -> P.foldl' (runAF af) e es- )+ ( P.pure x+ , \d -> case P.toList d of+ [] -> runZF zfa x+ e : es -> P.foldl' (runAF af) e es+ ) {-# INLINE pure #-} -- | 'Prelude.Backprop.product', but taking explicit 'add' and 'zero'.-product- :: (Foldable t, Functor t, Fractional a, Reifies s W)- => AddFunc (t a)- -> BVar s (t a)- -> BVar s a+product ::+ (Foldable t, Functor t, Fractional a, Reifies s W) =>+ AddFunc (t a) ->+ BVar s (t a) ->+ BVar s a product af = liftOp1 af . op1 $ \xs ->- let p = P.product xs- in ( p- , \d -> (\x -> p * d / x) P.<$> xs- )+ let p = P.product xs+ in ( p+ , \d -> (\x -> p * d / x) P.<$> xs+ ) {-# INLINE product #-} -- | 'Prelude.Backprop.length', but taking explicit 'add' and 'zero'.-length- :: (Foldable t, Num b, Reifies s W)- => AddFunc (t a)- -> ZeroFunc (t a)- -> BVar s (t a)- -> BVar s b+length ::+ (Foldable t, Num b, Reifies s W) =>+ AddFunc (t a) ->+ ZeroFunc (t a) ->+ BVar s (t a) ->+ BVar s b length af zfa = liftOp1 af . op1 $ \xs ->- ( P.fromIntegral (P.length xs)- , P.const (runZF zfa xs)- )+ ( P.fromIntegral (P.length xs)+ , P.const (runZF zfa xs)+ ) {-# INLINE length #-} -- | 'Prelude.Backprop.minimum', but taking explicit 'add' and 'zero'.-minimum- :: (Foldable t, Functor t, Ord a, Reifies s W)- => AddFunc (t a)- -> ZeroFunc a- -> BVar s (t a)- -> BVar s a+minimum ::+ (Foldable t, Functor t, Ord a, Reifies s W) =>+ AddFunc (t a) ->+ ZeroFunc a ->+ BVar s (t a) ->+ BVar s a minimum af zf = liftOp1 af . op1 $ \xs ->- let m = P.minimum xs- in ( m- , \d -> (\x -> if x == m then d else runZF zf x) P.<$> xs- )+ let m = P.minimum xs+ in ( m+ , \d -> (\x -> if x == m then d else runZF zf x) P.<$> xs+ ) {-# INLINE minimum #-} -- | 'Prelude.Backprop.maximum', but taking explicit 'add' and 'zero'.-maximum- :: (Foldable t, Functor t, Ord a, Reifies s W)- => AddFunc (t a)- -> ZeroFunc a- -> BVar s (t a)- -> BVar s a+maximum ::+ (Foldable t, Functor t, Ord a, Reifies s W) =>+ AddFunc (t a) ->+ ZeroFunc a ->+ BVar s (t a) ->+ BVar s a maximum af zf = liftOp1 af . op1 $ \xs ->- let m = P.maximum xs- in ( m- , \d -> (\x -> if x == m then d else runZF zf x) P.<$> xs- )+ let m = P.maximum xs+ in ( m+ , \d -> (\x -> if x == m then d else runZF zf x) P.<$> xs+ ) {-# INLINE maximum #-} -- | 'Prelude.Backprop.foldr', but taking explicit 'add' and 'zero'. -- -- @since 0.2.3.0-foldr- :: (Traversable t, Reifies s W)- => AddFunc a- -> ZeroFunc a- -> (BVar s a -> BVar s b -> BVar s b)- -> BVar s b- -> BVar s (t a)- -> BVar s b+foldr ::+ (Traversable t, Reifies s W) =>+ AddFunc a ->+ ZeroFunc a ->+ (BVar s a -> BVar s b -> BVar s b) ->+ BVar s b ->+ BVar s (t a) ->+ BVar s b foldr af z f x = P.foldr f x . toList af z {-# INLINE foldr #-} -- | 'Prelude.Backprop.foldl'', but taking explicit 'add' and 'zero'. -- -- @since 0.2.3.0-foldl'- :: (Traversable t, Reifies s W)- => AddFunc a- -> ZeroFunc a- -> (BVar s b -> BVar s a -> BVar s b)- -> BVar s b- -> BVar s (t a)- -> BVar s b+foldl' ::+ (Traversable t, Reifies s W) =>+ AddFunc a ->+ ZeroFunc a ->+ (BVar s b -> BVar s a -> BVar s b) ->+ BVar s b ->+ BVar s (t a) ->+ BVar s b foldl' af z f x = P.foldl' f x . toList af z {-# INLINE foldl' #-} -- | 'Prelude.Backprop.fmap', but taking explicit 'add' and 'zero'.-fmap- :: (Traversable f, Reifies s W)- => AddFunc a- -> AddFunc b- -> ZeroFunc a- -> ZeroFunc b- -> (BVar s a -> BVar s b)- -> BVar s (f a)- -> BVar s (f b)+fmap ::+ (Traversable f, Reifies s W) =>+ AddFunc a ->+ AddFunc b ->+ ZeroFunc a ->+ ZeroFunc b ->+ (BVar s a -> BVar s b) ->+ BVar s (f a) ->+ BVar s (f b) fmap afa afb zfa zfb f = collectVar afb zfb . P.fmap f . sequenceVar afa zfa {-# INLINE fmap #-} -- | 'Prelude.Backprop.fmapConst', but taking explicit 'add' and 'zero'. -- -- @since 0.2.4.0-fmapConst- :: (Functor f, Foldable f, Reifies s W)- => AddFunc (f a)- -> AddFunc b- -> ZeroFunc (f a)- -> ZeroFunc b- -> BVar s b- -> BVar s (f a)- -> BVar s (f b)+fmapConst ::+ (Functor f, Foldable f, Reifies s W) =>+ AddFunc (f a) ->+ AddFunc b ->+ ZeroFunc (f a) ->+ ZeroFunc b ->+ BVar s b ->+ BVar s (f a) ->+ BVar s (f b) fmapConst afa afb zfa zfb = liftOp2 afb afa . op2 $ \x xs ->- ( x P.<$ xs- , \d -> ( case P.toList d of- [] -> runZF zfb x- e:es -> P.foldl' (runAF afb) e es- , runZF zfa xs- )- )+ ( x P.<$ xs+ , \d ->+ ( case P.toList d of+ [] -> runZF zfb x+ e : es -> P.foldl' (runAF afb) e es+ , runZF zfa xs+ )+ ) {-# INLINE fmapConst #-} -- | 'Prelude.Backprop.traverse', but taking explicit 'add' and 'zero'.-traverse- :: (Traversable t, Applicative f, Foldable f, Reifies s W)- => AddFunc a- -> AddFunc b- -> AddFunc (t b)- -> ZeroFunc a- -> ZeroFunc b- -> (BVar s a -> f (BVar s b))- -> BVar s (t a)- -> BVar s (f (t b))-traverse afa afb aftb zfa zfb f- = collectVar aftb zftb- . P.fmap (collectVar afb zfb)- . P.traverse f- . sequenceVar afa zfa+traverse ::+ (Traversable t, Applicative f, Foldable f, Reifies s W) =>+ AddFunc a ->+ AddFunc b ->+ AddFunc (t b) ->+ ZeroFunc a ->+ ZeroFunc b ->+ (BVar s a -> f (BVar s b)) ->+ BVar s (t a) ->+ BVar s (f (t b))+traverse afa afb aftb zfa zfb f =+ collectVar aftb zftb+ . P.fmap (collectVar afb zfb)+ . P.traverse f+ . sequenceVar afa zfa where zftb = ZF $ P.fmap (runZF zfb) {-# INLINE zftb #-} {-# INLINE traverse #-} -- | 'Prelude.Backprop.liftA2', but taking explicit 'add' and 'zero'.-liftA2- :: ( Traversable f- , Applicative f- , Reifies s W- )- => AddFunc a- -> AddFunc b- -> AddFunc c- -> ZeroFunc a- -> ZeroFunc b- -> ZeroFunc c- -> (BVar s a -> BVar s b -> BVar s c)- -> BVar s (f a)- -> BVar s (f b)- -> BVar s (f c)-liftA2 afa afb afc zfa zfb zfc f x y- = collectVar afc zfc- $ f P.<$> sequenceVar afa zfa x- P.<*> sequenceVar afb zfb y+liftA2 ::+ ( Traversable f+ , Applicative f+ , Reifies s W+ ) =>+ AddFunc a ->+ AddFunc b ->+ AddFunc c ->+ ZeroFunc a ->+ ZeroFunc b ->+ ZeroFunc c ->+ (BVar s a -> BVar s b -> BVar s c) ->+ BVar s (f a) ->+ BVar s (f b) ->+ BVar s (f c)+liftA2 afa afb afc zfa zfb zfc f x y =+ collectVar afc zfc $+ f+ P.<$> sequenceVar afa zfa x+ P.<*> sequenceVar afb zfb y {-# INLINE liftA2 #-} -- | 'Prelude.Backprop.liftA3', but taking explicit 'add' and 'zero'.-liftA3- :: ( Traversable f- , Applicative f- , Reifies s W- )- => AddFunc a- -> AddFunc b- -> AddFunc c- -> AddFunc d- -> ZeroFunc a- -> ZeroFunc b- -> ZeroFunc c- -> ZeroFunc d- -> (BVar s a -> BVar s b -> BVar s c -> BVar s d)- -> BVar s (f a)- -> BVar s (f b)- -> BVar s (f c)- -> BVar s (f d)-liftA3 afa afb afc afd zfa zfb zfc zfd f x y z- = collectVar afd zfd- $ f P.<$> sequenceVar afa zfa x- P.<*> sequenceVar afb zfb y- P.<*> sequenceVar afc zfc z+liftA3 ::+ ( Traversable f+ , Applicative f+ , Reifies s W+ ) =>+ AddFunc a ->+ AddFunc b ->+ AddFunc c ->+ AddFunc d ->+ ZeroFunc a ->+ ZeroFunc b ->+ ZeroFunc c ->+ ZeroFunc d ->+ (BVar s a -> BVar s b -> BVar s c -> BVar s d) ->+ BVar s (f a) ->+ BVar s (f b) ->+ BVar s (f c) ->+ BVar s (f d)+liftA3 afa afb afc afd zfa zfb zfc zfd f x y z =+ collectVar afd zfd $+ f+ P.<$> sequenceVar afa zfa x+ P.<*> sequenceVar afb zfb y+ P.<*> sequenceVar afc zfc z {-# INLINE liftA3 #-} -- | Coerce items inside a 'BVar'.@@ -276,33 +295,33 @@ -- | 'Prelude.Backprop.fromIntegral', but taking explicit 'add' and 'zero'. -- -- @since 0.2.1.0-fromIntegral- :: (P.Integral a, P.Integral b, Reifies s W)- => AddFunc a- -> BVar s a- -> BVar s b+fromIntegral ::+ (P.Integral a, P.Integral b, Reifies s W) =>+ AddFunc a ->+ BVar s a ->+ BVar s b fromIntegral af = isoVar af P.fromIntegral P.fromIntegral {-# INLINE fromIntegral #-} -- | 'Prelude.Backprop.realToFrac', but taking explicit 'add' and 'zero'. -- -- @since 0.2.1.0-realToFrac- :: (Fractional a, P.Real a, Fractional b, P.Real b, Reifies s W)- => AddFunc a- -> BVar s a- -> BVar s b+realToFrac ::+ (Fractional a, P.Real a, Fractional b, P.Real b, Reifies s W) =>+ AddFunc a ->+ BVar s a ->+ BVar s b realToFrac af = isoVar af P.realToFrac P.realToFrac {-# INLINE realToFrac #-} -- | 'Prelude.Backprop.round', but taking explicit 'add' and 'zero'. -- -- @since 0.2.3.0-round- :: (P.RealFrac a, P.Integral b, Reifies s W)- => AddFunc a- -> BVar s a- -> BVar s b+round ::+ (P.RealFrac a, P.Integral b, Reifies s W) =>+ AddFunc a ->+ BVar s a ->+ BVar s b round af = isoVar af P.round P.fromIntegral {-# INLINE round #-} @@ -310,60 +329,60 @@ -- 'zero'. -- -- @since 0.2.3.0-fromIntegral'- :: (P.Integral a, P.RealFrac b, Reifies s W)- => AddFunc a- -> BVar s a- -> BVar s b+fromIntegral' ::+ (P.Integral a, P.RealFrac b, Reifies s W) =>+ AddFunc a ->+ BVar s a ->+ BVar s b fromIntegral' af = isoVar af P.fromIntegral P.round {-# INLINE fromIntegral' #-} -- | 'Prelude.Backprop.length', but taking explicit 'add' and 'zero'. -- -- @since 0.2.2.0-toList- :: (Traversable t, Reifies s W)- => AddFunc a- -> ZeroFunc a- -> BVar s (t a)- -> [BVar s a]+toList ::+ (Traversable t, Reifies s W) =>+ AddFunc a ->+ ZeroFunc a ->+ BVar s (t a) ->+ [BVar s a] toList af z = toListOfVar af (ZF (P.fmap (runZF z))) P.traverse {-# INLINE toList #-} -- | 'Prelude.Backprop.mapAccumL', but taking explicit 'add' and 'zero'. -- -- @since 0.2.2.0-mapAccumL- :: (Traversable t, Reifies s W)- => AddFunc b- -> AddFunc c- -> ZeroFunc b- -> ZeroFunc c- -> (BVar s a -> BVar s b -> (BVar s a, BVar s c))- -> BVar s a- -> BVar s (t b)- -> (BVar s a, BVar s (t c))+mapAccumL ::+ (Traversable t, Reifies s W) =>+ AddFunc b ->+ AddFunc c ->+ ZeroFunc b ->+ ZeroFunc c ->+ (BVar s a -> BVar s b -> (BVar s a, BVar s c)) ->+ BVar s a ->+ BVar s (t b) ->+ (BVar s a, BVar s (t c)) mapAccumL afb afc zfb zfc f s =- second (collectVar afc zfc)- . P.mapAccumL f s- . sequenceVar afb zfb+ second (collectVar afc zfc)+ . P.mapAccumL f s+ . sequenceVar afb zfb {-# INLINE mapAccumL #-} -- | 'Prelude.Backprop.mapAccumR', but taking explicit 'add' and 'zero'. -- -- @since 0.2.2.0-mapAccumR- :: (Traversable t, Reifies s W)- => AddFunc b- -> AddFunc c- -> ZeroFunc b- -> ZeroFunc c- -> (BVar s a -> BVar s b -> (BVar s a, BVar s c))- -> BVar s a- -> BVar s (t b)- -> (BVar s a, BVar s (t c))+mapAccumR ::+ (Traversable t, Reifies s W) =>+ AddFunc b ->+ AddFunc c ->+ ZeroFunc b ->+ ZeroFunc c ->+ (BVar s a -> BVar s b -> (BVar s a, BVar s c)) ->+ BVar s a ->+ BVar s (t b) ->+ (BVar s a, BVar s (t c)) mapAccumR afb afc zfb zfc f s =- second (collectVar afc zfc)- . P.mapAccumR f s- . sequenceVar afb zfb+ second (collectVar afc zfc)+ . P.mapAccumR f s+ . sequenceVar afb zfb {-# INLINE mapAccumR #-}
src/Prelude/Backprop/Num.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE FlexibleContexts #-}-{-# OPTIONS_HADDOCK not-home #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_HADDOCK not-home #-} -- | -- Module : Prelude.Backprop.Num@@ -14,90 +14,105 @@ -- 'Num' instances for all types involved instead of 'Backprop' instances. -- -- @since 0.2.0.0- module Prelude.Backprop.Num ( -- * Foldable and Traversable- sum- , product- , length- , minimum- , maximum- , traverse- , toList- , mapAccumL- , mapAccumR- , foldr, foldl'+ sum,+ product,+ length,+ minimum,+ maximum,+ traverse,+ toList,+ mapAccumL,+ mapAccumR,+ foldr,+ foldl',+ -- * Functor and Applicative- , fmap, fmapConst- , (<$>), (<$), ($>)- , pure- , liftA2- , liftA3+ fmap,+ fmapConst,+ (<$>),+ (<$),+ ($>),+ pure,+ liftA2,+ liftA3,+ -- * Numeric- , fromIntegral- , realToFrac- , round- , fromIntegral'+ fromIntegral,+ realToFrac,+ round,+ fromIntegral',+ -- * Misc- , E.coerce- ) where+ E.coerce,+) where -import Numeric.Backprop.Num-import Prelude (Num(..), Fractional(..), Ord(..), Functor, Foldable, Traversable, Applicative) import qualified Numeric.Backprop.Explicit as E-import qualified Prelude as P+import Numeric.Backprop.Num import qualified Prelude.Backprop.Explicit as E+import Prelude (+ Applicative,+ Foldable,+ Fractional (..),+ Functor,+ Num (..),+ Ord (..),+ Traversable,+ )+import qualified Prelude as P -- | 'Prelude.Backprop.sum', but with 'Num' constraints instead of -- 'Backprop' constraints.-sum :: (Foldable t, Functor t, Num (t a), Num a, Reifies s W)- => BVar s (t a)- -> BVar s a+sum ::+ (Foldable t, Functor t, Num (t a), Num a, Reifies s W) =>+ BVar s (t a) ->+ BVar s a sum = E.sum E.afNum {-# INLINE sum #-} -- | 'Prelude.Backprop.pure', but with 'Num' constraints instead of -- 'Backprop' constraints.-pure- :: (Foldable t, Applicative t, Num a, Reifies s W)- => BVar s a- -> BVar s (t a)+pure ::+ (Foldable t, Applicative t, Num a, Reifies s W) =>+ BVar s a ->+ BVar s (t a) pure = E.pure E.afNum E.zfNum {-# INLINE pure #-} -- | 'Prelude.Backprop.product', but with 'Num' constraints instead of -- 'Backprop' constraints.-product- :: (Foldable t, Functor t, Num (t a), Fractional a, Reifies s W)- => BVar s (t a)- -> BVar s a+product ::+ (Foldable t, Functor t, Num (t a), Fractional a, Reifies s W) =>+ BVar s (t a) ->+ BVar s a product = E.product E.afNum {-# INLINE product #-} -- | 'Prelude.Backprop.length', but with 'Num' constraints instead of -- 'Backprop' constraints.-length- :: (Foldable t, Num (t a), Num b, Reifies s W)- => BVar s (t a)- -> BVar s b+length ::+ (Foldable t, Num (t a), Num b, Reifies s W) =>+ BVar s (t a) ->+ BVar s b length = E.length E.afNum E.zfNum {-# INLINE length #-} -- | 'Prelude.Backprop.minimum', but with 'Num' constraints instead of -- 'Backprop' constraints.-minimum- :: (Foldable t, Functor t, Num a, Ord a, Num (t a), Reifies s W)- => BVar s (t a)- -> BVar s a+minimum ::+ (Foldable t, Functor t, Num a, Ord a, Num (t a), Reifies s W) =>+ BVar s (t a) ->+ BVar s a minimum = E.minimum E.afNum E.zfNum {-# INLINE minimum #-} -- | 'Prelude.Backprop.maximum', but with 'Num' constraints instead of -- 'Backprop' constraints.-maximum- :: (Foldable t, Functor t, Num a, Ord a, Num (t a), Reifies s W)- => BVar s (t a)- -> BVar s a+maximum ::+ (Foldable t, Functor t, Num a, Ord a, Num (t a), Reifies s W) =>+ BVar s (t a) ->+ BVar s a maximum = E.maximum E.afNum E.zfNum {-# INLINE maximum #-} @@ -105,12 +120,12 @@ -- 'Backprop' constraints. -- -- @since 0.2.3.0-foldr- :: (Traversable t, Num a, Reifies s W)- => (BVar s a -> BVar s b -> BVar s b)- -> BVar s b- -> BVar s (t a)- -> BVar s b+foldr ::+ (Traversable t, Num a, Reifies s W) =>+ (BVar s a -> BVar s b -> BVar s b) ->+ BVar s b ->+ BVar s (t a) ->+ BVar s b foldr = E.foldr E.afNum E.zfNum {-# INLINE foldr #-} @@ -118,22 +133,22 @@ -- 'Backprop' constraints. -- -- @since 0.2.3.0-foldl'- :: (Traversable t, Num a, Reifies s W)- => (BVar s b -> BVar s a -> BVar s b)- -> BVar s b- -> BVar s (t a)- -> BVar s b+foldl' ::+ (Traversable t, Num a, Reifies s W) =>+ (BVar s b -> BVar s a -> BVar s b) ->+ BVar s b ->+ BVar s (t a) ->+ BVar s b foldl' = E.foldl' E.afNum E.zfNum {-# INLINE foldl' #-} -- | 'Prelude.Backprop.fmap', but with 'Num' constraints instead of -- 'Backprop' constraints.-fmap- :: (Traversable f, Num a, Num b, Reifies s W)- => (BVar s a -> BVar s b)- -> BVar s (f a)- -> BVar s (f b)+fmap ::+ (Traversable f, Num a, Num b, Reifies s W) =>+ (BVar s a -> BVar s b) ->+ BVar s (f a) ->+ BVar s (f b) fmap = E.fmap E.afNum E.afNum E.zfNum E.zfNum {-# INLINE fmap #-} @@ -141,45 +156,48 @@ -- 'Backprop' constraints. -- -- @since 0.2.4.0-fmapConst- :: (Functor f, Foldable f, Num b, Num (f a), Reifies s W)- => BVar s b- -> BVar s (f a)- -> BVar s (f b)+fmapConst ::+ (Functor f, Foldable f, Num b, Num (f a), Reifies s W) =>+ BVar s b ->+ BVar s (f a) ->+ BVar s (f b) fmapConst = E.fmapConst E.afNum E.afNum E.zfNum E.zfNum {-# INLINE fmapConst #-} -- | Alias for 'fmap'.-(<$>)- :: (Traversable f, Num a, Num b, Reifies s W)- => (BVar s a -> BVar s b)- -> BVar s (f a)- -> BVar s (f b)+(<$>) ::+ (Traversable f, Num a, Num b, Reifies s W) =>+ (BVar s a -> BVar s b) ->+ BVar s (f a) ->+ BVar s (f b) (<$>) = fmap+ infixl 4 <$> {-# INLINE (<$>) #-} -- | Alias for 'fmapConst'. -- -- @since 0.2.4.0-(<$)- :: (Functor f, Foldable f, Num b, Num (f a), Reifies s W)- => BVar s b- -> BVar s (f a)- -> BVar s (f b)+(<$) ::+ (Functor f, Foldable f, Num b, Num (f a), Reifies s W) =>+ BVar s b ->+ BVar s (f a) ->+ BVar s (f b) (<$) = fmapConst+ infixl 4 <$ {-# INLINE (<$) #-} -- | Alias for @'flip' 'fmapConst'@. -- -- @since 0.2.4.0-($>)- :: (Functor f, Foldable f, Num b, Num (f a), Reifies s W)- => BVar s (f a)- -> BVar s b- -> BVar s (f b)+($>) ::+ (Functor f, Foldable f, Num b, Num (f a), Reifies s W) =>+ BVar s (f a) ->+ BVar s b ->+ BVar s (f b) xs $> x = x <$ xs+ infixl 4 $> {-# INLINE ($>) #-} @@ -188,54 +206,67 @@ -- -- See <https://hackage.haskell.org/package/vector-sized vector-sized> for -- a fixed-length vector type with a very appropriate 'Num' instance!-traverse- :: (Traversable t, Applicative f, Foldable f, Num a, Num b, Num (t b), Reifies s W)- => (BVar s a -> f (BVar s b))- -> BVar s (t a)- -> BVar s (f (t b))+traverse ::+ (Traversable t, Applicative f, Foldable f, Num a, Num b, Num (t b), Reifies s W) =>+ (BVar s a -> f (BVar s b)) ->+ BVar s (t a) ->+ BVar s (f (t b)) traverse = E.traverse E.afNum E.afNum E.afNum E.zfNum E.zfNum {-# INLINE traverse #-} -- | 'Prelude.Backprop.liftA2', but with 'Num' constraints instead of -- 'Backprop' constraints.-liftA2- :: ( Traversable f- , Applicative f- , Num a, Num b, Num c- , Reifies s W- )- => (BVar s a -> BVar s b -> BVar s c)- -> BVar s (f a)- -> BVar s (f b)- -> BVar s (f c)+liftA2 ::+ ( Traversable f+ , Applicative f+ , Num a+ , Num b+ , Num c+ , Reifies s W+ ) =>+ (BVar s a -> BVar s b -> BVar s c) ->+ BVar s (f a) ->+ BVar s (f b) ->+ BVar s (f c) liftA2 = E.liftA2 E.afNum E.afNum E.afNum E.zfNum E.zfNum E.zfNum {-# INLINE liftA2 #-} -- | 'Prelude.Backprop.liftA3', but with 'Num' constraints instead of -- 'Backprop' constraints.-liftA3- :: ( Traversable f- , Applicative f- , Num a, Num b, Num c, Num d- , Reifies s W- )- => (BVar s a -> BVar s b -> BVar s c -> BVar s d)- -> BVar s (f a)- -> BVar s (f b)- -> BVar s (f c)- -> BVar s (f d)-liftA3 = E.liftA3 E.afNum E.afNum E.afNum E.afNum- E.zfNum E.zfNum E.zfNum E.zfNum+liftA3 ::+ ( Traversable f+ , Applicative f+ , Num a+ , Num b+ , Num c+ , Num d+ , Reifies s W+ ) =>+ (BVar s a -> BVar s b -> BVar s c -> BVar s d) ->+ BVar s (f a) ->+ BVar s (f b) ->+ BVar s (f c) ->+ BVar s (f d)+liftA3 =+ E.liftA3+ E.afNum+ E.afNum+ E.afNum+ E.afNum+ E.zfNum+ E.zfNum+ E.zfNum+ E.zfNum {-# INLINE liftA3 #-} -- | 'Prelude.Backprop.fromIntegral', but with 'Num' constraints instead of -- 'Backprop' constraints. -- -- @since 0.2.1.0-fromIntegral- :: (P.Integral a, P.Integral b, Reifies s W)- => BVar s a- -> BVar s b+fromIntegral ::+ (P.Integral a, P.Integral b, Reifies s W) =>+ BVar s a ->+ BVar s b fromIntegral = E.fromIntegral E.afNum {-# INLINE fromIntegral #-} @@ -243,10 +274,10 @@ -- 'Backprop' constraints. -- -- @since 0.2.1.0-realToFrac- :: (Fractional a, P.Real a, Fractional b, P.Real b, Reifies s W)- => BVar s a- -> BVar s b+realToFrac ::+ (Fractional a, P.Real a, Fractional b, P.Real b, Reifies s W) =>+ BVar s a ->+ BVar s b realToFrac = E.realToFrac E.afNum {-# INLINE realToFrac #-} @@ -254,10 +285,10 @@ -- 'Backprop' constraints. -- -- @since 0.2.3.0-round- :: (P.RealFrac a, P.Integral b, Reifies s W)- => BVar s a- -> BVar s b+round ::+ (P.RealFrac a, P.Integral b, Reifies s W) =>+ BVar s a ->+ BVar s b round = E.round E.afNum {-# INLINE round #-} @@ -265,10 +296,10 @@ -- of 'Backprop' constraints. -- -- @since 0.2.3.0-fromIntegral'- :: (P.Integral a, P.RealFrac b, Reifies s W)- => BVar s a- -> BVar s b+fromIntegral' ::+ (P.Integral a, P.RealFrac b, Reifies s W) =>+ BVar s a ->+ BVar s b fromIntegral' = E.fromIntegral' E.afNum {-# INLINE fromIntegral' #-} @@ -276,10 +307,10 @@ -- 'Backprop' constraints. -- -- @since 0.2.2.0-toList- :: (Traversable t, Num a, Reifies s W)- => BVar s (t a)- -> [BVar s a]+toList ::+ (Traversable t, Num a, Reifies s W) =>+ BVar s (t a) ->+ [BVar s a] toList = E.toList E.afNum E.zfNum {-# INLINE toList #-} @@ -289,12 +320,12 @@ -- Prior to v0.2.3, required a 'Num' constraint on @t b@. -- -- @since 0.2.2.0-mapAccumL- :: (Traversable t, Num b, Num c, Reifies s W)- => (BVar s a -> BVar s b -> (BVar s a, BVar s c))- -> BVar s a- -> BVar s (t b)- -> (BVar s a, BVar s (t c))+mapAccumL ::+ (Traversable t, Num b, Num c, Reifies s W) =>+ (BVar s a -> BVar s b -> (BVar s a, BVar s c)) ->+ BVar s a ->+ BVar s (t b) ->+ (BVar s a, BVar s (t c)) mapAccumL = E.mapAccumL E.afNum E.afNum E.zfNum E.zfNum {-# INLINE mapAccumL #-} @@ -304,12 +335,11 @@ -- Prior to v0.2.3, required a 'Num' constraint on @t b@. -- -- @since 0.2.2.0-mapAccumR- :: (Traversable t, Num b, Num c, Reifies s W)- => (BVar s a -> BVar s b -> (BVar s a, BVar s c))- -> BVar s a- -> BVar s (t b)- -> (BVar s a, BVar s (t c))+mapAccumR ::+ (Traversable t, Num b, Num c, Reifies s W) =>+ (BVar s a -> BVar s b -> (BVar s a, BVar s c)) ->+ BVar s a ->+ BVar s (t b) ->+ (BVar s a, BVar s (t c)) mapAccumR = E.mapAccumR E.afNum E.afNum E.zfNum E.zfNum {-# INLINE mapAccumR #-}-