Copyright | (c) Justin Le 2017 |
---|---|

License | BSD3 |

Maintainer | justin@jle.im |

Stability | experimental |

Portability | non-portable |

Safe Haskell | None |

Language | Haskell2010 |

Provides the `BP`

monad and the `BVar`

type; after manipulating `BVar`

s
(inputs to your function) to produce a result, the library tracks internal data
dependencies, which are used to perform back-propagation (reverse-mode
automatic differentiation) to calculate the gradient of the output with
respect to the inputs.

Similar to automatic differentiation from the *ad* library and
Numeric.AD.Mode.Reverse, except for a few key differences:

- Most importantly, this library implements
*heterogeneous*back-propagation, so you can manipulate values of different types (like different matrix and vector types, and product and sum types). This is essential for things like back-propagation for neural networks. - This module allows you to
*explicitly*build your data dependency graph if you wish, which allows the library to perform optimizations and reduce extra allocation, which may or may not provide advantages over Numeric.AD.Mode.Reverse's`unsafePerformIO`

-based implicit graph building.

See the README for more information
and links to demonstrations and tutorials. If you want to plunge right
in, you can also look directly at the main types, `BP`

, `BPOp`

, `BVar`

,
`Op`

, and the main functions, `backprop`

and `opVar`

.

Note that every type involved has to be an instance of `Num`

. This is
because gradients all need to be "summable" (which is implemented using
`sum`

and `+`

), and we also need to able to generate gradients of '1'
and '0'.

