{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} module Algebra.Morphism.Affine where import Prelude (Eq(..), Ord(..), Functor(..), id,Bool(..),Show,otherwise) import Algebra.Classes import Algebra.Linear import qualified Data.Map as M import Data.Either import Control.Applicative import Algebra.Morphism.LinComb (LinComb(..)) import qualified Algebra.Morphism.LinComb as LC data Affine x c = Affine c (LinComb x c) deriving (Functor, Eq, Ord,Show) instance Multiplicative c => Scalable c (Affine x c) where k *^ x = k *< x instance (Ord x, AbelianAdditive c,DecidableZero c) => AbelianAdditive (Affine x c) instance (Ord x, AbelianAdditive c,Group c,DecidableZero c) => Group (Affine x c) where negate = fmap negate instance (Ord x, AbelianAdditive c,DecidableZero c) => Additive (Affine x c) where (Affine c1 xs1) + (Affine c2 xs2) = Affine (c1 + c2) (xs1 + xs2) zero = Affine zero zero splitVar :: Ord x => Additive c => x -> Affine x c -> (c, Affine x c) splitVar x (Affine c0 (LinComb m)) = (M.findWithDefault zero x m, Affine c0 (LinComb (M.delete x m))) -- | @solve x f@ solves the equation @f == 0@ for x. -- Let f = k x + e. If k == 0, return Left e. Otherwise, x and return Right -e/k. (The value of x) solve :: (Ord scalar, Eq scalar, Field scalar, Ord x,DecidableZero scalar) => x -> Affine x scalar -> Either (Affine x scalar) (Bool,Affine x scalar) solve x f = if k == zero then Left e else Right (k>zero,recip k *^ negate e) where (k,e) = splitVar x f -- | Constant affine expression constant :: (AbelianAdditive c, DecidableZero c) => Ord x => c -> Affine x c constant c = Affine c zero isConstant :: Eq c => Ord x => DecidableZero c => Affine x c -> Either x c isConstant (Affine k x) = case LC.toList x of [] -> Right k ((v,_):_) -> Left v var :: Multiplicative c => Additive c => v -> Affine v c var x = Affine zero (LC.var x) eval :: forall x c v. (Additive x, Scalable x x) => (c -> x) -> (v -> x) -> Affine v c -> x eval fc fv (Affine c p) = fc c + LC.eval fc fv p subst :: (Ord x, AbelianAdditive c, DecidableZero c, Multiplicative c) => (v -> Affine x c) -> Affine v c -> Affine x c subst f (Affine c p) = constant c + LC.eval id f p mapVars :: Ord x => (v -> x) -> Affine v c -> Affine x c mapVars f (Affine k e) = Affine k (LC.mapVars f e) traverseVars :: Ord x => Applicative f => (v -> f x) -> Affine v c -> f (Affine x c) traverseVars f (Affine k e) = Affine k <$> LC.traverseVars f e