packages feed

algebra 4.0 → 4.1

raw patch · 5 files changed

+263/−1 lines, 5 filesdep ~basePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Numeric.Domain.Class: class (IntegralSemiring d, Ring d) => Domain d
+ Numeric.Domain.Class: instance (IntegralSemiring d, Ring d) => Domain d
+ Numeric.Domain.Euclidean: chineseRemainder :: Euclidean r => [(r, r)] -> r
+ Numeric.Domain.Euclidean: class (Ring r, DecidableZero r, DecidableUnits r, Domain r) => Euclidean r where quot a b = fst $ a `divide` b rem a b = snd $ a `divide` b gcd a b = let (g, _, _) : _ = euclid a b in g euclid f g = let (ug, g') = splitUnit g Just t' = recipUnit ug (uf, f') = splitUnit f Just s = recipUnit uf in step [(g', 0, t'), (f', s, 0)] where step acc@((r', s', t') : (r, s, t) : _) | isZero r' = tail acc | otherwise = let q = r `quot` r' (ur, r'') = splitUnit $ r - q * r' Just u = recipUnit ur s'' = (s - q * s') * u t'' = (t - q * t') * u in step ((r'', s'', t'') : acc) step _ = error "cannot happen!"
+ Numeric.Domain.Euclidean: degree :: Euclidean r => r -> Maybe Natural
+ Numeric.Domain.Euclidean: divide :: Euclidean r => r -> r -> (r, r)
+ Numeric.Domain.Euclidean: euclid :: Euclidean r => r -> r -> [(r, r, r)]
+ Numeric.Domain.Euclidean: gcd :: Euclidean r => r -> r -> r
+ Numeric.Domain.Euclidean: gcd' :: Euclidean r => [r] -> r
+ Numeric.Domain.Euclidean: instance Euclidean Integer
+ Numeric.Domain.Euclidean: leadingUnit :: Euclidean r => r -> r
+ Numeric.Domain.Euclidean: normalize :: Euclidean r => r -> r
+ Numeric.Domain.Euclidean: prs :: Euclidean r => r -> r -> [(r, r, r)]
+ Numeric.Domain.Euclidean: quot :: Euclidean r => r -> r -> r
+ Numeric.Domain.Euclidean: rem :: Euclidean r => r -> r -> r
+ Numeric.Domain.Euclidean: splitUnit :: Euclidean r => r -> (r, r)
+ Numeric.Field.Fraction: (%) :: Euclidean d => d -> d -> Fraction d
+ Numeric.Field.Fraction: data Fraction d
+ Numeric.Field.Fraction: denominator :: Fraction t -> t
+ Numeric.Field.Fraction: instance (Characteristic d, Euclidean d) => Characteristic (Fraction d)
+ Numeric.Field.Fraction: instance (Commutative d, Euclidean d) => Commutative (Fraction d)
+ Numeric.Field.Fraction: instance (Eq d, Multiplicative d) => Eq (Fraction d)
+ Numeric.Field.Fraction: instance (Eq d, Show d, Unital d) => Show (Fraction d)
+ Numeric.Field.Fraction: instance (Ord d, Multiplicative d) => Ord (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Abelian (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Additive (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => DecidableUnits (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => DecidableZero (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Division (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Group (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => IntegralSemiring (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => LeftModule Integer (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => LeftModule Natural (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Monoidal (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Multiplicative (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Rig (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => RightModule Integer (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => RightModule Natural (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Ring (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Semiring (Fraction d)
+ Numeric.Field.Fraction: instance Euclidean d => Unital (Fraction d)
+ Numeric.Field.Fraction: lcm :: Euclidean r => r -> r -> r
+ Numeric.Field.Fraction: numerator :: Fraction t -> t
+ Numeric.Field.Fraction: type Ratio = Fraction

Files

CHANGELOG.markdown view
@@ -1,3 +1,12 @@+4.1+---+* Added Euclidean domains and the field of fractions.++4.0+---+* Compatibility with GHC 7.8.x+* Removed `keyed` and `representable-tries` dependencies+ 3.0.2 ----- * Started CHANGELOG
algebra.cabal view
@@ -1,6 +1,6 @@ name:          algebra category:      Math, Algebra-version:       4.0+version:       4.1 license:       BSD3 cabal-version: >= 1.6 license-file:  LICENSE@@ -93,8 +93,11 @@     Numeric.Decidable.Units     Numeric.Decidable.Zero     Numeric.Dioid.Class+    Numeric.Domain.Class+    Numeric.Domain.Euclidean     Numeric.Exp     Numeric.Field.Class+    Numeric.Field.Fraction     Numeric.Log     Numeric.Map     Numeric.Module.Class
+ src/Numeric/Domain/Class.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}+module Numeric.Domain.Class where+import Numeric.Ring.Class+import Numeric.Semiring.Integral++-- | (Integral) domain is the integral semiring.+class (IntegralSemiring d, Ring d) => Domain d+instance (IntegralSemiring d, Ring d) => Domain d
+ src/Numeric/Domain/Euclidean.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE CPP, ConstraintKinds, FlexibleContexts, FlexibleInstances     #-}+{-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses, RankNTypes #-}+{-# LANGUAGE RebindableSyntax, UndecidableInstances                        #-}+module Numeric.Domain.Euclidean (Euclidean(..), prs, normalize, gcd', leadingUnit, chineseRemainder) where+import Numeric.Additive.Group+import Numeric.Algebra.Class+import Numeric.Algebra.Unital+import Numeric.Decidable.Units+import Numeric.Decidable.Zero+import Numeric.Domain.Class+import Numeric.Natural (Natural)+import Numeric.Ring.Class+import Prelude (Eq (..), Integer, Maybe (..), abs)+import Prelude (fst, otherwise)+import Prelude (signum, snd, ($), (.))+import qualified Prelude                 as P++infixl 7 `quot`, `rem`+infix  7 `divide`+class (Ring r, DecidableZero r, DecidableUnits r, Domain r) => Euclidean r where+  -- | @splitUnit r@ calculates its leading unit and normal form.+  --+  -- prop> let (u, n) = splitUnit r in r == u * n && fst (splitUnit n) == one && isUnit u+  splitUnit :: r -> (r, r)+  -- | Euclidean (degree) function on @r@.+  degree :: r -> Maybe Natural+  -- | Division algorithm. @a `divide` b@ calculates+  --   quotient and reminder of @a@ divided by @b@.+  --+  -- prop> let (q, r) = divide a p in p*q + r == a && degree r < degree q+  divide :: r                   -- ^ elements divided by+         -> r                   -- ^ divisor+         -> (r,r)               -- ^ quotient and remin+  quot :: r -> r -> r+  quot a b = fst $ a `divide` b+  {-# INLINE quot #-}++  rem :: r -> r -> r+  rem a b = snd $ a `divide` b+  {-# INLINE rem #-}++  -- | @'gcd' a b@ calculates greatest common divisor of @a@ and @b@.+  gcd :: r -> r -> r+  gcd a b = let (g,_,_):_ = euclid a b+            in g+  {-# INLINE gcd #-}++  -- | Extended euclidean algorithm.+  --+  -- prop> euclid f g == xs ==> all (\(r, s, t) -> r == f * s + g * t) xs+  euclid :: r -> r -> [(r,r,r)]+  euclid f g =+    let (ug, g') = splitUnit g+        Just t'  = recipUnit ug+        (uf, f') = splitUnit f+        Just s   = recipUnit uf+    in step [(g', 0, t'), (f', s, 0)]+    where+      step acc@((r',s',t'):(r,s,t):_)+        | isZero r' = P.tail acc+        | otherwise =+          let q         = r `quot` r'+              (ur, r'') = splitUnit $ r - q * r'+              Just u    = recipUnit ur+              s''       = (s - q * s') * u+              t''       = (t - q * t') * u+          in step ((r'', s'', t'') : acc)+      step _ = P.error "cannot happen!"+#if (__GLASGOW_HASKELL__ > 708)+  {-# MINIMAL splitUnit, degree, divide #-}+#endif++prs :: Euclidean r => r -> r -> [(r, r, r)]+prs f g = step [(g, 0, 1), (f, 1, 0)]+  where+    step acc@((r',s',t'):(r,s,t):_)+      | isZero r' = P.tail acc+      | otherwise =+        let q         = r `quot` r'+            s''       = (s - q * s')+            t''       = (t - q * t')+        in step ((r - q * r', s'', t'') : acc)+    step _ = P.error "cannot happen!"++gcd' :: Euclidean r => [r] -> r+gcd' []     = one+gcd' [x]    = leadingUnit x+gcd' [x,y]  = gcd x y+gcd' (x:xs) = gcd x (gcd' xs)++normalize :: Euclidean r => r -> r+normalize = snd . splitUnit++leadingUnit :: Euclidean r => r -> r+leadingUnit = fst . splitUnit++instance Euclidean Integer where+  splitUnit 0 = (1, 0)+  splitUnit n = (signum n, abs n)+  {-# INLINE splitUnit #-}++  degree = Just . P.fromInteger . abs+  {-# INLINE degree #-}++  divide = P.divMod+  {-# INLINE divide #-}++chineseRemainder :: Euclidean r+                 => [(r, r)] -- ^ List of @(m_i, v_i)@+                 -> r        -- ^ @f@ with @f@ = @v_i@ (mod @v_i@)+chineseRemainder mvs =+  let (ms, _) = P.unzip mvs+      m = product ms+  in sum [((vi*s) `rem` mi)*n | (mi, vi) <- mvs+                               , let n = m `quot` mi+                               , let (_, s, _) : _ = euclid n mi+                               ]
+ src/Numeric/Field/Fraction.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE MultiParamTypeClasses, NoImplicitPrelude, RebindableSyntax #-}+{-# LANGUAGE ScopedTypeVariables, ViewPatterns                          #-}+module Numeric.Field.Fraction+  ( Fraction+  , numerator+  , denominator+  , Ratio+  , (%)+  , lcm+  ) where+import Data.Proxy+import Numeric.Additive.Class+import Numeric.Additive.Group+import Numeric.Algebra.Class+import Numeric.Algebra.Commutative+import Numeric.Algebra.Division+import Numeric.Algebra.Unital+import Numeric.Decidable.Units+import Numeric.Decidable.Zero+import Numeric.Domain.Euclidean+import Numeric.Natural+import Numeric.Rig.Characteristic+import Numeric.Rig.Class+import Numeric.Ring.Class+import Numeric.Semiring.Integral+import Prelude                     hiding (Integral (..), Num (..), gcd, lcm)++-- | Fraction field @k(D)@ of 'Euclidean' domain @D@.+data Fraction d = Fraction !d !d++-- Invariants: r == Fraction p q+--         ==> leadingUnit q == one && q /= 0+--          && isUnit (gcd p q)++-- | Convenient synonym for 'Fraction'.+type Ratio = Fraction++lcm :: Euclidean r => r -> r -> r+lcm p q = p * q `quot` gcd p q++instance (Eq d, Show d, Unital d) => Show (Fraction d) where+  showsPrec d (Fraction p q)+   | q == one    = showsPrec d p+   | otherwise = showParen (d > 5) $ showsPrec 6 p . showString " / " . showsPrec 6 q++infixl 7 %+(%) :: Euclidean d => d -> d -> Fraction d+a % b = let (ua, a') = splitUnit a+            (ub, b') = splitUnit b+            Just ub' = recipUnit ub+            r = gcd a' b'+        in Fraction (ua * ub' * a' `quot` r) (b' `quot` r)++numerator :: Fraction t -> t+numerator (Fraction q _) = q+{-# INLINE numerator #-}++denominator :: Fraction t -> t+denominator (Fraction _ p) = p+{-# INLINE denominator #-}++instance Euclidean d => IntegralSemiring (Fraction d)+instance (Eq d, Multiplicative d) => Eq (Fraction d) where+  Fraction p q == Fraction s t = p*t == q*s+  {-# INLINE (==) #-}++instance (Ord d, Multiplicative d) => Ord (Fraction d)  where+  compare (Fraction p q) (Fraction p' q') = compare (p*q') (p'*q)+  {-# INLINE compare #-}++instance Euclidean d => Division (Fraction d) where+  recip (Fraction p q) | isZero p  = error "Ratio has zero denominator!"+                       | otherwise = let (recipUnit -> Just u, p') = splitUnit p+                                     in Fraction (q * u) p'+  Fraction p q / Fraction s t = (p*t) % (q*s)+  {-# INLINE recip #-}+  {-# INLINE (/) #-}++instance (Commutative d, Euclidean d) => Commutative (Fraction d)++instance Euclidean d => DecidableZero (Fraction d) where+  isZero (Fraction p _) = isZero p+  {-# INLINE isZero #-}++instance Euclidean d => DecidableUnits (Fraction d) where+  isUnit (Fraction p _) = not $ isZero p+  {-# INLINE isUnit #-}+  recipUnit (Fraction p q) | isZero p  = Nothing+                           | otherwise = Just (Fraction q p)+  {-# INLINE recipUnit #-}+instance Euclidean d => Ring (Fraction d)+instance Euclidean d => Abelian (Fraction d)+instance Euclidean d => Semiring (Fraction d)+instance Euclidean d => Group (Fraction d) where+  negate (Fraction p q) = Fraction (negate p) q+  Fraction p q - Fraction p' q' = (p*q'-p'*q) % (q*q')+instance Euclidean d => Monoidal (Fraction d) where+  zero = Fraction zero one+  {-# INLINE zero #-}+instance Euclidean d => LeftModule Integer (Fraction d) where+  n .* Fraction p r = (n .* p) % r+  {-# INLINE (.*) #-}+instance Euclidean d => RightModule Integer (Fraction d) where+  Fraction p r *. n = (p *. n) % r+  {-# INLINE (*.) #-}+instance Euclidean d => LeftModule Natural (Fraction d) where+  n .* Fraction p r = (n .* p) % r+  {-# INLINE (.*) #-}+instance Euclidean d => RightModule Natural (Fraction d) where+  Fraction p r *. n = (p *. n) % r+  {-# INLINE (*.) #-}+instance Euclidean d => Additive (Fraction d) where+  Fraction p q + Fraction s t =+    let u = gcd q t+    in Fraction (p * t `quot` u + s*q`quot`u) (q*t`quot`u)+  {-# INLINE (+) #-}+instance Euclidean d => Unital (Fraction d) where+  one = Fraction one one+  {-# INLINE one #-}+instance Euclidean d => Multiplicative (Fraction d) where+  Fraction p q * Fraction s t = (p*s) % (q*t)+instance Euclidean d => Rig (Fraction d)++instance (Characteristic d, Euclidean d) => Characteristic (Fraction d) where+  char _ = char (Proxy :: Proxy d)