packages feed

downhill-0.2.0.0: src/Downhill/Linear/Lift.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PartialTypeSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

-- | While 'BackGrad' is intended to be simple to construct manually, this module provides a way to do
--   that with a bit less of boilerplate.
module Downhill.Linear.Lift
  ( -- * Lifts
    lift1,
    lift2,
    lift3,

    -- * Dense lifts
    lift1_dense,
    lift2_dense,
    lift3_dense,

    -- * Lifts for 'SparseVector'
    lift1_sparse,
    lift2_sparse,
    lift3_sparse,
  )
where

import Downhill.Linear.BackGrad (BackGrad (..), castBackGrad, realNode)
import Downhill.Linear.Expr (BasicVector (..), Expr (ExprSum), SparseVector (unSparseVector))
import Prelude hiding (fst, snd, zip)

lift1 ::
  forall z r a.
  BasicVector z =>
  (z -> VecBuilder a) ->
  BackGrad r a ->
  BackGrad r z
lift1 fa (BackGrad da) = realNode node
  where
    node = ExprSum [da fa]

lift2 ::
  forall z r a b.
  BasicVector z =>
  (z -> VecBuilder a) ->
  (z -> VecBuilder b) ->
  BackGrad r a ->
  BackGrad r b ->
  BackGrad r z
lift2 fa fb (BackGrad da) (BackGrad db) = realNode node
  where
    node = ExprSum [da fa, db fb]

lift3 ::
  forall z r a b c.
  BasicVector z =>
  (z -> VecBuilder a) ->
  (z -> VecBuilder b) ->
  (z -> VecBuilder c) ->
  BackGrad r a ->
  BackGrad r b ->
  BackGrad r c ->
  BackGrad r z
lift3 fa fb fc (BackGrad da) (BackGrad db) (BackGrad dc) = realNode node
  where
    node = ExprSum [da fa, db fb, dc fc]

-- | Same as 'sparseNode', included here for completeness.
lift1_sparse ::
  forall r a z.
  BasicVector z =>
  (VecBuilder z -> VecBuilder a) ->
  BackGrad r a ->
  BackGrad r z
lift1_sparse fa = castBackGrad . lift1 @(SparseVector z) fa'
  where
    fa' = fa . unSparseVector

lift2_sparse ::
  forall r a b z.
  BasicVector z =>
  (VecBuilder z -> VecBuilder a) ->
  (VecBuilder z -> VecBuilder b) ->
  BackGrad r a ->
  BackGrad r b ->
  BackGrad r z
lift2_sparse fa fb a b = castBackGrad $ lift2 @(SparseVector z) fa' fb' a b
  where
    fa' = fa . unSparseVector
    fb' = fb . unSparseVector

lift3_sparse ::
  forall r a b c z.
  BasicVector z =>
  (VecBuilder z -> VecBuilder a) ->
  (VecBuilder z -> VecBuilder b) ->
  (VecBuilder z -> VecBuilder c) ->
  BackGrad r a ->
  BackGrad r b ->
  BackGrad r c ->
  BackGrad r z
lift3_sparse fa fb fc a b c =
  castBackGrad $
    lift3 @(SparseVector z) fa' fb' fc' a b c
  where
    fa' = fa . unSparseVector
    fb' = fb . unSparseVector
    fc' = fc . unSparseVector

lift1_dense ::
  (BasicVector v, BasicVector a) =>
  ((v -> a) -> BackGrad r a -> BackGrad r v)
lift1_dense fa = lift1 (identityBuilder . fa)

lift2_dense ::
  (BasicVector v, BasicVector a, BasicVector b) =>
  (v -> a) ->
  (v -> b) ->
  BackGrad r a ->
  BackGrad r b ->
  BackGrad r v
lift2_dense fa fb = lift2 (identityBuilder . fa) (identityBuilder . fb)

lift3_dense ::
  (BasicVector v, BasicVector a, BasicVector b, BasicVector c) =>
  (v -> a) ->
  (v -> b) ->
  (v -> c) ->
  BackGrad r a ->
  BackGrad r b ->
  BackGrad r c ->
  BackGrad r v
lift3_dense fa fb fc = lift3 (identityBuilder . fa) (identityBuilder . fb) (identityBuilder . fc)