- data BP s rs a
- type BPOp s rs a = BP s rs (BVar s rs a)
- type BPOpI s rs a = Prod (BVar s rs) rs -> BVar s rs a
- data BVar :: Type -> [Type] -> Type -> Type
- type Op as a = forall m. Monad m => OpM m as a
- type OpB s as a = OpM (ST s) as a
- data Prod k f a :: forall k. (k -> *) -> [k] -> * where
- type Tuple = Prod * I
- newtype I a :: * -> * = I {
- getI :: a

- backprop :: Every Num rs => (forall s. BPOp s rs a) -> Tuple rs -> (a, Tuple rs)
- evalBPOp :: (forall s. BPOp s rs a) -> Tuple rs -> a
- gradBPOp :: Every Num rs => (forall s. BPOp s rs a) -> Tuple rs -> Tuple rs
- withInps :: Known Length rs => (Prod (BVar s rs) rs -> BP s rs a) -> BP s rs a
- implicitly :: (Known Length rs, Num a) => BPOpI s rs a -> BPOp s rs a
- withInps' :: Length rs -> (Prod (BVar s rs) rs -> BP s rs a) -> BP s rs a
- implicitly' :: Num a => Length rs -> BPOpI s rs a -> BPOp s rs a
- constVar :: a -> BVar s rs a
- inpVar :: Index rs a -> BVar s rs a
- inpVars :: Known Length rs => Prod (BVar s rs) rs
- bpOp :: Every Num rs => BPOp s rs a -> OpB s rs a
- bindVar :: Num a => BVar s rs a -> BP s rs (BVar s rs a)
- inpVars' :: Length rs -> Prod (BVar s rs) rs
- opVar :: forall s rs as a. Num a => OpB s as a -> Prod (BVar s rs) as -> BP s rs (BVar s rs a)
- (~$) :: Num a => OpB s as a -> Prod (BVar s rs) as -> BP s rs (BVar s rs a)
- opVar1 :: Num b => OpB s '[a] b -> BVar s rs a -> BP s rs (BVar s rs b)
- opVar2 :: Num c => OpB s '[a, b] c -> BVar s rs a -> BVar s rs b -> BP s rs (BVar s rs c)
- opVar3 :: Num d => OpB s '[a, b, c] d -> BVar s rs a -> BVar s rs b -> BVar s rs c -> BP s rs (BVar s rs d)
- (-$) :: (Every Num as, Known Length as, Num a) => BPOp s as a -> Prod (BVar s rs) as -> BPOp s rs a
- partsVar :: forall s rs bs b. Every Num bs => Iso' b (Tuple bs) -> BVar s rs b -> BP s rs (Prod (BVar s rs) bs)
- (#<~) :: (Every Num bs, Known Length bs) => Iso' b (Tuple bs) -> BVar s rs b -> BP s rs (Prod (BVar s rs) bs)
- withParts :: Every Num bs => Iso' b (Tuple bs) -> BVar s rs b -> (Prod (BVar s rs) bs -> BP s rs a) -> BP s rs a
- splitVars :: forall s rs as. Every Num as => BVar s rs (Tuple as) -> BP s rs (Prod (BVar s rs) as)
- gSplit :: (Every Num bs, Generic b, Code b ~ '[bs]) => BVar s rs b -> BP s rs (Prod (BVar s rs) bs)
- gTuple :: (Generic a, Code a ~ '[as]) => Iso' a (Tuple as)
- choicesVar :: forall s rs bs b. Every Num bs => Iso' b (Sum I bs) -> BVar s rs b -> BP s rs (Sum (BVar s rs) bs)
- (?<~) :: (Every Num bs, Known Length bs) => Iso' b (Sum I bs) -> BVar s rs b -> BP s rs (Sum (BVar s rs) bs)
- withChoices :: forall s rs bs b a. Every Num bs => Iso' b (Sum I bs) -> BVar s rs b -> (Sum (BVar s rs) bs -> BP s rs a) -> BP s rs a
- data Sum k f a :: forall k. (k -> *) -> [k] -> * where
- sopVar :: forall s rs bss b. Every (Every Num) bss => Iso' b (Sum Tuple bss) -> BVar s rs b -> BP s rs (Sum (Prod (BVar s rs)) bss)
- gSplits :: forall s rs b. (Generic b, Every (Every Num) (Code b)) => BVar s rs b -> BP s rs (Sum (Prod (BVar s rs)) (Code b))
- gSOP :: Generic a => Iso' a (Sum Tuple (Code a))
- withGADT :: forall s rs a b. BVar s rs a -> (a -> BPCont s rs a b) -> BP s rs b
- data BPCont :: Type -> [Type] -> Type -> Type -> Type where
- liftB :: OpB s as a -> Prod (BVar s rs) as -> BVar s rs a
- (.$) :: OpB s as a -> Prod (BVar s rs) as -> BVar s rs a
- liftB1 :: OpB s '[a] b -> BVar s rs a -> BVar s rs b
- liftB2 :: OpB s '[a, b] c -> BVar s rs a -> BVar s rs b -> BVar s rs c
- liftB3 :: OpB s '[a, b, c] d -> BVar s rs a -> BVar s rs b -> BVar s rs c -> BVar s rs d
- op1 :: Num a => (forall s. AD s (Forward a) -> AD s (Forward a)) -> Op '[a] a
- op2 :: Num a => (forall s. Reifies s Tape => Reverse s a -> Reverse s a -> Reverse s a) -> Op '[a, a] a
- op3 :: Num a => (forall s. Reifies s Tape => Reverse s a -> Reverse s a -> Reverse s a -> Reverse s a) -> Op '[a, a, a] a
- opN :: (Num a, Known Nat n) => (forall s. Reifies s Tape => Vec n (Reverse s a) -> Reverse s a) -> Op (Replicate n a) a
- composeOp :: (Monad m, Every Num as, Known Length as) => Prod (OpM m as) bs -> OpM m bs c -> OpM m as c
- composeOp1 :: (Monad m, Every Num as, Known Length as) => OpM m as b -> OpM m '[b] c -> OpM m as c
- (~.) :: (Monad m, Known Length as, Every Num as) => OpM m '[b] c -> OpM m as b -> OpM m as c
- op1' :: (a -> (b, Maybe b -> a)) -> Op '[a] b
- op2' :: (a -> b -> (c, Maybe c -> (a, b))) -> Op '[a, b] c
- op3' :: (a -> b -> c -> (d, Maybe d -> (a, b, c))) -> Op '[a, b, c] d
- pattern (:>) :: forall k f a b. f a -> f b -> Prod k f ((:) k a ((:) k b ([] k)))
- only :: f a -> Prod k f ((:) k a ([] k))
- head' :: Prod k f ((:<) k a as) -> f a
- pattern (::<) :: forall a as. a -> Tuple as -> Tuple ((:<) * a as)
- only_ :: a -> Tuple ((:) * a ([] *))
- (+.) :: Num a => Op '[a, a] a
- (-.) :: Num a => Op '[a, a] a
- (*.) :: Num a => Op '[a, a] a
- negateOp :: Num a => Op '[a] a
- absOp :: Num a => Op '[a] a
- signumOp :: Num a => Op '[a] a
- (/.) :: Fractional a => Op '[a, a] a
- recipOp :: Fractional a => Op '[a] a
- expOp :: Floating a => Op '[a] a
- logOp :: Floating a => Op '[a] a
- sqrtOp :: Floating a => Op '[a] a
- (**.) :: Floating a => Op '[a, a] a
- logBaseOp :: Floating a => Op '[a, a] a
- sinOp :: Floating a => Op '[a] a
- cosOp :: Floating a => Op '[a] a
- tanOp :: Floating a => Op '[a] a
- asinOp :: Floating a => Op '[a] a
- acosOp :: Floating a => Op '[a] a
- atanOp :: Floating a => Op '[a] a
- sinhOp :: Floating a => Op '[a] a
- coshOp :: Floating a => Op '[a] a
- tanhOp :: Floating a => Op '[a] a
- asinhOp :: Floating a => Op '[a] a
- acoshOp :: Floating a => Op '[a] a
- atanhOp :: Floating a => Op '[a] a

# Types

## Backprop types

A Monad allowing you to explicitly build hetereogeneous data dependency graphs and that the library can perform back-propagation on.

A

is a `BP`

s rs a`BP`

action that uses an environment of `rs`

returning a `a`

. When "run", it will compute a gradient that is a tuple
of `rs`

. (The phantom parameter `s`

is used to ensure that any `BVar`

s
aren't leaked out of the monad)

Note that you can only "run" a

that produces a `BP`

s rs`BVar`

--
that is, things of the form

`BP`

s rs (`BVar`

s rs a)

The above is a `BP`

action that returns a `BVar`

containing an `a`

.
When this is run, it'll produce a result of type `a`

and a gradient of
that is a tuple of `rs`

. (This form has a type synonym,
`BPOp`

, for convenience)

For example, a

is a monad that
represents a computation with an `BP`

s '[ Int, Double, Double ]`Int`

, `Double`

, and `Double`

as
inputs. And, if you ran a

`BP`

s '[ Int, Double, Double ] (`BVar`

s '[ Int, Double, Double ] Double)

Or, using the `BPOp`

type synonym:

`BPOp`

s '[ Int, Double, Double ] Double

with `backprop`

or `gradBPOp`

, it'll
return a gradient on the inputs (`Int`

, `Double`

, and `Double`

) and
produce a value of type `Double`

.

Now, one powerful thing about this type is that a `BP`

is itself an
`Op`

(or more precisely, an `OpB`

, which is a subtype of
`OpM`

). So, once you create your fancy `BP`

computation, you can
transform it into an `OpM`

using `bpOp`

.

type BPOp s rs a = BP s rs (BVar s rs a) Source #

A handy type synonym representing a `BP`

action that returns a `BVar`

.
This is handy because this is the form of `BP`

actions that
`backprop`

and `gradBPOp`

(etc.) expects.

A value of type:

`BPOp`

s rs a

is an action that takes an input environment of `rs`

and produces
a `BVar`

containing a value of type `a`

. Because it returns a `BVar`

,
the library can track the data dependencies between the `BVar`

and the
input environment and perform back-propagation.

See documentation for `BP`

for an explanation of the phantom type
parameter `s`

.

type BPOpI s rs a = Prod (BVar s rs) rs -> BVar s rs a Source #

An "implicit" operation on `BVar`

s that can be backpropagated.
A value of type:

`BPOpI`

s rs a

takes a bunch of `BVar`

s containg `rs`

and uses them to (purely) produce
a `BVar`

containing an `a`

.

foo :: BPOpI s '[ Double, Double ] Double foo (x :< y :< Ø) = x + sqrt y

If you are exclusively doing implicit back-propagation by combining
`BVar`

s and using `BPOpI`

s, you are probably better off just importing
Numeric.Backprop.Implicit, which provides better tools. This type
synonym exists in Numeric.Backprop just for the `implicitly`

function,
which can convert "implicit" backprop functions like a

into an "explicit" graph backprop function, a `BPOpI`

s rs a

.`BPOp`

s rs a

data BVar :: Type -> [Type] -> Type -> Type Source #

The basic unit of manipulation inside `BP`

(or inside an
implicit-graph backprop function). Instead of directly working with
values, you work with `BVar`

s contating those values. When you work
with a `BVar`

, the *backprop* library can keep track of what values
refer to which other values, and so can perform back-propagation to
compute gradients.

A

refers to a value of type `BVar`

s rs a`a`

, with an environment
of values of the types `rs`

. The phantom parameter `s`

is used to
ensure that stray `BVar`

s don't leak outside of the backprop process.

(That is, if you're using implicit backprop, it ensures that you interact
with `BVar`

s in a polymorphic way. And, if you're using explicit
backprop, it ensures that a

never leaves the `BVar`

s rs a

that it was created in.)`BP`

s rs

`BVar`

s have `Num`

, `Fractional`

, `Floating`

, etc. instances, so they
can be manipulated using polymorphic functions and numeric functions in
Haskell. You can add them, subtract them, etc., in "implicit" backprop
style.

(However, note that if you directly manipulate `BVar`

s using those
instances or using `liftB`

, it delays evaluation, so every usage site
has to re-compute the result/create a new node. If you want to re-use
a `BVar`

you created using `+`

or `-`

or `liftB`

, use
`bindVar`

to force it first. See documentation for
`bindVar`

for more details.)

Floating a => Floating (BVar s rs a) Source # | See note for |

Fractional a => Fractional (BVar s rs a) Source # | See note for |

Num a => Num (BVar s rs a) Source # | Note that if you use the |

type Op as a = forall m. Monad m => OpM m as a Source #

An

describes a differentiable function from `Op`

as a`as`

to `a`

.

For example, a value of type

`Op`

'[Int, Bool] Double

is a function from an `Int`

and a `Bool`

, returning a `Double`

. It can
be differentiated to give a *gradient* of an `Int`

and a `Bool`

if given
a total derivative for the `Double`

. If we call `Bool`

\(2\), then,
mathematically, it is akin to a:

\[ f : \mathbb{Z} \times 2 \rightarrow \mathbb{R} \]

See `runOp`

, `gradOp`

, and `gradOpWith`

for examples on how to run it,
and `Op`

for instructions on creating it.

This type is abstracted over using the pattern synonym with constructor
`Op`

, so you can create one from scratch with it. However, it's
simplest to create it using `op2'`

, `op1'`

, `op2'`

, and `op3'`

helper
smart constructors And, if your function is a numeric function, they
can even be created automatically using `op1`

, `op2`

, `op3`

, and `opN`

with a little help from Numeric.AD from the *ad* library.

Note that this type is a *subset* or *subtype* of `OpM`

(and also of
`OpB`

). So, if a function ever expects an

(or a `OpM`

m as
a`OpB`

), you can always provide an

instead.`Op`

as a

Many functions in this library will expect an

(or
an `OpM`

m as a

), and in all of these cases, you can
provide an `OpB`

s as a

.`Op`

as a

type OpB s as a = OpM (ST s) as a Source #

A subclass of `OpM`

(and superclass of `Op`

), representing `Op`

s that
the *backprop* library uses to perform backpropation.

An

`OpB`

s rs a

represents a differentiable function that takes a tuple of `rs`

and
produces an a `a`

, which can be run on

s and also inside `BVar`

s

s. For example, an `BP`

s

takes an `OpB`

s '[ Int, Double ] Bool`Int`

and
a `Double`

and produces a `Bool`

, and does it in a differentiable way.

`OpB`

is a *superset* of `Op`

, so, if you see any function
that expects an `OpB`

(like `opVar'`

and
`~$`

, for example), you can give them an `Op`

, as well.

You can think of `OpB`

as a superclass/parent class of `Op`

in this
sense, and of `Op`

as a subclass of `OpB`

.

## Tuple types

`Prod`

, from the <http://hackage.haskell.org/package/type-combinators
type-combinators> library (in Data.Type.Prod) is a heterogeneous
list/tuple type, which allows you to tuple together multiple values of
different types and operate on them generically.

A

contains an `Prod`

f '[a, b, c]`f a`

, an `f b`

, and an `f c`

, and
is constructed by consing them together with `:<`

(using 'Ø' as nil):

`I`

"hello"`:<`

I True :< I 7.8 :< Ø ::`Prod`

`I`

'[String, Bool, Double]`C`

"hello" :< C "world" :< C "ok" :< Ø ::`Prod`

(`C`

String) '[a, b, c]`Proxy`

:< Proxy :< Proxy :< Ø ::`Prod`

`Proxy`

'[a, b, c]

(`I`

is the identity functor, and `C`

is the constant functor)

So, in general:

x :: f a y :: f b z :: f c x :< y :< z :< Ø :: Prod f '[a, b, c]

If you're having problems typing 'Ø', you can use `only`

:

only z :: Prod f '[c] x :< y :< only z :: Prod f '[a, b, c]

`Tuple`

is provided as a convenient type synonym for `Prod`

`I`

, and has
a convenient pattern synonym `::<`

(and `only_`

), which can also be used
for pattern matching:

x :: a y :: b z :: c`only_`

z ::`Tuple`

'[c] x`::<`

y ::< z ::< Ø ::`Tuple`

'[a, b, c] x ::< y ::< only_ z ::`Tuple`

'[a, b, c]

data Prod k f a :: forall k. (k -> *) -> [k] -> * where #

Witness ØC ØC (Prod k f (Ø k)) | |

IxFunctor1 k [k] (Index k) (Prod k) | |

IxFoldable1 k [k] (Index k) (Prod k) | |

IxTraversable1 k [k] (Index k) (Prod k) | |

Functor1 [k] k (Prod k) | |

Foldable1 [k] k (Prod k) | |

Traversable1 [k] k (Prod k) | |

TestEquality k f => TestEquality [k] (Prod k f) | |

BoolEquality k f => BoolEquality [k] (Prod k f) | |

Eq1 k f => Eq1 [k] (Prod k f) | |

Ord1 k f => Ord1 [k] (Prod k f) | |

Show1 k f => Show1 [k] (Prod k f) | |

Read1 k f => Read1 [k] (Prod k f) | |

(Known [k] (Length k) as, Every k (Known k f) as) => Known [k] (Prod k f) as | |

(Witness p q (f a1), Witness s t (Prod a f as)) => Witness (p, s) (q, t) (Prod a f ((:<) a a1 as)) | |

ListC ((<$>) Constraint * Eq ((<$>) * k f as)) => Eq (Prod k f as) | |

(ListC ((<$>) Constraint * Eq ((<$>) * k f as)), ListC ((<$>) Constraint * Ord ((<$>) * k f as))) => Ord (Prod k f as) | |

ListC ((<$>) Constraint * Show ((<$>) * k f as)) => Show (Prod k f as) | |

type WitnessC ØC ØC (Prod k f (Ø k)) | |

type KnownC [k] (Prod k f) as | |

type WitnessC (p, s) (q, t) (Prod a f ((:<) a a1 as)) | |

# BP

## Backprop

backprop :: Every Num rs => (forall s. BPOp s rs a) -> Tuple rs -> (a, Tuple rs) Source #

Perform back-propagation on the given `BPOp`

. Returns the result of
the operation it represents, as well as the gradient of the result with
respect to its inputs. See module header for Numeric.Backprop and
package documentation for examples and usages.

Simply run the `BPOp`

on an input tuple, getting the result without
bothering with the gradient or with back-propagation.

Run the `BPOp`

on an input tuple and return the gradient of the result
with respect to the input tuple.

## Utility combinators

withInps :: Known Length rs => (Prod (BVar s rs) rs -> BP s rs a) -> BP s rs a Source #

Runs a continuation on a `Prod`

of all of the input `BVar`

s.

Handy for bringing the environment into scope and doing stuff with it:

foo ::`BPOp`

'[Double, Int] a foo =`withInps`

$ \(x :< y :< Ø) -> do -- do stuff with inputs

Looks kinda like `foo (x :< y :< Ø) = -- ...`

, don't it?

Note that the above is the same as

foo ::`BPOp`

'[Double, Int] a foo = do case`inpVars`

of x ::< Ø - do -- do stuff with inputs

But just a little nicer!

implicitly :: (Known Length rs, Num a) => BPOpI s rs a -> BPOp s rs a Source #

Convert a `BPOpI`

into a `BPOp`

. That is, convert a function on
a bundle of `BVar`

s (generating an implicit graph) into a fully fledged
`BPOp`

that you can run `backprop`

on. See `BPOpI`

for more
information.

If you are going to write exclusively using implicit `BVar`

operations,
it might be more convenient to use Numeric.Backprop.Implicit instead,
which is geared around that use case.

withInps' :: Length rs -> (Prod (BVar s rs) rs -> BP s rs a) -> BP s rs a Source #

A version of `withInps`

taking explicit `Length`

, indicating the
number of inputs required and their types.

Mostly useful for rare "extremely polymorphic" situations, where GHC
can't infer the type and length of the list of inputs. If you ever
actually explicitly write down `rs`

as a list of types, you should be
able to just use `withInps`

.

implicitly' :: Num a => Length rs -> BPOpI s rs a -> BPOp s rs a Source #

A version of `implicitly`

taking explicit `Length`

, indicating the
number of inputs required and their types.

Requiring an explicit `Length`

is mostly useful for rare "extremely
polymorphic" situations, where GHC can't infer the type and length of
the list of inputs. If you ever actually explicitly write down `rs`

as
a list of types, you should be able to just use `implicitly`

.

# Vars

inpVar :: Index rs a -> BVar s rs a Source #

Create a `BVar`

given an index into the input environment. For an
example,

`inpVar`

`IZ`

would refer to the *first* input variable (the `Int`

in a

), and`BP`

s '[Int, Bool]

`inpVar`

(`IS`

`IZ`

)

Would refer to the *second* input variable (the `Bool`

in a

)`BP`

s '[Int, Bool]

Typically, there shouldn't be any reason to use `inpVar`

directly. It's
cleaner to get all of your input `BVar`

s together using `withInps`

or
`inpVars`

.

inpVars :: Known Length rs => Prod (BVar s rs) rs Source #

Get a `Prod`

(tupling) of `BVar`

s for all of the input environment
(`rs`

) of the `BP`

s rs

For example, if your `BP`

has an `Int`

and `Double`

in its input
environment (a

), this would return a `BP`

s '[Int, Double]`BVar`

pointing to the `Int`

and a `BVar`

pointing to the `Double`

.

case (`inpVars`

::`Prod`

(`BVar`

s '[Int, Double]) '[Int, Double]) of x :< y :< Ø -> do -- the first item, x, is a var to the input`Int`

-- x ::`BVar`

s '[Int, Double] Int -- the second item, y, is a var to the input`Double`

-- y ::`BVar`

s '[Int, Double] Double

bpOp :: Every Num rs => BPOp s rs a -> OpB s rs a Source #

Turn a `BPOp`

into an `OpB`

. Basically converts a `BP`

taking an `rs`

and producing an `a`

into an `Op`

taking an `rs`

and returning an `a`

,
with all of the powers and utility of an `Op`

, including all of its
gradient-finding glory.

Really just reveals the fact that any

is itself an `BPOp`

s rs a`Op`

,
an

, which makes it a differentiable function.`OpB`

s rs a

Handy because an `OpB`

can be used with almost all of
the `Op`

-related functions in this moduel, including `opVar`

, `~$`

, etc.

bindVar :: Num a => BVar s rs a -> BP s rs (BVar s rs a) Source #

Concretizes a delayed `BVar`

. If you build up a `BVar`

using numeric
functions like `+`

or `*`

or using `liftB`

, it'll defer the evaluation,
and all of its usage sites will create a separate graph node.

Use `bindVar`

if you ever intend to use a `BVar`

in more than one
location.

-- bad errSquared :: Num a =>`BP`

s '[a, a] a errSquared =`withInp`

$ \(r :< t :< Ø) -> do let err = r - t`return`

(err * err) -- err is used twice! -- good errSquared :: Num a =>`BP`

s '[a, a] a errSquared =`withInps`

$ \(r :< t :< Ø) -> do let err = r - t e <-`bindVar`

err -- force e, so that it's safe to use twice!`return`

(e * e) -- better errSquared :: Num a =>`BP`

s '[a, a] a errSquared =`withInps`

$ \(r :< t :< Ø) -> do let err = r - t e <-`bindVar`

err`bindVar`

(e * e) -- result is forced so user doesn't have to worry

Note the relation to `opVar`

* ~$ *

`liftB`

/ `.$`

:`opVar`

o xs =`bindVar`

(`liftB`

o xs) o`~$`

xs =`bindVar`

(o`.$`

xs)`op2`

(*)`~$`

(x :< y :< Ø) =`bindVar`

(x * y)

So you can avoid `bindVar`

altogether if you use the explicitly binding
`~$`

and `opVar`

etc.

Note that `bindVar`

on `BVar`

s that are already forced is a no-op.

inpVars' :: Length rs -> Prod (BVar s rs) rs Source #

A version of `inpVars`

taking explicit `Length`

, indicating the
number of inputs required and their types.

Mostly useful for rare "extremely polymorphic" situations, where GHC
can't infer the type and length of the list of inputs. If you ever
actually explicitly write down `rs`

as a list of types, you should be
able to just use `inpVars`

.

## From Ops

opVar :: forall s rs as a. Num a => OpB s as a -> Prod (BVar s rs) as -> BP s rs (BVar s rs a) Source #

Apply an `OpB`

to a `Prod`

(tupling) of `BVar`

s.

If you had an

, this function will expect a 3-Prod
of a `OpB`

s '[a, b, c] d

, a `BVar`

s rs a

, and a `BVar`

s rs b

, and the
result will be a `BVar`

s rs c

:`BVar`

s rs d

myOp ::`OpB`

s '[a, b, c] d x ::`BVar`

s rs a y ::`BVar`

s rs b z ::`BVar`

s rs c x :< y :< z :< Ø ::`Prod`

(`BVar`

s rs) '[a, b, c]`opVar`

myOp (x :< y :< z :< Ø) ::`BP`

s rs (`BVar`

s rs d)

Note that `OpB`

is a superclass of `Op`

, so you can provide any `Op`

here, as well (like those created by `op1`

, `op2`

, `constOp`

, `op0`

etc.)

`opVar`

has an infix alias, `~$`

, so the above example can also be
written as:

myOp`~$`

(x :< y :< z :< Ø) ::`BP`

s rs (`BVar`

s rs d)

to let you pretend that you're applying the `myOp`

function to three
inputs.

Also note the relation between `opVar`

and `liftB`

and `bindVar`

:

`opVar`

o xs =`bindVar`

(`liftB`

o xs)

(~$) :: Num a => OpB s as a -> Prod (BVar s rs) as -> BP s rs (BVar s rs a) infixr 5 Source #

Infix synonym for `opVar`

, which lets you pretend that you're applying
`OpB`

s as if they were functions:

myOp ::`OpB`

s '[a, b, c] d x ::`BVar`

s rs a y ::`BVar`

s rs b z ::`BVar`

s rs c x :< y :< z :< Ø ::`Prod`

(`BVar`

s rs) '[a, b, c] myOp`~$`

(x :< y :< z :< Ø) ::`BP`

s rs (`BVar`

s rs d)

Note that `OpB`

is a superclass of `Op`

, so you can pass in any `Op`

here, as well (like those created by `op1`

, `op2`

, `constOp`

, `op0`

etc.)

`~$`

can also be thought of as a "binding" version of `.$`

:

o`~$`

xs =`bindVar`

(o`.$`

xs)

opVar1 :: Num b => OpB s '[a] b -> BVar s rs a -> BP s rs (BVar s rs b) Source #

Convenient wrapper over `opVar`

that takes an `OpB`

with one argument
and a single `BVar`

argument. Lets you not have to type out the entire
`Prod`

.

`opVar1`

o x =`opVar`

o (x`:<`

'Ø') myOp ::`Op`

'[a] b x ::`BVar`

s rs a`opVar1`

myOp x ::`BP`

s rs (`BVar`

s rs b)

Note that `OpB`

is a superclass of `Op`

, so you can pass in an `Op`

here
(like one made with `op1`

) as well.

opVar2 :: Num c => OpB s '[a, b] c -> BVar s rs a -> BVar s rs b -> BP s rs (BVar s rs c) Source #

Convenient wrapper over `opVar`

that takes an `OpB`

with two arguments
and two `BVar`

arguments. Lets you not have to type out the entire
`Prod`

.

`opVar2`

o x y =`opVar`

o (x`:<`

y`:<`

'Ø') myOp ::`Op`

'[a, b] c x ::`BVar`

s rs a y ::`BVar`

s rs b`opVar2`

myOp x y ::`BP`

s rs (`BVar`

s rs c)

Note that `OpB`

is a superclass of `Op`

, so you can pass in an `Op`

here
(like one made with `op2`

) as well.

opVar3 :: Num d => OpB s '[a, b, c] d -> BVar s rs a -> BVar s rs b -> BVar s rs c -> BP s rs (BVar s rs d) Source #

Convenient wrapper over `opVar`

that takes an `OpB`

with three arguments
and three `BVar`

arguments. Lets you not have to type out the entire
`Prod`

.

`opVar3`

o x y z =`opVar`

o (x`:<`

y`:<`

z`:<`

'Ø') myOp ::`Op`

'[a, b, c] d x ::`BVar`

s rs a y ::`BVar`

s rs b z ::`BVar`

s rs c`opVar3`

myOp x y z ::`BP`

s rs (`BVar`

s rs d)

Note that `OpB`

is a superclass of `Op`

, so you can pass in an `Op`

here
(like one made with `op3`

) as well.

(-$) :: (Every Num as, Known Length as, Num a) => BPOp s as a -> Prod (BVar s rs) as -> BPOp s rs a infixr 5 Source #

Lets you treat a

as an `BPOp`

s as b

, and "apply"
arguments to it just like you would with an `Op`

as b`Op`

and `~$`

/ `opVar`

.

Basically a convenient wrapper over `bpOp`

and `~$`

:

o`-$`

xs = bpOp o`~$`

xs

So for a

, you can "plug in" `BPOp`

s as b`BVar`

s to `as`

, and get
a `b`

as a result.

Useful for running a

that you got from a different function, and
"plugging in" its `BPOp`

s as b`as`

inputs with `BVar`

s from your current
environment.

## Var manipulation

### As parts

partsVar :: forall s rs bs b. Every Num bs => Iso' b (Tuple bs) -> BVar s rs b -> BP s rs (Prod (BVar s rs) bs) Source #

Use an `Iso`

(or compatible `Iso`

from the lens
library) to "pull out" the parts of a data type and work with each part
as a `BVar`

.

If there is an isomorphism between a `b`

and a

(that is, if
an `Tuple`

as`a`

is just a container for a bunch of `as`

), then it lets you break
out the `as`

inside and work with those.

data Foo = F Int Bool fooIso ::`Iso'`

Foo (Tuple '[Int, Bool]) fooIso =`iso`

(\(F i b) -> i ::< b ::< Ø) (\(i ::< b ::< Ø) -> F i b )`partsVar`

fooIso ::`BVar`

rs Foo ->`BP`

s rs (`Prod`

(`BVar`

s rs) '[Int, Bool]) stuff ::`BP`

s '[Foo] a stuff =`withInps`

$ \(foo :< Ø) -> do i :< b :< Ø <- partsVar fooIso foo -- now, i is a`BVar`

pointing to the`Int`

inside foo -- and b is a`BVar`

pointing to the`Bool`

inside foo -- you can do stuff with the i and b here

You can use this to pass in product types as the environment to a `BP`

,
and then break out the type into its constituent products.

Note that for a type like `Foo`

, `fooIso`

can be generated automatically
with `Generic`

from GHC.Generics and
`Generic`

from Generics.SOP and *generics-sop*, using the
`gTuple`

iso. See `gSplit`

for more information.

Also, if you are literally passing a tuple (like

) then you can give in the identity
isomorphism (`BP`

s '[Tuple '[Int, Bool]`id`

) or use `splitVars`

.

(#<~) :: (Every Num bs, Known Length bs) => Iso' b (Tuple bs) -> BVar s rs b -> BP s rs (Prod (BVar s rs) bs) infixr 1 Source #

A useful infix alias for `partsVar`

.

Building on the example from `partsVar`

:

data Foo = F Int Bool fooIso ::`Iso'`

Foo (Tuple '[Int, Bool]) fooIso =`iso`

(\(F i b) -> i ::< b ::< Ø) (\(i ::< b ::< Ø) -> F i b ) stuff ::`BP`

s '[Foo] a stuff =`withInps`

$ \(foo :< Ø) -> do i :< b :< Ø <- fooIso`#<~`

foo -- now, i is a`BVar`

pointing to the`Int`

inside foo -- and b is a`BVar`

pointing to the`Bool`

inside foo -- you can do stuff with the i and b here

See `gSplit`

for an example usage of splitting up an arbitrary product
type (like `Foo`

) using GHC.Geneics and Generics.SOP.

withParts :: Every Num bs => Iso' b (Tuple bs) -> BVar s rs b -> (Prod (BVar s rs) bs -> BP s rs a) -> BP s rs a Source #

A continuation-based version of `partsVar`

. Instead of binding the
parts and using it in the rest of the block, provide a continuation to
handle do stuff with the parts inside.

Building on the example from `partsVar`

:

data Foo = F Int Bool fooIso ::`Iso'`

Foo (Tuple '[Int, Bool]) fooIso =`iso`

(\(F i b) -> i ::< b ::< Ø) (\(i ::< b ::< Ø) -> F i b ) stuff ::`BP`

s '[Foo] a stuff =`withInps`

$ \(foo :< Ø) -> do`withParts`

fooIso foo $ \(i :< b :< Ø) -> do -- now, i is a`BVar`

pointing to the`Int`

inside foo -- and b is a`BVar`

pointing to the`Bool`

inside foo -- you can do stuff with the i and b here

Useful so that you can work with the internal parts of the data type
in a closure, so the parts don't leak out to the rest of your `BP`

.
But, mostly just a stylistic choice.

splitVars :: forall s rs as. Every Num as => BVar s rs (Tuple as) -> BP s rs (Prod (BVar s rs) as) Source #

Split out a `BVar`

of a tuple into a tuple (`Prod`

) of `BVar`

s.

-- the environment is a single Int-Bool tuple, tup stuff ::`BP`

s '[ Tuple '[Int, Bool] ] a stuff =`withInps`

$ \(tup :< Ø) -> do i :< b :< Ø <-`splitVars`

tup -- now, i is a`BVar`

pointing to the`Int`

inside tup -- and b is a`BVar`

pointing to the`Bool`

inside tup -- you can do stuff with the i and b here

Note that

`splitVars`

=`partsVar`

`id`

gSplit :: (Every Num bs, Generic b, Code b ~ '[bs]) => BVar s rs b -> BP s rs (Prod (BVar s rs) bs) Source #

Using `Generic`

from GHC.Generics and
`Generic`

from Generics.SOP, *split* a `BVar`

containing
a product type into a tuple (`Prod`

) of `BVar`

s pointing to each value
inside.

Building on the example from `partsVar`

:

import qualified Generics.SOP as SOP data Foo = F Int Bool deriving Generic instance SOP.Generic Foo`gSplit`

::`BVar`

rs Foo ->`BP`

s rs (`Prod`

(`BVar`

s rs) '[Int, Bool]) stuff ::`BP`

s '[Foo] a stuff =`withInps`

$ \(foo :< Ø) -> do i :< b :< Ø <-`gSplit`

foo -- now, i is a`BVar`

pointing to the`Int`

inside foo -- and b is a`BVar`

pointing to the`Bool`

inside foo -- you can do stuff with the i and b here

Because `Foo`

is a straight up product type, `gSplit`

can use
GHC.Generics and take out the items inside.

Note that because

`gSplit`

=`splitVars`

`gTuple`

Then, you can also use `gTuple`

with `#<~`

:

stuff ::`BP`

s '[Foo] a stuff =`withInps`

$ \(foo :< Ø) -> do i :< b :< Ø <-`gTuple`

`#<~`

foo -- now, i is a`BVar`

pointing to the`Int`

inside foo -- and b is a`BVar`

pointing to the`Bool`

inside foo -- you can do stuff with the i and b here

gTuple :: (Generic a, Code a ~ '[as]) => Iso' a (Tuple as) Source #

An `Iso`

between a type that is a product type, and a tuple that
contains all of its components. Uses Generics.SOP and the
`Generic`

typeclass.

`>>>`

`import qualified Generics.SOP as SOP`

`>>>`

`data Foo = A Int Bool deriving Generic`

`>>>`

`instance SOP.Generic Foo`

`>>>`

10 ::< True ::< Ø`view gTuple (A 10 True)`

`>>>`

A 15 False`review gTuple (15 ::< False ::< Ø)`

### As sums

choicesVar :: forall s rs bs b. Every Num bs => Iso' b (Sum I bs) -> BVar s rs b -> BP s rs (Sum (BVar s rs) bs) Source #

Use an `Iso`

(or compatible `Iso`

from the lens
library) to "pull out" the different constructors of a sum type and
return a (choice) sum of `BVar`

s that you can pattern match on.

If there is an isomorphism between a `b`

and a

(that is,
if an `Sum`

`I`

as`a`

is just a sum type for every type in `as`

), then it lets you
*branch* on which constructor is used inside the `b`

.

Essentially implements pattern matching on `BVar`

values.

data Bar = A Int | B Bool | C String barIso ::`Iso'`

Bar (`Sum`

I '[Int, Bool, String]) barIso =`iso`

(\case A i ->`InL`

(I i) B b ->`InR`

(`InL`

(I b)) C s ->`InR`

(`InR`

(`InL`

(I s)) ) (\case`InL`

(I i) -> A i`InR`

(`InL`

(I b)) -> B b`InR`

(`InR`

(`InL`

(I s))) -> C s ) choicesVar barIso :: BVar rs Bar -> BP s rs (Sum I (BVar s rs) '[Int, Bool, String]) stuff ::`BP`

s '[Bar] a stuff =`withInps`

$ \(bar :< Ø) -> do c <-`choicesVar`

barIso bar case c of`InL`

i -> do -- in this branch, bar was made with the A constructor -- i is the Int inside it`InR`

(`InL`

b) -> do -- in this branch, bar was made with the B constructor -- b is the Bool inside it`InR`

(`InR`

(`InL`

s)) -> do -- in this branch, bar was made with the B constructor -- s is the String inside it

You can use this to pass in sum types as the environment to a `BP`

, and
then branch on which constructor the value was made with.

See Numeric.Backprop for a mini-tutorial on `Sum`

.

(?<~) :: (Every Num bs, Known Length bs) => Iso' b (Sum I bs) -> BVar s rs b -> BP s rs (Sum (BVar s rs) bs) infixr 1 Source #

A useful infix alias for `choicesVar`

.

Building on the example from `choicesVar`

:

data Bar = A Int | B Bool | C String barIso ::`Iso'`

Bar (`Sum`

I '[Int, Bool, String]) barIso =`iso`

(\case A i ->`InL`

(I i) B b ->`InR`

(`InL`

(I b)) C s ->`InR`

(`InR`

(`InL`

(I s)) ) (\case`InL`

(I i) -> A i`InR`

(`InL`

(I b)) -> B b`InR`

(`InR`

(`InL`

(I s))) -> C s ) stuff ::`BP`

s '[Bar] a stuff =`withInps`

$ \(bar :< Ø) -> do c <- barIso`?<~`

bar case c of`InL`

i -> do -- in this branch, bar was made with the A constructor -- i is the Int inside it`InR`

(`InL`

b) -> do -- in this branch, bar was made with the B constructor -- b is the Bool inside it`InR`

(`InR`

(`InL`

s)) -> do -- in this branch, bar was made with the B constructor -- s is the String inside it

withChoices :: forall s rs bs b a. Every Num bs => Iso' b (Sum I bs) -> BVar s rs b -> (Sum (BVar s rs) bs -> BP s rs a) -> BP s rs a Source #

A continuation-based version of `choicesVar`

. Instead of binding the
parts and using it in the rest of the block, provide a continuation that
will handle every possible constructor/case of the type of the value the
`BVar`

points to.

Building on the example from `choicesVar`

:

data Bar = A Int | B Bool | C String barIso ::`Iso'`

Bar (`Sum`

I '[Int, Bool, String]) barIso =`iso`

(\case A i ->`InL`

(I i) B b ->`InR`

(`InL`

(I b)) C s ->`InR`

(`InR`

(`InL`

(I s)) ) (\case`InL`

(I i) -> A i`InR`

(`InL`

(I b)) -> B b`InR`

(`InR`

(`InL`

(I s))) -> C s )`choicesVar`

barIso :: BVar rs Bar -> BP s rs (Sum I (BVar s rs) '[Int, Bool, String]) stuff ::`BP`

s '[Bar] a stuff =`withInps`

$ \(bar :< Ø) -> do`withChoices`

barIso bar $ case`InL`

i -> do -- in this branch, bar was made with the A constructor -- i is the Int inside it`InR`

(`InL`

b) -> do -- in this branch, bar was made with the B constructor -- b is the Bool inside it`InR`

(`InR`

(`InL`

s)) -> do -- in this branch, bar was made with the B constructor -- s is the String inside it

Nicer than `choicesVar`

directly, because you don't have to give the
result a superfluous name before pattern matching on it. You can just
directly pattern match in the lambda, so there's a lot less syntactical
noise.

Like the `Prod`

type (see mini-tutorial at Numeric.Backprop), the
`Sum`

type (from the
type-combinators
library, in Data.Type.Sum) lets you make arbitrary sum types over
different types and work with them generically.

A

contains `Sum`

f '[a, b, c]*either* an `f a`

, an `f b`

, *or* an ```
f
c
```

, and is constructed with the constructors `InL`

and `InR`

, which are
analogous to `Left`

and `Right`

.

For a value of type

, there are three
constructors:`Sum`

f '[Int, Bool, String]

`InL`

:: f Int ->`Sum`

f '[Int, Bool, String] InL . InR :: f Bool -> Sum f '[Int, Bool, String] InL . InR . InR :: f String -> Sum f '[Int, Bool, String]

Each `InR`

"pushes deeper" into the `Sum`

.

Likewise, if you have a value of type

,
you can see which constructor it was made (and what type it contains)
with by pattern matching:`Sum`

f '[Int, Bool, String]

foo ::`Sum`

f '[Int, Bool, String] case foo of`InL`

i -> -- foo contains an "f Int"`InR`

(InL b) -> -- foo contains an "f Bool" InR (InR (InL s)) -> -- foo contains an "f String"

data Sum k f a :: forall k. (k -> *) -> [k] -> * where #

Witness p q (f a) => Witness p q (Sum k f ((:) k a ([] k))) | |

(Witness p q (f a1), Witness p q (Sum a f ((:<) a b as))) => Witness p q (Sum a f ((:<) a a1 ((:<) a b as))) | |

IxFunctor1 k [k] (Index k) (Sum k) | |

IxFoldable1 k [k] (Index k) (Sum k) | |

IxTraversable1 k [k] (Index k) (Sum k) | |

Functor1 [k] k (Sum k) | |

Foldable1 [k] k (Sum k) | |

Traversable1 [k] k (Sum k) | |

Eq1 k f => Eq1 [k] (Sum k f) | |

Ord1 k f => Ord1 [k] (Sum k f) | |

Show1 k f => Show1 [k] (Sum k f) | |

Read1 k f => Read1 [k] (Sum k f) | |

ListC ((<$>) Constraint * Eq ((<$>) * k f as)) => Eq (Sum k f as) | |

(ListC ((<$>) Constraint * Eq ((<$>) * k f as)), ListC ((<$>) Constraint * Ord ((<$>) * k f as))) => Ord (Sum k f as) | |

ListC ((<$>) Constraint * Show ((<$>) * k f as)) => Show (Sum k f as) | |

type WitnessC p q (Sum a f ((:<) a a1 ((:<) a b as))) | |

type WitnessC p q (Sum k f ((:) k a ([] k))) | |

### As sums of products

sopVar :: forall s rs bss b. Every (Every Num) bss => Iso' b (Sum Tuple bss) -> BVar s rs b -> BP s rs (Sum (Prod (BVar s rs)) bss) Source #

A combination of `partsVar`

and `choicesVar`

, that lets you split
a type into a sum of products. Using an `Iso`

(or compatible
`Iso`

from the lens library), you can pull out a type
that is a sum of products into a sum of products of `BVar`

s.

Implements branching on the constructors of a value that a `BVar`

contains, and also splitting out the different items inside each
constructor.

data Baz = A Int Bool | B String Double bazIso ::`Iso'`

Baz (`Sum`

`Tuple`

'[ '[Int, Bool], '[String, Double] ]) bazIso =`iso`

(\case A i b ->`InL`

(I (i ::< b ::< Ø)) B s d ->`InR`

(`InL`

(I (s ::< d ::< Ø))) ) (\case`InL`

(I (i ::::< Ø)) - A i b`InR`

(`InL`

(I (s ::::< Ø))) - B s d )`sopVar`

bazIso ::`BVar`

rs Baz ->`BP`

s rs (`Sum`

(`Prod`

(`BVar`

s rs)) '[ '[Int, Bool], '[String, Double] ]) stuff ::`BP`

s '[Baz] a stuff =`withInps`

$ \(baz :< Ø) -> do c <-`sopVar`

barIso baz case c of`InL`

(i ::< Ø) - do -- in this branch, baz was made with the A constructor -- i and b are the Int and Bool inside it`InR`

(`InL`

(s ::< Ø)) - do -- in this branch, baz was made with the B constructor -- s and d are the String and Double inside it

Essentially exists to implement "pattern matching" on multiple
constructors and fields for the value inside a `BVar`

.

Note that for a type like `Baz`

, `bazIso`

can be generated automatically
with `Generic`

from GHC.Generics and
`Generic`

from Generics.SOP and *generics-sop*, with
`gSOP`

. See `gSplits`

for more information.

See Numeric.Backprop for a mini-tutorial on `Sum`

.

gSplits :: forall s rs b. (Generic b, Every (Every Num) (Code b)) => BVar s rs b -> BP s rs (Sum (Prod (BVar s rs)) (Code b)) Source #

Using `Generic`

from GHC.Generics and
`Generic`

from Generics.SOP, *split* a `BVar`

containing
a sum of products (any simple ADT, essentialy) into a `Sum`

of each
constructor, each containing a tuple (`Prod`

) of `BVar`

s pointing to
each value inside.

Building on the example from `sopVar`

:

import qualified Generics.SOP as SOP data Baz = A Int Bool | B String Double deriving Generic instance SOP.Generic Baz`gSplits`

::`BVar`

rs Baz ->`BP`

s rs (`Sum`

(`Prod`

(`BVar`

s rs)) '[ '[Int, Bool], '[String, Double] ]) stuff ::`BP`

s '[Baz] a stuff =`withInps`

$ \(baz :< Ø) -> do c <- gSplits baz case c of`InL`

(i ::< Ø) - do -- in this branch, baz was made with the A constructor -- i and b are the Int and Bool inside it`InR`

(`InL`

(s ::< Ø)) - do -- in this branch, baz was made with the B constructor -- s and d are the String and Double inside it

Because `Foo`

is a straight up sum-of-products type, `gSplits`

can use
GHC.Generics and take out the items inside.

Note:

`gSplit`

=`splitVars`

`gSOP`

See Numeric.Backprop for a mini-tutorial on `Sum`

.

gSOP :: Generic a => Iso' a (Sum Tuple (Code a)) Source #

An `Iso`

between a sum type whose constructors are products, and a sum
(`Sum`

) of products (`Tuple`

). Uses Generics.SOP and the
`Generic`

typeclass.

`>>>`

`import qualified Generics.SOP as SOP`

`>>>`

`data Bar = A Int Bool | B String Double`

`>>>`

`instance SOP.Generic Bar`

`>>>`

'InL' (10 ::< True ::< Ø)`'view' 'gSOP' (A 10 True)`

`>>>`

'InR' ('InL' ("hello" ::< 3.4 ::< Ø))`'view' 'gSOP' (B "hello" 3.4)`

`>>>`

A 15 False`'review' 'gTuple' ('InL' (15 ::< False ::< Ø))`

`>>>`

B "bye" 9.8`'review' 'gTuple' ('InR' ('InL' ("bye" ::< 9.8 ::< Ø)))`

### As GADTs

withGADT :: forall s rs a b. BVar s rs a -> (a -> BPCont s rs a b) -> BP s rs b Source #

Special **unsafe** combinator that lets you pattern match and work on
GADTs.

data MyGADT :: Bool -> Type where A :: String -> Int -> MyGADT 'True B :: Bool -> Double -> MyGADT 'False foo :: BP s '[ MyGADT b ] a foo =`withInps`

$ \( gVar :< Ø ) -> withGADT gVar $ \case A s i -> BPC (s ::< i ::< Ø) (\(s' ::< i' ::< Ø) -> A s i) $ \(sVar :- do -- .. in this`BP`

action, sVar and iVar are`BPVar`

s that -- refer to the String and Int inside the A constructor in -- gVar B b d -> BPC (b ::< d ::< Ø) (\(b' ::< d' ::< Ø) -> B b d) $ \(bVar :- do -- .. in this`BP`

action, bVar and dVar are`BPVar`

s that -- refer to the Bool and DOuble inside the B constructor in -- gVar

`withGADT`

lets to directly pattern match on the GADT, but as soon as
you pattern match, you must handle the results with a `BPCont`

containing:

*All*of the items inside the GADT constructor, in a`Tuple`

- A function from a
`Tuple`

of items inside the GADT constructor that assembles them back into the original*same*constructor. - A function from a
`Prod`

of`BVar`

s (that contain the items inside the constructor) and doing whatever you wanted to do with it, inside`BP`

.

If you don't provide all of the items inside the GADT into the `BPC`

, or
if your "re-assembling" function doesn't properly reassemble things
correctly or changes some of the values, this will not work.

data BPCont :: Type -> [Type] -> Type -> Type -> Type where Source #

## Combining

liftB :: OpB s as a -> Prod (BVar s rs) as -> BVar s rs a Source #

Apply `OpB`

over a `Prod`

of `BVar`

s, as inputs. Provides
"implicit-graph" back-propagation, with deferred evaluation.

If you had an

, this function will expect a 3-Prod
of a `OpB`

s '[a, b, c] d

, a `BVar`

s rs a

, and a `BVar`

s rs b

, and the
result will be a `BVar`

s rs c

:`BVar`

s rs d

myOp ::`OpB`

s '[a, b, c] d x ::`BVar`

s rs a y ::`BVar`

s rs b z ::`BVar`

s rs c x :< y :< z :< Ø ::`Prod`

(`BVar`

s rs) '[a, b, c]`liftB`

myOp (x :< y :< z :< Ø) ::`BVar`

s rs d

Note that `OpB`

is a superclass of `Op`

, so you can provide any `Op`

here, as well (like those created by `op1`

, `op2`

, `constOp`

, `op0`

etc.)

`liftB`

has an infix alias, `.$`

, so the above example can also be
written as:

myOp`.$`

(x :< y :< z :< Ø) ::`BVar`

s rs d

to let you pretend that you're applying the `myOp`

function to three
inputs.

The result is a new *deferred* `BVar`

. This should be fine in most
cases, unless you use the result in more than one location. This will
cause evaluation to be duplicated and multiple redundant graph nodes to
be created. If you need to use it in two locations, you should use
`opVar`

instead of `liftB`

, or use `bindVar`

:

`opVar`

o xs =`bindVar`

(`liftB`

o xs)

`liftB`

can be thought of as a "deferred evaluation" version of `opVar`

.

(.$) :: OpB s as a -> Prod (BVar s rs) as -> BVar s rs a infixr 5 Source #

Infix synonym for `liftB`

, which lets you pretend that you're applying
`OpB`

s as if they were functions:

myOp ::`OpB`

s '[a, b, c] d x ::`BVar`

s rs a y ::`BVar`

s rs b z ::`BVar`

s rs c x :< y :< z :< Ø ::`Prod`

(`BVar`

s rs) '[a, b, c] myOp`.$`

(x :< y :< z :< Ø) ::`BVar`

s rs d

Note that `OpB`

is a superclass of `Op`

, so you can pass in any `Op`

here, as well (like those created by `op1`

, `op2`

, `constOp`

, `op0`

etc.)

See the documentation for `liftB`

for all the caveats of this usage.

`.$`

can also be thought of as a "deferred evaluation" version of `~$`

:

o`~$`

xs =`bindVar`

(o`.$`

xs)

liftB1 :: OpB s '[a] b -> BVar s rs a -> BVar s rs b Source #

Convenient wrapper over `liftB`

that takes an `OpB`

with one argument
and a single `BVar`

argument. Lets you not have to type out the entire
`Prod`

.

`liftB1`

o x =`liftB`

o (x`:<`

'Ø') myOp ::`Op`

'[a] b x ::`BVar`

s rs a`liftB1`

myOp x ::`BVar`

s rs b

Note that `OpB`

is a superclass of `Op`

, so you can pass in an `Op`

here
(like one made with `op1`

) as well.

See the documentation for `liftB`

for caveats and potential problematic
situations with this.

liftB2 :: OpB s '[a, b] c -> BVar s rs a -> BVar s rs b -> BVar s rs c Source #

Convenient wrapper over `liftB`

that takes an `OpB`

with two arguments
and two `BVar`

arguments. Lets you not have to type out the entire
`Prod`

.

`liftB2`

o x y =`liftB`

o (x`:<`

y`:<`

'Ø') myOp ::`Op`

'[a, b] c x ::`BVar`

s rs a y ::`BVar`

s rs b`liftB2`

myOp x y ::`BVar`

s rs c

Note that `OpB`

is a superclass of `Op`

, so you can pass in an `Op`

here
(like one made with `op2`

) as well.

See the documentation for `liftB`

for caveats and potential problematic
situations with this.

liftB3 :: OpB s '[a, b, c] d -> BVar s rs a -> BVar s rs b -> BVar s rs c -> BVar s rs d Source #

Convenient wrapper over `liftB`

that takes an `OpB`

with three arguments
and three `BVar`

arguments. Lets you not have to type out the entire
`Prod`

.

`liftB3`

o x y z =`liftB`

o (x`:<`

y`:<`

z`:<`

'Ø') myOp ::`Op`

'[a, b, c] d x ::`BVar`

s rs a y ::`BVar`

s rs b z ::`BVar`

s rs c`liftB3`

myOp x y z ::`BVar`

s rs d

Note that `OpB`

is a superclass of `Op`

, so you can pass in an `Op`

here
(like one made with `op3`

) as well.

See the documentation for `liftB`

for caveats and potential problematic
situations with this.

# Op

op2 :: Num a => (forall s. Reifies s Tape => Reverse s a -> Reverse s a -> Reverse s a) -> Op '[a, a] a Source #

op3 :: Num a => (forall s. Reifies s Tape => Reverse s a -> Reverse s a -> Reverse s a -> Reverse s a) -> Op '[a, a, a] a Source #

opN :: (Num a, Known Nat n) => (forall s. Reifies s Tape => Vec n (Reverse s a) -> Reverse s a) -> Op (Replicate n a) a Source #

composeOp1 :: (Monad m, Every Num as, Known Length as) => OpM m as b -> OpM m '[b] c -> OpM m as c Source #

(~.) :: (Monad m, Known Length as, Every Num as) => OpM m '[b] c -> OpM m as b -> OpM m as c infixr 9 Source #

op1' :: (a -> (b, Maybe b -> a)) -> Op '[a] b Source #

Create an `Op`

of a function taking one input, by giving its explicit
derivative. The function should return a tuple containing the result of
the function, and also a function taking the derivative of the result
and return the derivative of the input.

If we have

\[ \eqalign{ f &: \mathbb{R} \rightarrow \mathbb{R}\cr y &= f(x)\cr z &= g(y) } \]

Then the derivative \( \frac{dz}{dx} \), it would be:

\[ \frac{dz}{dx} = \frac{dz}{dy} \frac{dy}{dx} \]

If our `Op`

represents \(f\), then the second item in the resulting
tuple should be a function that takes \(\frac{dz}{dy}\) and returns
\(\frac{dz}{dx}\).

If the input is `Nothing`

, then \(\frac{dz}{dy}\) should be taken to be
\(1\).

As an example, here is an `Op`

that squares its input:

square :: Num a =>`Op`

'[a] a square =`op1'`

$ \x -> (x*x, \case Nothing -> 2 * x Just d -> 2 * d * x )

Remember that, generally, end users shouldn't directly construct `Op`

s;
they should be provided by libraries or generated automatically.

For numeric functions, single-input `Op`

s can be generated automatically
using `op1`

.

op2' :: (a -> b -> (c, Maybe c -> (a, b))) -> Op '[a, b] c Source #

Create an `Op`

of a function taking two inputs, by giving its explicit
gradient. The function should return a tuple containing the result of
the function, and also a function taking the derivative of the result
and return the derivative of the input.

If we have

\[ \eqalign{ f &: \mathbb{R}^2 \rightarrow \mathbb{R}\cr z &= f(x, y)\cr k &= g(z) } \]

Then the gradient \( \left< \frac{\partial k}{\partial x}, \frac{\partial k}{\partial y} \right> \) would be:

\[ \left< \frac{\partial k}{\partial x}, \frac{\partial k}{\partial y} \right> = \left< \frac{dk}{dz} \frac{\partial z}{dx}, \frac{dk}{dz} \frac{\partial z}{dy} \right> \]

If our `Op`

represents \(f\), then the second item in the resulting
tuple should be a function that takes \(\frac{dk}{dz}\) and returns
\( \left< \frac{\partial k}{dx}, \frac{\partial k}{dx} \right> \).

If the input is `Nothing`

, then \(\frac{dk}{dz}\) should be taken to be
\(1\).

As an example, here is an `Op`

that multiplies its inputs:

mul :: Num a =>`Op`

'[a, a] a mul =`op2'`

$ \x y -> (x*y, \case Nothing -> (y , x ) Just d -> (d*y, x*d) )

Remember that, generally, end users shouldn't directly construct `Op`

s;
they should be provided by libraries or generated automatically.

For numeric functions, two-input `Op`

s can be generated automatically
using `op2`

.

# Utility

pattern (:>) :: forall k f a b. f a -> f b -> Prod k f ((:) k a ((:) k b ([] k))) infix 6 #

Construct a two element Prod. Since the precedence of (:>) is higher than (:<), we can conveniently write lists like:

`>>>`

`a :< b :> c`

Which is identical to:

`>>>`

`a :< b :< c :< Ø`

## Numeric Ops

Optimized ops for numeric functions. See Numeric.Backprop.Op for more information.