numhask 0.2.0.0 → 0.2.1.0
raw patch · 12 files changed
+1163/−79 lines, 12 files
Files
- numhask.cabal +2/−1
- src/NumHask/Algebra.hs +3/−1
- src/NumHask/Algebra/Additive.hs +170/−0
- src/NumHask/Algebra/Distribution.hs +24/−0
- src/NumHask/Algebra/Field.hs +59/−33
- src/NumHask/Algebra/Integral.hs +155/−5
- src/NumHask/Algebra/Metric.hs +252/−34
- src/NumHask/Algebra/Module.hs +32/−3
- src/NumHask/Algebra/Multiplicative.hs +124/−0
- src/NumHask/Algebra/Rational.hs +232/−0
- src/NumHask/Algebra/Ring.hs +109/−1
- stack.yaml +1/−1
numhask.cabal view
@@ -1,5 +1,5 @@ name: numhask-version: 0.2.0.0+version: 0.2.1.0 synopsis: numeric classes description: A numeric class heirarchy. category: mathematics@@ -44,6 +44,7 @@ NumHask.Algebra.Ring NumHask.Algebra.Field NumHask.Algebra.Integral+ NumHask.Algebra.Rational NumHask.Algebra.Magma NumHask.Algebra.Metric NumHask.Algebra.Module
src/NumHask/Algebra.hs view
@@ -3,7 +3,7 @@ -- | The basic algebraic class structure of a number. -- -- > import NumHask.Algebra--- > import Prelude hiding (Bounded(..), Integral(..), (*), (**), (+), (-), (/), (^), (^^), abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceiling, cos, cosh, exp, floor, fromInteger, fromIntegral, isNaN, log, logBase, negate, pi, product, recip, round, sin, sinh, sqrt, sum, tan, tanh, toInteger)+-- > import Prelude hiding (Integral(..), (*), (**), (+), (-), (/), (^), (^^), abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceiling, cos, cosh, exp, floor, fromInteger, fromIntegral, isNaN, log, logBase, negate, pi, product, recip, round, sin, sinh, sqrt, sum, tan, tanh, toInteger, fromRational) -- module NumHask.Algebra ( -- * Mapping from Num@@ -18,6 +18,7 @@ , module NumHask.Algebra.Metric , module NumHask.Algebra.Module , module NumHask.Algebra.Multiplicative+ , module NumHask.Algebra.Rational , module NumHask.Algebra.Ring , Complex(..) ) where@@ -32,6 +33,7 @@ import NumHask.Algebra.Metric import NumHask.Algebra.Module import NumHask.Algebra.Multiplicative+import NumHask.Algebra.Rational import NumHask.Algebra.Ring -- $numMap
src/NumHask/Algebra/Additive.hs view
@@ -16,6 +16,9 @@ ) where import Data.Complex (Complex(..))+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Natural (Natural(..)) import qualified Prelude as P import Prelude (Bool(..), Double, Float, Int, Integer)@@ -46,6 +49,36 @@ instance (AdditiveMagma a) => AdditiveMagma (Complex a) where (rx :+ ix) `plus` (ry :+ iy) = (rx `plus` ry) :+ (ix `plus` iy) +instance AdditiveMagma Natural where+ plus = (P.+)++instance AdditiveMagma Int8 where+ plus = (P.+)++instance AdditiveMagma Int16 where+ plus = (P.+)++instance AdditiveMagma Int32 where+ plus = (P.+)++instance AdditiveMagma Int64 where+ plus = (P.+)++instance AdditiveMagma Word where+ plus = (P.+)++instance AdditiveMagma Word8 where+ plus = (P.+)++instance AdditiveMagma Word16 where+ plus = (P.+)++instance AdditiveMagma Word32 where+ plus = (P.+)++instance AdditiveMagma Word64 where+ plus = (P.+)+ -- | Unital magma for addition. -- -- > zero `plus` a == a@@ -72,6 +105,36 @@ instance (AdditiveUnital a) => AdditiveUnital (Complex a) where zero = zero :+ zero +instance AdditiveUnital Natural where+ zero = 0++instance AdditiveUnital Int8 where+ zero = 0++instance AdditiveUnital Int16 where+ zero = 0++instance AdditiveUnital Int32 where+ zero = 0++instance AdditiveUnital Int64 where+ zero = 0++instance AdditiveUnital Word where+ zero = 0++instance AdditiveUnital Word8 where+ zero = 0++instance AdditiveUnital Word16 where+ zero = 0++instance AdditiveUnital Word32 where+ zero = 0++instance AdditiveUnital Word64 where+ zero = 0+ -- | Associative magma for addition. -- -- > (a `plus` b) `plus` c == a `plus` (b `plus` c)@@ -90,6 +153,26 @@ instance (AdditiveAssociative a) => AdditiveAssociative (Complex a) +instance AdditiveAssociative Natural++instance AdditiveAssociative Int8++instance AdditiveAssociative Int16++instance AdditiveAssociative Int32++instance AdditiveAssociative Int64++instance AdditiveAssociative Word++instance AdditiveAssociative Word8++instance AdditiveAssociative Word16++instance AdditiveAssociative Word32++instance AdditiveAssociative Word64+ -- | Commutative magma for addition. -- -- > a `plus` b == b `plus` a@@ -108,6 +191,26 @@ instance (AdditiveCommutative a) => AdditiveCommutative (Complex a) +instance AdditiveCommutative Natural++instance AdditiveCommutative Int8++instance AdditiveCommutative Int16++instance AdditiveCommutative Int32++instance AdditiveCommutative Int64++instance AdditiveCommutative Word++instance AdditiveCommutative Word8++instance AdditiveCommutative Word16++instance AdditiveCommutative Word32++instance AdditiveCommutative Word64+ -- | Invertible magma for addition. -- -- > ∀ a ∈ A: negate a ∈ A@@ -135,6 +238,33 @@ instance (AdditiveInvertible a) => AdditiveInvertible (Complex a) where negate (rx :+ ix) = negate rx :+ negate ix +instance AdditiveInvertible Int8 where+ negate = P.negate++instance AdditiveInvertible Int16 where+ negate = P.negate++instance AdditiveInvertible Int32 where+ negate = P.negate++instance AdditiveInvertible Int64 where+ negate = P.negate++instance AdditiveInvertible Word where+ negate = P.negate++instance AdditiveInvertible Word8 where+ negate = P.negate++instance AdditiveInvertible Word16 where+ negate = P.negate++instance AdditiveInvertible Word32 where+ negate = P.negate++instance AdditiveInvertible Word64 where+ negate = P.negate+ -- | Idempotent magma for addition. -- -- > a `plus` a == a@@ -144,6 +274,7 @@ instance AdditiveIdempotent Bool -- | sum definition avoiding a clash with the Sum monoid in base+-- fixme: fit in with the Sum monoid -- sum :: (Additive a, P.Foldable f) => f a -> a sum = P.foldr (+) zero@@ -172,6 +303,26 @@ instance (Additive a) => Additive (Complex a) +instance Additive Natural++instance Additive Int8++instance Additive Int16++instance Additive Int32++instance Additive Int64++instance Additive Word++instance Additive Word8++instance Additive Word16++instance Additive Word32++instance Additive Word64+ -- | Non-commutative left minus -- -- > negate a `plus` a = zero@@ -213,3 +364,22 @@ instance AdditiveGroup Integer instance (AdditiveGroup a) => AdditiveGroup (Complex a)++instance AdditiveGroup Int8++instance AdditiveGroup Int16++instance AdditiveGroup Int32++instance AdditiveGroup Int64++instance AdditiveGroup Word++instance AdditiveGroup Word8++instance AdditiveGroup Word16++instance AdditiveGroup Word32++instance AdditiveGroup Word64+
src/NumHask/Algebra/Distribution.hs view
@@ -6,6 +6,9 @@ ) where import Data.Complex (Complex(..))+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Natural (Natural(..)) import NumHask.Algebra.Additive import NumHask.Algebra.Multiplicative import Prelude (Bool(..), Double, Float, Int, Integer)@@ -30,3 +33,24 @@ instance Distribution Bool instance (AdditiveGroup a, Distribution a) => Distribution (Complex a)++instance Distribution Natural++instance Distribution Int8++instance Distribution Int16++instance Distribution Int32++instance Distribution Int64++instance Distribution Word++instance Distribution Word8++instance Distribution Word16++instance Distribution Word32++instance Distribution Word64+
src/NumHask/Algebra/Field.hs view
@@ -1,3 +1,6 @@+{-# LANGUAGE RebindableSyntax #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -Wall #-} -- | Field classes@@ -6,9 +9,9 @@ , Field , ExpField(..) , QuotientField(..)- , BoundedField(..)- , infinity- , neginfinity+ , UpperBoundedField(..)+ , LowerBoundedField(..)+ , BoundedField , TrigField(..) ) where @@ -16,18 +19,19 @@ import NumHask.Algebra.Additive import NumHask.Algebra.Multiplicative import NumHask.Algebra.Ring+import Data.Bool (bool) import Prelude (Bool, Double, Float, Integer, (||)) import qualified Prelude as P --- | A Semifield is a Field without Commutative Multiplication.-class (MultiplicativeInvertible a, Ring a) =>+-- | A Semifield is chosen here to be a Field without an Additive Inverse+class (MultiplicativeInvertible a, MultiplicativeGroup a, Semiring a) => Semifield a instance Semifield Double instance Semifield Float -instance (Semifield a) => Semifield (Complex a)+instance (Semifield a, AdditiveGroup a) => Semifield (Complex a) -- | A Field is a Ring plus additive invertible and multiplicative invertible operations. --@@ -97,24 +101,39 @@ -- -- > a - one < floor a <= a <= ceiling a < a + one -- > round a == floor (a + one/(one+one))-class (Field a) =>+--+-- fixme: had to redefine Signed operators here because of the Field import in Metric, itself due to Complex being defined there+class (P.Ord a, Field a) => QuotientField a where+ properFraction :: a -> (Integer, a)+ round :: a -> Integer+ round x = case properFraction x of+ (n,r) -> let+ m = bool (n+one) (n-one) (r P.< zero)+ half_down = abs' r - (one/(one+one))+ abs' a+ | a P.< zero = negate a+ | P.otherwise = a+ in+ case P.compare half_down zero of+ P.LT -> n+ P.EQ -> bool m n (P.even n)+ P.GT -> m+ ceiling :: a -> Integer+ ceiling x = bool n (n+one) (r P.> zero)+ where (n,r) = properFraction x+ floor :: a -> Integer- (^^) :: a -> Integer -> a+ floor x = bool n (n-one) (r P.< zero)+ where (n,r) = properFraction x instance QuotientField Float where- round = P.round- ceiling = P.ceiling- floor = P.floor- (^^) = (P.^^)+ properFraction = P.properFraction instance QuotientField Double where- round = P.round- ceiling = P.ceiling- floor = P.floor- (^^) = (P.^^)+ properFraction = P.properFraction -- | A bounded field includes the concepts of infinity and NaN, thus moving away from error throwing. --@@ -126,36 +145,43 @@ -- > zero / zero != nan -- -- Note the tricky law that, although nan is assigned to zero/zero, they are never-the-less not equal. A committee decided this.-class (Field a) =>- BoundedField a where- maxBound :: a- maxBound = one / zero- minBound :: a- minBound = negate (one / zero)+class (Semifield a) =>+ UpperBoundedField a where++ infinity :: a+ infinity = one / zero nan :: a nan = zero / zero- isNaN :: a -> Bool --- | prints as `Infinity`-infinity :: BoundedField a => a-infinity = maxBound---- | prints as `-Infinity`-neginfinity :: BoundedField a => a-neginfinity = minBound+ isNaN :: a -> Bool -instance BoundedField Float where+instance UpperBoundedField Float where isNaN = P.isNaN -instance BoundedField Double where+instance UpperBoundedField Double where isNaN = P.isNaN +class (Field a) =>+ LowerBoundedField a where++ negInfinity :: a+ negInfinity = negate (one / zero)++instance LowerBoundedField Float++instance LowerBoundedField Double+ -- | todo: work out boundings for complex -- as it stands now, complex is different eg -- -- > one / (zero :: Complex Float) == nan-instance (BoundedField a) => BoundedField (Complex a) where+instance (AdditiveGroup a, UpperBoundedField a) =>+ UpperBoundedField (Complex a) where isNaN (rx :+ ix) = isNaN rx || isNaN ix++class (UpperBoundedField a, LowerBoundedField a) => BoundedField a++instance (UpperBoundedField a, LowerBoundedField a) => BoundedField a -- | Trigonometric Field class (P.Ord a, Field a) =>
src/NumHask/Algebra/Integral.hs view
@@ -6,34 +6,129 @@ , ToInteger(..) , FromInteger(..) , fromIntegral+ , even+ , odd+ , (^)+ , (^^) ) where +import Data.Int (Int8, Int16, Int32, Int64)+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Natural (Natural(..)) import NumHask.Algebra.Ring+import NumHask.Algebra.Additive+import NumHask.Algebra.Multiplicative import qualified Prelude as P import Prelude (Double, Float, Int, Integer, (.), fst, snd) -- | Integral laws -- -- > b == zero || b * (a `div` b) + (a `mod` b) == a-class (Ring a) =>+class (Semiring a) => Integral a where infixl 7 `div`, `mod` div :: a -> a -> a div a1 a2 = fst (divMod a1 a2) mod :: a -> a -> a mod a1 a2 = snd (divMod a1 a2)+ divMod :: a -> a -> (a, a) + quot :: a -> a -> a+ quot a1 a2 = fst (quotRem a1 a2)+ rem :: a -> a -> a+ rem a1 a2 = snd (quotRem a1 a2)++ quotRem :: a -> a -> (a, a)+ instance Integral Int where divMod = P.divMod+ quotRem = P.quotRem instance Integral Integer where divMod = P.divMod+ quotRem = P.quotRem +instance Integral Natural where+ divMod = P.divMod+ quotRem = P.quotRem++instance Integral Int8 where+ divMod = P.divMod+ quotRem = P.quotRem++instance Integral Int16 where+ divMod = P.divMod+ quotRem = P.quotRem++instance Integral Int32 where+ divMod = P.divMod+ quotRem = P.quotRem++instance Integral Int64 where+ divMod = P.divMod+ quotRem = P.quotRem++instance Integral Word where+ divMod = P.divMod+ quotRem = P.quotRem++instance Integral Word8 where+ divMod = P.divMod+ quotRem = P.quotRem++instance Integral Word16 where+ divMod = P.divMod+ quotRem = P.quotRem++instance Integral Word32 where+ divMod = P.divMod+ quotRem = P.quotRem++instance Integral Word64 where+ divMod = P.divMod+ quotRem = P.quotRem+ -- | toInteger is kept separate from Integral to help with compatability issues. class ToInteger a where toInteger :: a -> Integer +instance ToInteger Int where+ toInteger = P.toInteger++instance ToInteger Integer where+ toInteger = P.toInteger++instance ToInteger Natural where+ toInteger = P.toInteger++instance ToInteger Int8 where+ toInteger = P.toInteger++instance ToInteger Int16 where+ toInteger = P.toInteger++instance ToInteger Int32 where+ toInteger = P.toInteger++instance ToInteger Int64 where+ toInteger = P.toInteger++instance ToInteger Word where+ toInteger = P.toInteger++instance ToInteger Word8 where+ toInteger = P.toInteger++instance ToInteger Word16 where+ toInteger = P.toInteger++instance ToInteger Word32 where+ toInteger = P.toInteger++instance ToInteger Word64 where+ toInteger = P.toInteger+ -- | fromInteger is the most problematic of the 'Num' class operators. Particularly heinous, it is assumed that any number type can be constructed from an Integer, so that the broad classes of objects that are composed of multiple elements is avoided in haskell. class FromInteger a where fromInteger :: Integer -> a@@ -56,8 +151,63 @@ instance FromInteger Integer where fromInteger = P.fromInteger -instance ToInteger Int where- toInteger = P.toInteger+instance FromInteger Natural where+ fromInteger = P.fromInteger -instance ToInteger Integer where- toInteger = P.toInteger+instance FromInteger Int8 where+ fromInteger = P.fromInteger++instance FromInteger Int16 where+ fromInteger = P.fromInteger++instance FromInteger Int32 where+ fromInteger = P.fromInteger++instance FromInteger Int64 where+ fromInteger = P.fromInteger++instance FromInteger Word where+ fromInteger = P.fromInteger++instance FromInteger Word8 where+ fromInteger = P.fromInteger++instance FromInteger Word16 where+ fromInteger = P.fromInteger++instance FromInteger Word32 where+ fromInteger = P.fromInteger++instance FromInteger Word64 where+ fromInteger = P.fromInteger++-- $operators++even :: (P.Eq a, Integral a) => a -> P.Bool+even n = n `rem` (one + one) P.== zero++odd :: (P.Eq a, Integral a) => a -> P.Bool+odd = P.not . even++-------------------------------------------------------+-- | raise a number to a non-negative integral power+(^) :: (P.Ord b, Integral b, Multiplicative a) => a -> b -> a+x0 ^ y0 | y0 P.< zero = P.undefined -- P.errorWithoutStackTrace "Negative exponent"+ | y0 P.== zero = one+ | P.otherwise = f x0 y0+ where+ two = one+one++ -- f : x0 ^ y0 = x ^ y+ f x y | even y = f (x * x) (y `quot` two)+ | y P.== one = x+ | P.otherwise = g (x * x) (y `quot` two) x+ -- See Note [Half of y - 1]+ -- g : x0 ^ y0 = (x ^ y) * z+ g x y z | even y = g (x * x) (y `quot` two) z+ | y P.== one = x * z+ | P.otherwise = g (x * x) (y `quot` two) (x * z)+ -- See Note [Half of y - 1]++(^^) :: (MultiplicativeGroup a) => a -> Integer -> a+(^^) x n = if n P.>= zero then x^n else recip (x ^ negate n)
src/NumHask/Algebra/Metric.hs view
@@ -13,12 +13,16 @@ import qualified Prelude as P import Prelude- hiding (Bounded(..), Integral(..), (*), (+), (-), abs, negate, sqrt)+ hiding (fromInteger, Bounded(..), Integral(..), (*), (/), (+), (-), abs, negate, sqrt, (**)) import Data.Complex (Complex(..))+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Natural (Natural(..)) import NumHask.Algebra.Additive import NumHask.Algebra.Field import NumHask.Algebra.Multiplicative+import NumHask.Algebra.Integral -- | 'signum' from base is not an operator replicated in numhask, being such a very silly name, and preferred is the much more obvious 'sign'. Compare with 'Norm' and 'Banach' where there is a change in codomain --@@ -58,62 +62,263 @@ | otherwise = negate one abs = P.abs --- | Like Signed, except the codomain can be different to the domain.+instance Signed Natural where+ sign a+ | a == zero = zero+ | otherwise = one+ abs = id++instance Signed Int8 where+ sign a+ | a == zero = zero+ | a > zero = one+ | otherwise = negate one+ abs = P.abs++instance Signed Int16 where+ sign a+ | a == zero = zero+ | a > zero = one+ | otherwise = negate one+ abs = P.abs++instance Signed Int32 where+ sign a+ | a == zero = zero+ | a > zero = one+ | otherwise = negate one+ abs = P.abs++instance Signed Int64 where+ sign a+ | a == zero = zero+ | a > zero = one+ | otherwise = negate one+ abs = P.abs++instance Signed Word where+ sign a+ | a == zero = zero+ | otherwise = one+ abs = P.abs++instance Signed Word8 where+ sign a+ | a == zero = zero+ | otherwise = one+ abs = P.abs++instance Signed Word16 where+ sign a+ | a == zero = zero+ | otherwise = one+ abs = P.abs++instance Signed Word32 where+ sign a+ | a == zero = zero+ | otherwise = one+ abs = P.abs++instance Signed Word64 where+ sign a+ | a == zero = zero+ | otherwise = one+ abs = P.abs++-- | L1 and L2 norms are provided for potential speedups, as well as the generalized p-norm.+--+-- for p >= 1+--+-- > normLp p a >= zero+-- > normLp p zero == zero+--+-- Note that the Normed codomain can be different to the domain.+-- class Normed a b where- size :: a -> b+ normL1 :: a -> b+ normL2 :: a -> b+ normLp :: b -> a -> b instance Normed Double Double where- size = P.abs+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a instance Normed Float Float where- size = P.abs+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a instance Normed Int Int where- size = P.abs+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a instance Normed Integer Integer where- size = P.abs+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a -instance (Multiplicative a, ExpField a) =>+instance (Multiplicative a, ExpField a, Normed a a) => Normed (Complex a) a where- size (rx :+ ix) = sqrt (rx * rx + ix * ix)+ normL1 (rx :+ ix) = normL1 rx + normL1 ix+ normL2 (rx :+ ix) = sqrt (rx * rx + ix * ix)+ normLp p (rx :+ ix) = (normL1 rx ** p + normL1 ix ** p) ** (one / p) --- | distance between numbers+instance Normed Natural Natural where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++instance Normed Int8 Int8 where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++instance Normed Int16 Int16 where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++instance Normed Int32 Int32 where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++instance Normed Int64 Int64 where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++instance Normed Word Word where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++instance Normed Word8 Word8 where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++instance Normed Word16 Word16 where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++instance Normed Word32 Word32 where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++instance Normed Word64 Word64 where+ normL1 = P.abs+ normL2 = P.abs+ normLp _ a = P.abs a++-- | distance between numbers using L1, L2 or Lp-norms ----- > distance a b >= zero--- > distance a a == zero--- > \a b c -> distance a c + distance b c - distance a b >= zero &&--- > distance a b + distance b c - distance a c >= zero &&--- > distance a b + distance a c - distance b c >= zero &&+-- > distanceL2 a b >= zero+-- > distanceL2 a a == zero+-- > \a b c -> distanceL2 a c + distanceL2 b c - distanceL2 a b >= zero &&+-- > distanceL2 a b + distanceL2 b c - distanceL2 a c >= zero &&+-- > distanceL2 a b + distanceL2 a c - distanceL2 b c >= zero && class Metric a b where- distance :: a -> a -> b+ distanceL1 :: a -> a -> b+ distanceL2 :: a -> a -> b+ distanceLp :: b -> a -> a -> b instance Metric Double Double where- distance a b = abs (a - b)+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b) instance Metric Float Float where- distance a b = abs (a - b)+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b) instance Metric Int Int where- distance a b = abs (a - b)+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b) instance Metric Integer Integer where- distance a b = abs (a - b)+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b) -instance (Multiplicative a, ExpField a) =>+instance (Multiplicative a, ExpField a, Normed a a) => Metric (Complex a) a where- distance a b = size (a - b)+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b) +instance Metric Natural Natural where+ distanceL1 a b = fromInteger $ normL1 (toInteger a - toInteger b)+ distanceL2 a b = fromInteger $ normL2 (toInteger a - toInteger b)+ distanceLp p a b = fromInteger (normLp (toInteger p) (toInteger a - toInteger b))++instance Metric Int8 Int8 where+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b)++instance Metric Int16 Int16 where+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b)++instance Metric Int32 Int32 where+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b)++instance Metric Int64 Int64 where+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b)++-- fixme: circular distance may be more appropriate+instance Metric Word Word where+ distanceL1 a b = fromInteger $ normL1 (toInteger a - toInteger b)+ distanceL2 a b = fromInteger $ normL2 (toInteger a - toInteger b)+ distanceLp p a b = fromInteger (normLp (toInteger p) (toInteger a - toInteger b))++instance Metric Word8 Word8 where+ distanceL1 a b = fromInteger $ normL1 (toInteger a - toInteger b)+ distanceL2 a b = fromInteger $ normL2 (toInteger a - toInteger b)+ distanceLp p a b = fromInteger (normLp (toInteger p) (toInteger a - toInteger b))++instance Metric Word16 Word16 where+ distanceL1 a b = fromInteger $ normL1 (toInteger a - toInteger b)+ distanceL2 a b = fromInteger $ normL2 (toInteger a - toInteger b)+ distanceLp p a b = fromInteger (normLp (toInteger p) (toInteger a - toInteger b))++instance Metric Word32 Word32 where+ distanceL1 a b = fromInteger $ normL1 (toInteger a - toInteger b)+ distanceL2 a b = fromInteger $ normL2 (toInteger a - toInteger b)+ distanceLp p a b = fromInteger (normLp (toInteger p) (toInteger a - toInteger b))++instance Metric Word64 Word64 where+ distanceL1 a b = fromInteger $ normL1 (toInteger a - toInteger b)+ distanceL2 a b = fromInteger $ normL2 (toInteger a - toInteger b)+ distanceLp p a b = fromInteger (normLp (toInteger p) (toInteger a - toInteger b))+ -- | todo: This should probably be split off into some sort of alternative Equality logic, but to what end?-class (AdditiveGroup a) =>+class (Eq a, AdditiveGroup a) => Epsilon a where nearZero :: a -> Bool+ nearZero a = a == zero+ aboutEqual :: a -> a -> Bool- positive :: (Eq a, Signed a) => a -> Bool+ aboutEqual a b = nearZero $ a - b++ positive :: (Signed a) => a -> Bool positive a = a == abs a- veryPositive :: (Eq a, Signed a) => a -> Bool+ veryPositive :: (Signed a) => a -> Bool veryPositive a = P.not (nearZero a) && positive a- veryNegative :: (Eq a, Signed a) => a -> Bool+ veryNegative :: (Signed a) => a -> Bool veryNegative a = P.not (nearZero a P.|| positive a) infixl 4 ≈@@ -124,20 +329,33 @@ instance Epsilon Double where nearZero a = abs a <= (1e-12 :: Double)- aboutEqual a b = nearZero $ a - b instance Epsilon Float where nearZero a = abs a <= (1e-6 :: Float)- aboutEqual a b = nearZero $ a - b -instance Epsilon Int where- nearZero a = a == zero- aboutEqual a b = nearZero $ a - b+instance Epsilon Int -instance Epsilon Integer where- nearZero a = a == zero- aboutEqual a b = nearZero $ a - b+instance Epsilon Integer instance (Epsilon a) => Epsilon (Complex a) where nearZero (rx :+ ix) = nearZero rx && nearZero ix aboutEqual a b = nearZero $ a - b++instance Epsilon Int8++instance Epsilon Int16++instance Epsilon Int32++instance Epsilon Int64++instance Epsilon Word++instance Epsilon Word8++instance Epsilon Word16++instance Epsilon Word32++instance Epsilon Word64+
src/NumHask/Algebra/Module.hs view
@@ -24,6 +24,9 @@ import NumHask.Algebra.Metric import NumHask.Algebra.Multiplicative import NumHask.Algebra.Ring+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Natural import Prelude (Double, Float, Int, Integer) @@ -82,12 +85,18 @@ -- | Banach (with Norm) laws form rules around size and direction of a number, with a potential crossing into another codomain. ----- > a == singleton zero || normalize a *. size a == a+-- > a == singleton zero || normalizeL2 a *. normL2 a == a class (ExpField a, Normed (r a) a, MultiplicativeGroupModule r a) => Banach r a where- normalize :: r a -> r a- normalize a = a ./ size a+ normalizeL1 :: r a -> r a+ normalizeL1 a = a ./ normL1 a + normalizeL2 :: r a -> r a+ normalizeL2 a = a ./ normL2 a++ normalizeLp :: a -> r a -> r a+ normalizeLp p a = a ./ normLp p a+ -- | the inner product of a representable over a semiring -- -- > a <.> b == b <.> a@@ -109,6 +118,26 @@ type instance Double >< Double = Double type instance Float >< Float = Float++type instance Natural >< Natural = Natural++type instance Int8 >< Int8 = Int8++type instance Int16 >< Int16 = Int16++type instance Int32 >< Int32 = Int32++type instance Int64 >< Int64 = Int64++type instance Word >< Word = Word++type instance Word8 >< Word8 = Word8++type instance Word16 >< Word16 = Word16++type instance Word32 >< Word32 = Word32++type instance Word64 >< Word64 = Word64 -- | representation synthesis type family TensorRep k1 k2 where
src/NumHask/Algebra/Multiplicative.hs view
@@ -15,6 +15,9 @@ ) where import Data.Complex (Complex(..))+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Natural (Natural(..)) import NumHask.Algebra.Additive import qualified Prelude as P import Prelude (Bool(..), Double, Float, Int, Integer)@@ -47,6 +50,36 @@ (rx :+ ix) `times` (ry :+ iy) = (rx `times` ry - ix `times` iy) :+ (ix `times` ry + iy `times` rx) +instance MultiplicativeMagma Natural where+ times = (P.*)++instance MultiplicativeMagma Int8 where+ times = (P.*)++instance MultiplicativeMagma Int16 where+ times = (P.*)++instance MultiplicativeMagma Int32 where+ times = (P.*)++instance MultiplicativeMagma Int64 where+ times = (P.*)++instance MultiplicativeMagma Word where+ times = (P.*)++instance MultiplicativeMagma Word8 where+ times = (P.*)++instance MultiplicativeMagma Word16 where+ times = (P.*)++instance MultiplicativeMagma Word32 where+ times = (P.*)++instance MultiplicativeMagma Word64 where+ times = (P.*)+ -- | Unital magma for multiplication. -- -- > one `times` a == a@@ -74,6 +107,36 @@ MultiplicativeUnital (Complex a) where one = one :+ zero +instance MultiplicativeUnital Natural where+ one = 1++instance MultiplicativeUnital Int8 where+ one = 1++instance MultiplicativeUnital Int16 where+ one = 1++instance MultiplicativeUnital Int32 where+ one = 1++instance MultiplicativeUnital Int64 where+ one = 1++instance MultiplicativeUnital Word where+ one = 1++instance MultiplicativeUnital Word8 where+ one = 1++instance MultiplicativeUnital Word16 where+ one = 1++instance MultiplicativeUnital Word32 where+ one = 1++instance MultiplicativeUnital Word64 where+ one = 1+ -- | Associative magma for multiplication. -- -- > (a `times` b) `times` c == a `times` (b `times` c)@@ -93,6 +156,26 @@ instance (AdditiveGroup a, MultiplicativeAssociative a) => MultiplicativeAssociative (Complex a) +instance MultiplicativeAssociative Natural++instance MultiplicativeAssociative Int8++instance MultiplicativeAssociative Int16++instance MultiplicativeAssociative Int32++instance MultiplicativeAssociative Int64++instance MultiplicativeAssociative Word++instance MultiplicativeAssociative Word8++instance MultiplicativeAssociative Word16++instance MultiplicativeAssociative Word32++instance MultiplicativeAssociative Word64+ -- | Commutative magma for multiplication. -- -- > a `times` b == b `times` a@@ -112,6 +195,26 @@ instance (AdditiveGroup a, MultiplicativeCommutative a) => MultiplicativeCommutative (Complex a) +instance MultiplicativeCommutative Natural++instance MultiplicativeCommutative Int8++instance MultiplicativeCommutative Int16++instance MultiplicativeCommutative Int32++instance MultiplicativeCommutative Int64++instance MultiplicativeCommutative Word++instance MultiplicativeCommutative Word8++instance MultiplicativeCommutative Word16++instance MultiplicativeCommutative Word32++instance MultiplicativeCommutative Word64+ -- | Invertible magma for multiplication. -- -- > ∀ a ∈ A: recip a ∈ A@@ -142,6 +245,7 @@ instance MultiplicativeIdempotent Bool -- | product definition avoiding a clash with the Product monoid in base+-- fixme: fit in with Product in base -- product :: (Multiplicative a, P.Foldable f) => f a -> a product = P.foldr (*) one@@ -172,6 +276,26 @@ instance Multiplicative Bool instance (AdditiveGroup a, Multiplicative a) => Multiplicative (Complex a)++instance Multiplicative Natural++instance Multiplicative Int8++instance Multiplicative Int16++instance Multiplicative Int32++instance Multiplicative Int64++instance Multiplicative Word++instance Multiplicative Word8++instance Multiplicative Word16++instance Multiplicative Word32++instance Multiplicative Word64 -- | Non-commutative left divide --
+ src/NumHask/Algebra/Rational.hs view
@@ -0,0 +1,232 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# OPTIONS_GHC -Wall #-}++-- | Integral classes+module NumHask.Algebra.Rational+ ( Ratio(..)+ , Rational+ , ToRatio(..)+ , FromRatio(..)+ , fromRational+ -- * $integral_functionality+ , reduce+ , gcd+ ) where++-- import Data.Coerce+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Float+import GHC.Natural (Natural(..))+import qualified GHC.Real+import qualified Prelude as P+import Prelude (Double, Float, Int, Integer, (.))+import NumHask.Algebra.Additive+import NumHask.Algebra.Multiplicative+import NumHask.Algebra.Distribution+import NumHask.Algebra.Integral+import NumHask.Algebra.Metric+import NumHask.Algebra.Ring+import NumHask.Algebra.Field++data Ratio a = !a :% !a deriving (P.Eq, P.Show)++type Rational = Ratio Integer++instance (P.Ord a, Multiplicative a, Integral a) => P.Ord (Ratio a) where+ (x:%y) <= (x':%y') = x * y' P.<= x' * y+ (x:%y) < (x':%y') = x * y' P.< x' * y++instance (P.Ord a, Integral a, Signed a, AdditiveInvertible a) => AdditiveMagma (Ratio a) where+ (x:%y) `plus` (x':%y') =+ reduce ((x `times` y') `plus` (x' `times` y)) (y `times` y')++instance (P.Ord a, Integral a, Signed a, AdditiveInvertible a) => AdditiveUnital (Ratio a) where+ zero = zero :% one++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) => AdditiveAssociative (Ratio a)++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) => AdditiveCommutative (Ratio a)++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) => AdditiveInvertible (Ratio a) where+ negate (x :% y) = negate x :% y++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) => Additive (Ratio a)++instance (P.Ord a, Signed a, Integral a, AdditiveGroup a) => AdditiveGroup (Ratio a)++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) => MultiplicativeMagma (Ratio a) where+ (x:%y) `times` (x':%y') = reduce (x `times` x') (y `times` y')++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) => MultiplicativeUnital (Ratio a) where+ one = one :% one++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) =>+ MultiplicativeAssociative (Ratio a)++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) =>+ MultiplicativeCommutative (Ratio a)++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) =>+ MultiplicativeInvertible (Ratio a) where+ recip (x :% y)+ | x P.< zero = negate y :% negate x+ | P.otherwise = y :% x++instance (Signed a, AdditiveInvertible a, AdditiveUnital a, Integral a, P.Ord a, Multiplicative a) => Multiplicative (Ratio a)++instance (Signed a, AdditiveInvertible a, AdditiveUnital a, Integral a, P.Ord a, Multiplicative a) =>+ MultiplicativeGroup (Ratio a)++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) => Distribution (Ratio a)++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) => Semiring (Ratio a)+instance (P.Ord a, Signed a, Integral a, AdditiveGroup a) => Ring (Ratio a)+instance (P.Ord a, Signed a, Integral a, Multiplicative a, Ring a) => CRing (Ratio a)+instance (P.Ord a, Signed a, Integral a, Multiplicative a, Ring a) =>+ InvolutiveRing (Ratio a)++instance (P.Ord a, Signed a, Integral a, Multiplicative a, Ring a) =>+ Semifield (Ratio a)++instance (P.Ord a, Signed a, Integral a, Multiplicative a, Ring a) =>+ Field (Ratio a)++instance (P.Ord a, Signed a, ToInteger a, Integral a, Multiplicative a, Ring a) => QuotientField (Ratio a) where+ properFraction (n :% d) = let (w,r) = quotRem n d in (toInteger w,r:%d)++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a, Multiplicative a, Ring a) => UpperBoundedField (Ratio a) where+ isNaN (n :% d) = n P.== zero P.&& d P.== zero++instance (P.Ord a, Signed a, Integral a, Multiplicative a, Ring a, AdditiveInvertible a) => LowerBoundedField (Ratio a)++instance (P.Ord a, Signed a, Integral a, AdditiveInvertible a) => Signed (Ratio a) where+ sign (n :% _)+ | n P.== zero = zero+ | n P.> zero = one+ | P.otherwise = negate one+ abs (n :% d) = abs n :% abs d++instance (P.Ord a, Integral a, Signed a, AdditiveInvertible a) => Normed (Ratio a) (Ratio a) where+ normL1 = abs+ normL2 = abs+ normLp _ = abs++instance (P.Ord a, Integral a, Signed a, AdditiveGroup a) => Metric (Ratio a) (Ratio a) where+ distanceL1 a b = normL1 (a - b)+ distanceL2 a b = normL2 (a - b)+ distanceLp p a b = normLp p (a - b)++instance (P.Ord a, Signed a, Integral a, AdditiveGroup a) => Epsilon (Ratio a)++instance (FromInteger a, MultiplicativeUnital a) => FromInteger (Ratio a) where+ fromInteger x = fromInteger x :% one++-- | toRatio is equivalent to `Real` in base.+class ToRatio a where+ toRatio :: a -> Ratio Integer++instance (ToInteger a) => ToRatio (Ratio a) where+ toRatio (n :% d) = toInteger n :% toInteger d++-- | `Fractional` in base splits into fromRatio and MultiplicativeGroup+class FromRatio a where+ fromRatio :: Ratio Integer -> a++instance (FromInteger a) => FromRatio (Ratio a) where+ fromRatio (n :% d) = fromInteger n :% fromInteger d++-- | coercion of 'Rational's+--+-- > fromRational a == a+fromRational :: (ToRatio a, FromRatio b) => a -> b+fromRational = fromRatio . toRatio++-- | fixme: use coerce+fromBaseRational :: P.Rational -> Ratio Integer+fromBaseRational (n GHC.Real.:% d) = n :% d++instance FromRatio Double where+ fromRatio (n:%d)= rationalToDouble n d++instance FromRatio Float where+ fromRatio (n:%d)= rationalToFloat n d++instance ToRatio Double where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Float where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Int where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Integer where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Natural where+ toRatio = fromBaseRational . P.toRational++instance ToRatio P.Rational where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Int8 where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Int16 where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Int32 where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Int64 where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Word where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Word8 where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Word16 where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Word32 where+ toRatio = fromBaseRational . P.toRational++instance ToRatio Word64 where+ toRatio = fromBaseRational . P.toRational++-- * $integral_functions+-- integral functionality is largely based on GHC.Real+--+-- | 'reduce' is a subsidiary function used only in this module.+-- It normalises a ratio by dividing both numerator and denominator by+-- their greatest common divisor.+reduce :: (P.Ord a, AdditiveInvertible a, Signed a, Integral a) => a -> a -> Ratio a+reduce x y+ | x P.== zero P.&& y P.== zero = zero :% zero+ | z P.== zero = one :% zero+ | P.otherwise = (x `quot` z) % (y `quot` z)+ where+ z = gcd x y+ n % d+ | d P.< zero = negate n :% negate d+ | P.otherwise = n:%d++-- | @'gcd' x y@ is the non-negative factor of both @x@ and @y@ of which+-- every common factor of @x@ and @y@ is also a factor; for example+-- @'gcd' 4 2 = 2@, @'gcd' (-4) 6 = 2@, @'gcd' 0 4@ = @4@. @'gcd' 0 0@ = @0@.+-- (That is, the common divisor that is \"greatest\" in the divisibility+-- preordering.)+--+-- Note: Since for signed fixed-width integer types, @'abs' 'minBound' < 0@,+-- the result may be negative if one of the arguments is @'minBound'@ (and+-- necessarily is if the other is @0@ or @'minBound'@) for such types.+gcd :: (P.Ord a, Signed a, Integral a) => a -> a -> a+gcd x y = gcd' (abs x) (abs y)+ where+ gcd' a b+ | b P.== zero = a+ | P.otherwise = gcd' b (a `rem` b)
src/NumHask/Algebra/Ring.hs view
@@ -1,4 +1,5 @@ {-# OPTIONS_GHC -Wall #-}+{-# language FlexibleInstances #-} -- | Ring classes. A distinguishment is made between Rings and Commutative Rings. module NumHask.Algebra.Ring@@ -7,9 +8,13 @@ , CRing , StarSemiring(..) , KleeneAlgebra+ , InvolutiveRing(..) ) where import Data.Complex (Complex(..))+import Data.Int (Int8, Int16, Int32, Int64)+import Data.Word (Word, Word8, Word16, Word32, Word64)+import GHC.Natural (Natural(..)) import NumHask.Algebra.Additive import NumHask.Algebra.Distribution import NumHask.Algebra.Multiplicative@@ -31,8 +36,31 @@ instance (AdditiveGroup a, Semiring a) => Semiring (Complex a) +instance Semiring Natural++instance Semiring Int8++instance Semiring Int16++instance Semiring Int32++instance Semiring Int64++instance Semiring Word++instance Semiring Word8++instance Semiring Word16++instance Semiring Word32++instance Semiring Word64+ -- | Ring--- a summary of the laws inherited from the ring super-classes+-- +-- A Ring consists of a set equipped with two binary operations that generalize the arithmetic operations of addition and multiplication; it is an abelian group with a second binary operation that is associative, is distributive over the abelian group operation, and has an identity element.+-- +-- Summary of the laws inherited from the ring super-classes: -- -- > zero + a == a -- > a + zero == a@@ -49,6 +77,7 @@ -- > (a + b) `times` c == a `times` c + b `times` c -- > a `times` zero == zero -- > zero `times` a == zero+-- class ( Semiring a , AdditiveGroup a ) =>@@ -64,6 +93,24 @@ instance (Ring a) => Ring (Complex a) +instance Ring Int8++instance Ring Int16++instance Ring Int32++instance Ring Int64++instance Ring Word++instance Ring Word8++instance Ring Word16++instance Ring Word32++instance Ring Word64+ -- | CRing is a Ring with Multiplicative Commutation. It arises often due to '*' being defined as a multiplicative commutative operation. class (Multiplicative a, Ring a) => CRing a@@ -78,6 +125,24 @@ instance (CRing a) => CRing (Complex a) +instance CRing Int8++instance CRing Int16++instance CRing Int32++instance CRing Int64++instance CRing Word++instance CRing Word8++instance CRing Word16++instance CRing Word32++instance CRing Word64+ -- | StarSemiring -- -- > star a = one + a `times` star a@@ -96,4 +161,47 @@ -- class (StarSemiring a, AdditiveIdempotent a) => KleeneAlgebra a +-- | Involutive Ring+--+-- > adj (a + b) ==> adj a + adj b+-- > adj (a * b) ==> adj a * adj b+-- > adj one ==> one+-- > adj (adj a) ==> a+--+-- Note: elements for which @adj a == a@ are called "self-adjoint".+--+class Semiring a => InvolutiveRing a where+ adj :: a -> a+ adj x = x++instance InvolutiveRing Double++instance InvolutiveRing Float++instance InvolutiveRing Integer++instance InvolutiveRing Int++instance (Ring a) => InvolutiveRing (Complex a) where+ adj (a :+ b) = a :+ negate b++instance InvolutiveRing Natural++instance InvolutiveRing Int8++instance InvolutiveRing Int16++instance InvolutiveRing Int32++instance InvolutiveRing Int64++instance InvolutiveRing Word++instance InvolutiveRing Word8++instance InvolutiveRing Word16++instance InvolutiveRing Word32++instance InvolutiveRing Word64
stack.yaml view
@@ -1,3 +1,3 @@-resolver: nightly-2018-04-04+resolver: nightly-2018-05-06 extra-deps: []