inf-backprop-0.2.0.0: src/Debug/DiffExpr.hs
{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -fno-warn-missing-export-lists #-}
-- | Module : Debug.SimpleExpr
-- Copyright : (C) 2023 Alexey Tochin
-- License : BSD3 (see the file LICENSE)
-- Maintainer : Alexey Tochin <Alexey.Tochin@gmail.com>
--
-- Tools for symbolic differentiation expressions.
module Debug.DiffExpr where
import Data.Fix (Fix (Fix))
import Debug.SimpleExpr.Expr
( SimpleExpr,
SimpleExprF (SymbolicFuncF),
unaryFunc,
)
import Debug.SimpleExpr.Utils.Traced (Traced (MkTraced))
import Debug.Trace (trace)
import NumHask
( Additive,
Distributive,
Multiplicative,
(*),
(+),
)
import Numeric.InfBackprop (RevDiff (MkRevDiff))
import Prelude (Show, String, show, ($), (<>))
-- | Create a binary function expression.
--
-- ==== __Examples__
--
-- >>> import Debug.SimpleExpr (variable)
--
-- >>> twoArgFunc "f" (variable "x") (variable "y")
-- f(x,y)
twoArgFunc :: String -> SimpleExpr -> SimpleExpr -> SimpleExpr
twoArgFunc name x y = Fix (SymbolicFuncF name [x, y])
-- | This typecalss is for creating symbolic unary function expressions.
--
-- It is used in conjunction with automatic differentiation to represent
-- functions symbolically.
--
-- ==== __Examples__
--
-- >>> import Debug.SimpleExpr (variable)
-- >>> import Numeric.InfBackprop (simpleDerivative)
--
-- >>> :{
-- f :: SymbolicFunc a => a -> a
-- f = unarySymbolicFunc "f"
-- :}
--
-- >>> f (variable "x")
-- f(x)
--
-- >>> simpleDerivative f (variable "x")
-- f'(x)*1
class SymbolicFunc a where
unarySymbolicFunc :: String -> a -> a
-- | `SimpleExpr` instance of `SymbolicFunc` typeclass.
instance SymbolicFunc SimpleExpr where
unarySymbolicFunc = unaryFunc
-- | `RevDiff` instance of `SymbolicFunc` typeclass.
instance
(SymbolicFunc a, Multiplicative a) =>
SymbolicFunc (RevDiff t a a)
where
unarySymbolicFunc :: String -> RevDiff t a a -> RevDiff t a a
unarySymbolicFunc funcName (MkRevDiff x bp) =
MkRevDiff
(unarySymbolicFunc funcName x)
(\cy -> bp $ f' * cy)
where
f' = unarySymbolicFunc (funcName <> "'") x
-- | This typecalss is for creating symbolic binary function expressions.
--
-- It is used in conjunction with automatic differentiation to represent
-- functions symbolically. See `SymbolicFunc` for unary functions.
class BinarySymbolicFunc a where
binarySymbolicFunc :: String -> a -> a -> a
-- | `SimpleExpr` instance of `BinarySymbolicFunc` typeclass.
instance BinarySymbolicFunc SimpleExpr where
binarySymbolicFunc = twoArgFunc
-- | `RevDiff` instance of `BinarySymbolicFunc` typeclass.
instance
(BinarySymbolicFunc a, Distributive a, Additive t) =>
BinarySymbolicFunc (RevDiff t a a)
where
binarySymbolicFunc funcName (MkRevDiff x bpx) (MkRevDiff y bpy) =
MkRevDiff
(binarySymbolicFunc funcName x y)
(\cz -> bpx (f'1 * cz) + bpy (f'2 * cz))
where
f'1 = binarySymbolicFunc (funcName <> "'_1") x y
f'2 = binarySymbolicFunc (funcName <> "'_2") x y
-- | A traced version of `SimpleExpr` for debugging purposes.
type TracedSimpleExpr = Traced SimpleExpr
-- | A type alias for `Traced` version of `SimpleExpr`.
type TSE = TracedSimpleExpr
-- | `Traced` instance of `SymbolicFunc` typeclass.
instance
(SymbolicFunc a, Show a) =>
SymbolicFunc (Traced a)
where
unarySymbolicFunc name (MkTraced x) =
trace (" <<< TRACING: Calculating " <> name <> " of " <> show x <> " >>>") $
MkTraced $
unarySymbolicFunc name x
-- | `Traced` instance of `BinarySymbolicFunc` typeclass.
instance
(BinarySymbolicFunc a, Show a) =>
BinarySymbolicFunc (Traced a)
where
binarySymbolicFunc name (MkTraced x) (MkTraced y) =
trace (" <<< TRACING: Calculating " <> name <> " of " <> show x <> " and " <> show y <> " >>>") $
MkTraced $
binarySymbolicFunc name x y