From 03d54a93cab8fcb14ecbbfbe43e7c2068e5da8c0 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Wed, 8 Jul 2020 20:43:04 +0900 Subject: [PATCH 01/62] Corrects `recipUnit` for `WrapIntegral` --- algebraic-prelude/src/AlgebraicPrelude.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/algebraic-prelude/src/AlgebraicPrelude.hs b/algebraic-prelude/src/AlgebraicPrelude.hs index 12e06608..546a4fb1 100644 --- a/algebraic-prelude/src/AlgebraicPrelude.hs +++ b/algebraic-prelude/src/AlgebraicPrelude.hs @@ -440,8 +440,8 @@ instance (Eq a, P.Integral a) => DecidableUnits (WrapIntegral a) where recipUnit (WrapIntegral r) = if isUnit (WrapIntegral r) - then Nothing - else Just (WrapIntegral r) + then Just (WrapIntegral r) + else Nothing {-# INLINE recipUnit #-} instance (Eq a, P.Integral a) => DecidableAssociates (WrapIntegral a) where From 38c39c82f5f23c327b378c3e74ee7b0e6838070b Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Wed, 8 Jul 2020 20:51:51 +0900 Subject: [PATCH 02/62] Variadic representation for Prime Fields --- .../src/Algebra/Field/Prime/Test.hs | 9 +- halg-core/package.yaml | 3 + halg-core/src/Algebra/Field/Prime.hs | 290 ++++++++++++------ .../src/Algebra/Field/Galois.hs | 100 +++--- 4 files changed, 261 insertions(+), 141 deletions(-) diff --git a/halg-core-test/src/Algebra/Field/Prime/Test.hs b/halg-core-test/src/Algebra/Field/Prime/Test.hs index 44ca2907..60e85fcd 100644 --- a/halg-core-test/src/Algebra/Field/Prime/Test.hs +++ b/halg-core-test/src/Algebra/Field/Prime/Test.hs @@ -4,14 +4,13 @@ module Algebra.Field.Prime.Test where import Algebra.Field.Finite.Test -import Algebra.Field.Prime (F) -import Data.Reflection (Reifies) -import Prelude (Integer, Maybe (..), Monad) +import Algebra.Field.Prime (F, IsPrimeChar) +import Prelude (Maybe (..), Monad) import Test.QuickCheck (Arbitrary (..)) import Test.SmallCheck.Series (Serial (..)) -instance Reifies p Integer => Arbitrary (F p) where +instance IsPrimeChar p => Arbitrary (F p) where arbitrary = arbitraryFiniteField (Nothing :: Maybe (F p)) -instance (Monad m, Reifies p Integer) => Serial m (F p) where +instance (Monad m, IsPrimeChar p) => Serial m (F p) where series = seriesFiniteField (Nothing :: Maybe (F p)) diff --git a/halg-core/package.yaml b/halg-core/package.yaml index a7c456fe..5cd2d448 100644 --- a/halg-core/package.yaml +++ b/halg-core/package.yaml @@ -50,6 +50,7 @@ dependencies: - equational-reasoning - ghc-typelits-knownnat - ghc-typelits-presburger >= 0.2.0.5 +- singletons-presburger - hashable - intern - lens @@ -64,4 +65,6 @@ dependencies: library: source-dirs: src + dependencies: + - template-haskell ghc-options: ["-Wall", "-O2"] diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index ac905e57..0682ae1d 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -1,13 +1,19 @@ -{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, GADTs #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, LambdaCase, MultiParamTypeClasses #-} +{-# LANGUAGE MultiWayIf, PolyKinds, QuantifiedConstraints, RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables, TemplateHaskell, TypeApplications #-} +{-# LANGUAGE TypeFamilies, TypeOperators, UndecidableInstances #-} +{-# LANGUAGE UndecidableSuperClasses #-} +{-# OPTIONS_GHC -fplugin Data.Singletons.TypeNats.Presburger #-} -- | Prime fields -{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances #-} -{-# LANGUAGE MultiParamTypeClasses, PolyKinds, RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables, TypeFamilies, UndecidableInstances #-} module Algebra.Field.Prime - ( F(), naturalRepr, reifyPrimeField, withPrimeField - , modNat, modNat', modRat, modRat' - , FiniteField(..), order - ) where + ( F(), IsPrimeChar, + naturalRepr, reifyPrimeField, withPrimeField, + modNat, modNat', modRat, modRat', + FiniteField(..), order, + -- * Auxiliary interfaces + HasPrimeField(..) + ) where import Algebra.Arithmetic (modPow) import Algebra.Field.Finite import Algebra.Normed @@ -19,12 +25,16 @@ import Control.Monad.Random (uniform) import Control.Monad.Random (runRand) import Control.Monad.Random (Random (..)) import qualified Data.Coerce as C +import Data.Kind (Constraint, Type) import Data.Maybe (fromMaybe) import Data.Proxy (Proxy (..), asProxyTypeOf) import qualified Data.Ratio as R import Data.Reflection (Reifies (reflect), reifyNat) +import Data.Singletons.Prelude import GHC.Read import GHC.TypeLits (KnownNat) +import GHC.TypeNats (Nat, natVal) +import Language.Haskell.TH (litT, numTyLit) import Numeric.Algebra (char) import Numeric.Algebra (Natural) import qualified Numeric.Algebra as NA @@ -33,44 +43,144 @@ import qualified Prelude as P -- | Prime field of characteristic @p@. -- @p@ should be prime, and not statically checked. -newtype F (p :: k) = F { runF :: Integer } - deriving (NFData) - - -instance Reifies p Integer => Read (F p) where +newtype F (p :: k) = F { runF :: F' p } + -- deriving (NFData) + +type WORD_MAX_BOUND = + $(litT $ numTyLit $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int) +type F' (p :: k) = F_Aux k p +type family F_Aux (k :: Type) (p :: k) where + F_Aux Nat p = + F_Nat_Aux (WORD_MAX_BOUND <= p) + F_Aux k p = Integer + +type family F_Nat_Aux (oob :: Bool) where + F_Nat_Aux 'True = Integer + F_Nat_Aux 'False = Int + +instance {-# OVERLAPPING #-} KnownNat p => NFData (F p) where + {-# INLINE rnf #-} + rnf = case sing @WORD_MAX_BOUND %<= sing @p of + STrue -> rnf . runF + SFalse -> rnf .runF + +instance {-# OVERLAPPABLE #-} NFData (F (p :: Type)) where + rnf = rnf . runF + +instance IsPrimeChar p => Read (F p) where readPrec = fromInteger <$> readPrec -modNat :: Reifies (p :: k) Integer => Integer -> F p +class HasPrimeField kind where + type CharInfo (p :: kind) :: Constraint + charInfo_ :: CharInfo (p :: kind) => pxy p -> Integer + liftFUnary_ + :: CharInfo p + => (forall x. (Show x, Integral x) => x -> x) + -> F (p :: kind) -> F p + wrapF_ :: CharInfo p + => (forall x. (Show x, Integral x) => x) + -> F (p :: kind) + unwrapF + :: CharInfo p + => (forall x. (Show x, Integral x) => x -> a) + -> F (p :: kind) -> a + +charInfo :: IsPrimeChar p => pxy p -> Integer +{-# INLINE charInfo #-} +charInfo = charInfo_ + +{-# INLINE liftFUnary #-} +liftFUnary + :: forall p. IsPrimeChar p + => (forall x. Integral x => x -> x) + -> F p -> F p +liftFUnary f = liftFUnary_ $ + (`mod` fromInteger (charInfo @p Proxy)) . f + +wrapF + :: forall p. (IsPrimeChar p) + => (forall x. Integral x => x) + -> F (p :: kind) +{-# INLINE wrapF #-} +wrapF = \s -> wrapF_ (unwrapIntegral $ s `rem` fromInteger (charInfo @p Proxy)) + +unwrapBinF + :: IsPrimeChar p + => (forall x. Integral x => x -> x -> a) + -> F p -> F p -> a +{-# INLINE unwrapBinF #-} +unwrapBinF f = unwrapF $ \i -> unwrapF $ \j -> f i (fromIntegral j) + +liftBinF + :: IsPrimeChar p + => (forall x. Integral x => x -> x -> x) + -> F p -> F p -> F p +{-# INLINE liftBinF #-} +liftBinF f = unwrapBinF $ \x y -> wrapF $ fromIntegral $ f x y + +instance {-# OVERLAPPING #-} HasPrimeField Nat where + type CharInfo n = KnownNat n + charInfo_ = fromIntegral . natVal + liftFUnary_ f = \(F i :: F p) -> + case sing @WORD_MAX_BOUND %<= sing @p of + STrue -> F $ f i + SFalse -> F $ f i + unwrapF f = \(F i :: F p) -> + case sing @WORD_MAX_BOUND %<= sing @p of + STrue -> f i + SFalse -> f i + wrapF_ s = + (case sing @WORD_MAX_BOUND %<= sing @p of + STrue -> F s + SFalse -> F s) + :: forall p. KnownNat p => F (p :: Nat) + +instance HasPrimeField Type where + type CharInfo n = Reifies n Integer + charInfo_ = reflect + liftFUnary_ f = \(F p) -> F $ f p + wrapF_ = F + unwrapF f = \(F p) -> f p + +class (HasPrimeField k, Reifies p Integer, CharInfo p) + => IsPrimeChar (p :: k) +instance (HasPrimeField k, Reifies p Integer, CharInfo p) + => IsPrimeChar (p :: k) + +modNat :: IsPrimeChar (p :: k) => Integer -> F p modNat = modNat' Proxy {-# INLINE modNat #-} -modNat' :: forall proxy (p :: k). Reifies p Integer => proxy (F p) -> Integer -> F p -modNat' _ i = +modNat' :: forall proxy (p :: k). IsPrimeChar p => proxy (F p) -> Integer -> F p +modNat' _ i = wrapF $ let p = reflect (Proxy :: Proxy p) - in F (i `rem` p) + in unwrapIntegral $ fromInteger i `rem` fromInteger p {-# INLINE modNat' #-} -reifyPrimeField :: Integer -> (forall p. KnownNat p => Proxy (F p) -> a) -> a +reifyPrimeField + :: Integer + -> (forall p. IsPrimeChar (p :: Nat) => Proxy (F p) -> a) -> a reifyPrimeField p f = reifyNat p (f . proxyF) -withPrimeField :: Integer -> (forall p. KnownNat p => F p) -> Integer -withPrimeField p f = reifyPrimeField p $ runF . asProxyTypeOf f +withPrimeField :: Integer -> (forall p. IsPrimeChar (p :: Nat) => F p) -> Integer +withPrimeField p f = reifyPrimeField p $ unwrapF toInteger . asProxyTypeOf f -naturalRepr :: F p -> Integer -naturalRepr = runF +naturalRepr :: IsPrimeChar p => F p -> Integer +naturalRepr = unwrapF toInteger proxyF :: Proxy (a :: k) -> Proxy (F a) proxyF Proxy = Proxy -instance Eq (F p) where - F n == F m = n == m +instance IsPrimeChar p => Eq (F p) where + (==) = unwrapBinF (==) -instance Reifies p Integer => Normed (F p) where +instance IsPrimeChar p => Normed (F p) where type Norm (F p) = Integer - norm fp@(F p) = p where _ = reflect fp + norm = unwrapF toInteger liftNorm = modNat -instance Reifies p Integer => P.Num (F p) where +instance IsPrimeChar p => P.Num (F p) where fromInteger = fromInteger' {-# INLINE fromInteger #-} @@ -87,99 +197,105 @@ instance Reifies p Integer => P.Num (F p) where {-# INLINE (*) #-} abs = id - signum (F 0) = F 0 - signum (F _) = F 1 - -pows :: (P.Integral a1, Reifies p Integer) => F p -> a1 -> F p -pows a n = modNat $ modPow (runF a) (reflect a) (toInteger n) - -instance Reifies p Integer => NA.Additive (F p) where - F a + F b = modNat $ a + b + signum = liftFUnary $ \case + 0 -> 0 + _ -> 1 + +pows :: forall p a1. (P.Integral a1, IsPrimeChar p) => F p -> a1 -> F p +pows = flip $ \n -> liftFUnary $ \a -> + unwrapIntegral $ + modPow + (WrapIntegral a) + (WrapIntegral $ fromInteger $ reflect $ Proxy @p) (toInteger n) + +instance IsPrimeChar p => NA.Additive (F p) where + (+) = liftBinF (P.+) {-# INLINE (+) #-} - sinnum1p n (F k) = modNat $ (1 P.+ P.fromIntegral n) * k + sinnum1p n = liftFUnary $ \k -> (1 P.+ P.fromIntegral n) P.* k {-# INLINE sinnum1p #-} -instance Reifies p Integer => NA.Multiplicative (F p) where - F a * F b = modNat $ a * b +instance IsPrimeChar p => NA.Multiplicative (F p) where + (*) = liftBinF (P.*) {-# INLINE (*) #-} pow1p n p = pows n (p P.+ 1) {-# INLINE pow1p #-} -instance Reifies p Integer => NA.Monoidal (F p) where - zero = F 0 +instance IsPrimeChar p => NA.Monoidal (F p) where + zero = wrapF 0 {-# INLINE zero #-} - sinnum n (F k) = modNat $ P.fromIntegral n * k + sinnum n = liftFUnary $ \k -> P.fromIntegral n P.* k {-# INLINE sinnum #-} -instance Reifies p Integer => NA.LeftModule Natural (F p) where - n .* F p = modNat (n .* p) +instance IsPrimeChar p => NA.LeftModule Natural (F p) where + (.*) n = liftFUnary $ \p -> fromIntegral n P.* p {-# INLINE (.*) #-} -instance Reifies p Integer => NA.RightModule Natural (F p) where - F p *. n = modNat (p *. n) +instance IsPrimeChar p => NA.RightModule Natural (F p) where + (*.) = flip (.*) {-# INLINE (*.) #-} -instance Reifies p Integer => NA.LeftModule Integer (F p) where - n .* F p = modNat (n * p) +instance IsPrimeChar p => NA.LeftModule Integer (F p) where + (.*) n = liftFUnary $ \p -> fromIntegral n P.* p {-# INLINE (.*) #-} -instance Reifies p Integer => NA.RightModule Integer (F p) where - F p *. n = modNat (p * n) +instance IsPrimeChar p => NA.RightModule Integer (F p) where + (*.) = flip (.*) {-# INLINE (*.) #-} -instance Reifies p Integer => NA.Group (F p) where - F a - F b = modNat $ a - b +instance IsPrimeChar p => NA.Group (F p) where + (-) = liftBinF (P.-) {-# INLINE (-) #-} - negate (F a) = modNat $ negate a + negate = liftFUnary P.negate {-# INLINE negate #-} -instance Reifies p Integer => NA.Abelian (F p) +instance IsPrimeChar p => NA.Abelian (F p) -instance Reifies p Integer => NA.Semiring (F p) +instance IsPrimeChar p => NA.Semiring (F p) -instance Reifies p Integer => NA.Rig (F p) where +instance IsPrimeChar p => NA.Rig (F p) where fromNatural = modNat . P.fromIntegral {-# INLINE fromNatural #-} -instance Reifies p Integer => NA.Ring (F p) where +instance IsPrimeChar p => NA.Ring (F p) where fromInteger = modNat {-# INLINE fromInteger #-} -instance Reifies p Integer => NA.DecidableZero (F p) where - isZero (F p) = p == 0 +instance IsPrimeChar p => NA.DecidableZero (F p) where + isZero = unwrapF (== 0) -instance Reifies p Integer => NA.Unital (F p) where - one = F 1 +instance IsPrimeChar p => NA.Unital (F p) where + one = wrapF 1 {-# INLINE one #-} pow = pows {-# INLINE pow #-} -instance Reifies p Integer => DecidableUnits (F p) where - isUnit (F n) = n /= 0 +instance IsPrimeChar p => DecidableUnits (F p) where + isUnit = unwrapF (/= 0) {-# INLINE isUnit #-} - recipUnit n@(F k) = - let p = fromIntegral $ reflect n - (u,_,r) = head $ euclid p k - in if u == 1 then Just $ modNat $ fromInteger $ r `rem` p else Nothing + recipUnit = unwrapF $ \k -> + let p = WrapIntegral $ fromInteger $ charInfo @p Proxy + (u,_,r) = head $ euclid p (WrapIntegral k) + in if u == 1 + then Just $ wrapF $ fromIntegral $ unwrapIntegral $ r `rem` p else Nothing {-# INLINE recipUnit #-} -instance (Reifies p Integer) => DecidableAssociates (F p) where +instance (IsPrimeChar p) => DecidableAssociates (F p) where isAssociate p n = (isZero p && isZero n) || (not (isZero p) && not (isZero n)) {-# INLINE isAssociate #-} -instance (Reifies p Integer) => UnitNormalForm (F p) -instance (Reifies p Integer) => IntegralDomain (F p) -instance (Reifies p Integer) => GCDDomain (F p) -instance (Reifies p Integer) => UFD (F p) -instance (Reifies p Integer) => PID (F p) -instance (Reifies p Integer) => ZeroProductSemiring (F p) -instance (Reifies p Integer) => Euclidean (F p) +instance (IsPrimeChar p) => UnitNormalForm (F p) +instance (IsPrimeChar p) => IntegralDomain (F p) +instance (IsPrimeChar p) => GCDDomain (F p) +instance (IsPrimeChar p) => UFD (F p) +instance (IsPrimeChar p) => PID (F p) +instance (IsPrimeChar p) => ZeroProductSemiring (F p) +instance (IsPrimeChar p) => Euclidean (F p) -instance Reifies p Integer => Division (F p) where +instance IsPrimeChar p => Division (F p) where recip = fromMaybe (error "recip: not unit") . recipUnit {-# INLINE recip #-} a / b = a * recip b @@ -187,7 +303,7 @@ instance Reifies p Integer => Division (F p) where (^) = pows {-# INLINE (^) #-} -instance Reifies p Integer => P.Fractional (F p) where +instance IsPrimeChar p => P.Fractional (F p) where (/) = C.coerce ((P./) :: WrapAlgebra (F p) -> WrapAlgebra (F p) -> WrapAlgebra (F p)) {-# INLINE (/) #-} @@ -198,30 +314,30 @@ instance Reifies p Integer => P.Fractional (F p) where recip = C.coerce (P.recip :: WrapAlgebra (F p) -> WrapAlgebra (F p)) {-# INLINE recip #-} -instance Reifies p Integer => NA.Commutative (F p) +instance IsPrimeChar p => NA.Commutative (F p) -instance Reifies p Integer => NA.Characteristic (F p) where +instance IsPrimeChar p => NA.Characteristic (F p) where char _ = fromIntegral $ reflect (Proxy :: Proxy p) {-# INLINE char #-} -instance Reifies (p :: k) Integer => Show (F p) where - showsPrec d n@(F p) = showsPrec d (p `rem` reflect n) +instance IsPrimeChar p => Show (F p) where + showsPrec d = unwrapF $ showsPrec d -instance Reifies (p :: k) Integer => PrettyCoeff (F p) where - showsCoeff d (F p) - | p == 0 = Vanished - | p == 1 = OneCoeff - | otherwise = Positive $ showsPrec d p +instance IsPrimeChar p => PrettyCoeff (F p) where + showsCoeff d = unwrapF $ \p -> + if | p == 0 -> Vanished + | p == 1 -> OneCoeff + | otherwise -> Positive $ showsPrec d p -instance Reifies p P.Integer => FiniteField (F p) where +instance IsPrimeChar p => FiniteField (F p) where power _ = 1 {-# INLINE power #-} elements p = map modNat [0.. fromIntegral (char p) - 1] {-# INLINE elements #-} -instance Reifies p Integer => Random (F p) where +instance IsPrimeChar p => Random (F p) where random = runRand $ uniform (elements Proxy) {-# INLINE random #-} randomR (a, b) = runRand $ uniform $ map modNat [naturalRepr a..naturalRepr b] diff --git a/halg-galois-fields/src/Algebra/Field/Galois.hs b/halg-galois-fields/src/Algebra/Field/Galois.hs index 753fad2f..cab9896f 100644 --- a/halg-galois-fields/src/Algebra/Field/Galois.hs +++ b/halg-galois-fields/src/Algebra/Field/Galois.hs @@ -3,12 +3,15 @@ {-# LANGUAGE ParallelListComp, PolyKinds, QuasiQuotes, RankNTypes #-} {-# LANGUAGE ScopedTypeVariables, StandaloneDeriving, TypeApplications #-} {-# LANGUAGE TypeFamilies, TypeOperators, UndecidableInstances #-} -module Algebra.Field.Galois (GF'(), IsGF', modPoly, modVec, - withIrreducible, linearRepGF, linearRepGF', - reifyGF', generateIrreducible, - withGF', GF, ConwayPolynomial(..), - Conway, primitive, primitive', conway, - conwayFile, addConwayPolynomials) where +{-# LANGUAGE UndecidableSuperClasses #-} +module Algebra.Field.Galois + ( GF'(), IsGF', modPoly, modVec, + withIrreducible, linearRepGF, linearRepGF', + reifyGF', generateIrreducible, + withGF', GF, ConwayPolynomial(..), + Conway, primitive, primitive', conway, + conwayFile, addConwayPolynomials + ) where import Algebra.Field.Galois.Conway import Algebra.Field.Prime import Algebra.Internal @@ -39,7 +42,7 @@ import qualified Prelude as P -- | Galois field of order @p^n@. -- @f@ stands for the irreducible polynomial over @F_p@ of degree @n@. newtype GF' p (n :: TL.Nat) (f :: Type) = GF' { runGF' :: Sized n (F p) } -deriving instance Reifies p Integer => Eq (GF' p n f) +deriving instance IsPrimeChar p => Eq (GF' p n f) -- | Galois Field of order @p^n@. This uses conway polynomials -- as canonical minimal polynomial and it should be known at @@ -47,20 +50,20 @@ deriving instance Reifies p Integer => Eq (GF' p n f) -- instances should be defined to use field operations). type GF (p :: TL.Nat) n = GF' p n (Conway p n) -modPoly :: forall p n f. (KnownNat n, Reifies p Integer) => Unipol (F p) -> GF' p n f +modPoly :: forall p n f. (KnownNat n, IsPrimeChar p) => Unipol (F p) -> GF' p n f modPoly = GF' . polyToVec modVec :: Sized n (F p) -> GF' p n f modVec = GF' -instance (Reifies p Integer, Show (F p)) => Show (GF' p n f) where +instance (IsPrimeChar p, Show (F p)) => Show (GF' p n f) where showsPrec d (GF' (v :< vs)) = if F.all isZero vs then showsPrec d v else showChar '<' . showString (showPolynomialWith (singleton "ξ") 0 $ vecToPoly $ v :< vs) . showChar '>' showsPrec _ _ = showString "0" -instance (Reifies p Integer, Show (F p)) => PrettyCoeff (GF' p n f) +instance (IsPrimeChar p, Show (F p)) => PrettyCoeff (GF' p n f) varX :: CoeffRing r => Unipol r varX = var [od|0|] @@ -79,97 +82,97 @@ polyToVec f = | i <- [0..fromIntegral (fromSing (sing :: SNat n)) P.- 1] ] -instance Reifies p Integer => Additive (GF' p n f) where +instance IsPrimeChar p => Additive (GF' p n f) where GF' v + GF' u = GF' $ SV.zipWithSame (+) v u -instance (Reifies p Integer, KnownNat n) => Monoidal (GF' p n f) where +instance (IsPrimeChar p, KnownNat n) => Monoidal (GF' p n f) where zero = GF' $ SV.replicate' zero -instance Reifies p Integer => LeftModule Natural (GF' p n f) where +instance IsPrimeChar p => LeftModule Natural (GF' p n f) where n .* GF' v = GF' $ SV.map (n .*) v -instance Reifies p Integer => RightModule Natural (GF' p n f) where +instance IsPrimeChar p => RightModule Natural (GF' p n f) where GF' v *. n = GF' $ SV.map (*. n) v -instance Reifies p Integer => LeftModule Integer (GF' p n f) where +instance IsPrimeChar p => LeftModule Integer (GF' p n f) where n .* GF' v = GF' $ SV.map (n .*) v -instance Reifies p Integer => RightModule Integer (GF' p n f) where +instance IsPrimeChar p => RightModule Integer (GF' p n f) where GF' v *. n = GF' $ SV.map (*. n) v -instance (KnownNat n, Reifies p Integer) => Group (GF' p n f) where +instance (KnownNat n, IsPrimeChar p) => Group (GF' p n f) where negate (GF' v) = GF' $ SV.map negate v GF' u - GF' v = GF' $ SV.zipWithSame (-) u v -instance (Reifies p Integer) => Abelian (GF' p n f) +instance (IsPrimeChar p) => Abelian (GF' p n f) -instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) +instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Multiplicative (GF' p n f) where GF' u * GF' v = let t = (vecToPoly u * vecToPoly v) `rem` reflect (Proxy :: Proxy f) in GF' $ polyToVec t -instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Unital (GF' p n f) where +instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Unital (GF' p n f) where one = case zeroOrSucc (sing :: SNat n) of IsZero -> GF' NilL IsSucc k -> withKnownNat k $ GF' $ one :< SV.replicate' zero -instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Semiring (GF' p n f) +instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Semiring (GF' p n f) -instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Rig (GF' p n f) where +instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Rig (GF' p n f) where fromNatural n = case zeroOrSucc (sing :: SNat n) of IsZero -> GF' SV.empty IsSucc k -> withKnownNat k $ GF' $ fromNatural n :< SV.replicate' zero -instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Commutative (GF' p n f) +instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Commutative (GF' p n f) -instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => Ring (GF' p n f) where +instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Ring (GF' p n f) where fromInteger n = case zeroOrSucc (sing :: SNat n) of IsZero -> GF' NilL IsSucc k -> withKnownNat k $ GF' $ fromInteger n :< SV.replicate' zero -instance (KnownNat n, Reifies p Integer) => DecidableZero (GF' p n f) where +instance (KnownNat n, IsPrimeChar p) => DecidableZero (GF' p n f) where isZero (GF' sv) = F.all isZero sv -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) => DecidableUnits (GF' p n f) where +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => DecidableUnits (GF' p n f) where isUnit (GF' sv) = not $ F.all isZero sv recipUnit a | isZero a = Nothing | otherwise = Just $ recip a -instance (Reifies p Integer, Reifies f (Unipol (F p)), KnownNat n) +instance (IsPrimeChar p, Reifies f (Unipol (F p)), KnownNat n) => Characteristic (GF' p n f) where char _ = char (Proxy :: Proxy (F p)) -instance (Reifies p Integer, Reifies f (Unipol (F p)), KnownNat n) +instance (IsPrimeChar p, Reifies f (Unipol (F p)), KnownNat n) => Division (GF' p n f) where recip f = let p = reflect (Proxy :: Proxy f) (_,_,r) = P.head $ euclid p $ vecToPoly $ runGF' f in GF' $ polyToVec $ r `rem` p -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => DecidableAssociates (GF' p n f) where isAssociate p n = (isZero p && isZero n) || (not (isZero p) && not (isZero n)) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => ZeroProductSemiring (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => UnitNormalForm (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => IntegralDomain (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => GCDDomain (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => UFD (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => PID (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => Euclidean (GF' p n f) -instance (Reifies p Integer, Reifies f (Unipol (F p)), KnownNat n) => P.Num (GF' p n f) where +instance (IsPrimeChar p, Reifies f (Unipol (F p)), KnownNat n) => P.Num (GF' p n f) where (+) = (NA.+) (-) = (NA.-) negate = NA.negate @@ -178,7 +181,7 @@ instance (Reifies p Integer, Reifies f (Unipol (F p)), KnownNat n) => P.Num (GF' abs = error "not defined" signum = error "not defined" -instance (Reifies p Integer, Reifies f (Unipol (F p)), KnownNat n) => P.Fractional (GF' p n f) where +instance (IsPrimeChar p, Reifies f (Unipol (F p)), KnownNat n) => P.Fractional (GF' p n f) where fromRational u = fromInteger (Rat.numerator u) / fromInteger (Rat.denominator u) (/) = (/) recip = recip @@ -202,24 +205,25 @@ withIrreducible r f = withKnownNat sn $ reify r (f. proxyGF' (Proxy :: Proxy (F n)) sn) -reifyGF' :: MonadRandom m => Natural -> Natural - -> (forall (p :: TL.Nat) (f :: Type) (n :: TL.Nat) . (Reifies p Integer, Reifies f (Unipol (F p))) - => Proxy (GF' p n f) -> a) - -> m a +reifyGF' + :: MonadRandom m => Natural -> Natural + -> (forall (p :: TL.Nat) (f :: Type) (n :: TL.Nat) . (IsPrimeChar p, Reifies f (Unipol (F p))) + => Proxy (GF' p n f) -> a) + -> m a reifyGF' p n f = reifyPrimeField (P.toInteger p) $ \pxy -> do mpol <- generateIrreducible pxy n case toSing (fromIntegral p) of SomeSing sp -> return $ withKnownNat sp $ withIrreducible mpol f -linearRepGF :: GF' p n f -> V.Vector (F p) +linearRepGF :: IsPrimeChar p => GF' p n f -> V.Vector (F p) linearRepGF = SV.unsized . runGF' -linearRepGF' :: GF' p n f -> V.Vector Integer +linearRepGF' :: IsPrimeChar p => GF' p n f -> V.Vector Integer linearRepGF' = V.map naturalRepr . linearRepGF withGF' :: MonadRandom m => Natural -> Natural - -> (forall (p :: TL.Nat) f (n :: TL.Nat) . (Reifies p Integer, Reifies f (Unipol (F p))) + -> (forall (p :: TL.Nat) f (n :: TL.Nat) . (IsPrimeChar p, Reifies f (Unipol (F p))) => GF' p n f) -> m (V.Vector Integer) withGF' p n f = reifyGF' p n $ V.map naturalRepr . linearRepGF . asProxyTypeOf f @@ -228,12 +232,10 @@ proxyGF' :: Proxy (F p) -> SNat n -> Proxy f -> Proxy (GF' p n f) proxyGF' _ _ Proxy = Proxy -- | Type-constraint synonym to work with Galois field. -class (KnownNat n, KnownNat p, Reifies f (Unipol (F p))) => IsGF' p n f -instance (KnownNat n, KnownNat p, Reifies f (Unipol (F p))) => IsGF' p n f +class (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => IsGF' p n f +instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => IsGF' p n f -instance (KnownNat n, IsGF' p n f) => ZeroProductSemiring (GF' p n f) - instance (KnownNat n, IsGF' p n f) => FiniteField (GF' p n f) where power _ = fromIntegral $ fromSing (sing :: SNat n) elements _ = From 7ee745bd414093852737773685ef6aa4315946bb Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Wed, 8 Jul 2020 21:46:29 +0900 Subject: [PATCH 03/62] SPECIALISE pragmas --- halg-core/src/Algebra/Field/Prime.hs | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 0682ae1d..b8291f9a 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -173,6 +173,8 @@ proxyF :: Proxy (a :: k) -> Proxy (F a) proxyF Proxy = Proxy instance IsPrimeChar p => Eq (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => Eq (F p) #-} (==) = unwrapBinF (==) instance IsPrimeChar p => Normed (F p) where @@ -181,6 +183,8 @@ instance IsPrimeChar p => Normed (F p) where liftNorm = modNat instance IsPrimeChar p => P.Num (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => P.Num (F p) #-} fromInteger = fromInteger' {-# INLINE fromInteger #-} @@ -202,6 +206,7 @@ instance IsPrimeChar p => P.Num (F p) where _ -> 1 pows :: forall p a1. (P.Integral a1, IsPrimeChar p) => F p -> a1 -> F p +{-# INLINE pows #-} pows = flip $ \n -> liftFUnary $ \a -> unwrapIntegral $ modPow @@ -209,12 +214,16 @@ pows = flip $ \n -> liftFUnary $ \a -> (WrapIntegral $ fromInteger $ reflect $ Proxy @p) (toInteger n) instance IsPrimeChar p => NA.Additive (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => Additive (F p) #-} (+) = liftBinF (P.+) {-# INLINE (+) #-} sinnum1p n = liftFUnary $ \k -> (1 P.+ P.fromIntegral n) P.* k {-# INLINE sinnum1p #-} instance IsPrimeChar p => NA.Multiplicative (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => Multiplicative (F p) #-} (*) = liftBinF (P.*) {-# INLINE (*) #-} @@ -222,28 +231,40 @@ instance IsPrimeChar p => NA.Multiplicative (F p) where {-# INLINE pow1p #-} instance IsPrimeChar p => NA.Monoidal (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => Monoidal (F p) #-} zero = wrapF 0 {-# INLINE zero #-} sinnum n = liftFUnary $ \k -> P.fromIntegral n P.* k {-# INLINE sinnum #-} instance IsPrimeChar p => NA.LeftModule Natural (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => LeftModule Natural (F p) #-} (.*) n = liftFUnary $ \p -> fromIntegral n P.* p {-# INLINE (.*) #-} instance IsPrimeChar p => NA.RightModule Natural (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => RightModule Natural (F p) #-} (*.) = flip (.*) {-# INLINE (*.) #-} instance IsPrimeChar p => NA.LeftModule Integer (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => LeftModule Integer (F p) #-} (.*) n = liftFUnary $ \p -> fromIntegral n P.* p {-# INLINE (.*) #-} instance IsPrimeChar p => NA.RightModule Integer (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => RightModule Integer (F p) #-} (*.) = flip (.*) {-# INLINE (*.) #-} instance IsPrimeChar p => NA.Group (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => Group (F p) #-} (-) = liftBinF (P.-) {-# INLINE (-) #-} @@ -255,23 +276,33 @@ instance IsPrimeChar p => NA.Abelian (F p) instance IsPrimeChar p => NA.Semiring (F p) instance IsPrimeChar p => NA.Rig (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => Rig (F p) #-} fromNatural = modNat . P.fromIntegral {-# INLINE fromNatural #-} instance IsPrimeChar p => NA.Ring (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => Ring (F p) #-} fromInteger = modNat {-# INLINE fromInteger #-} instance IsPrimeChar p => NA.DecidableZero (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => DecidableZero (F p) #-} isZero = unwrapF (== 0) instance IsPrimeChar p => NA.Unital (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => Unital (F p) #-} one = wrapF 1 {-# INLINE one #-} pow = pows {-# INLINE pow #-} instance IsPrimeChar p => DecidableUnits (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => DecidableUnits (F p) #-} isUnit = unwrapF (/= 0) {-# INLINE isUnit #-} @@ -283,6 +314,8 @@ instance IsPrimeChar p => DecidableUnits (F p) where {-# INLINE recipUnit #-} instance (IsPrimeChar p) => DecidableAssociates (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => DecidableAssociates (F p) #-} isAssociate p n = (isZero p && isZero n) || (not (isZero p) && not (isZero n)) {-# INLINE isAssociate #-} @@ -296,6 +329,8 @@ instance (IsPrimeChar p) => ZeroProductSemiring (F p) instance (IsPrimeChar p) => Euclidean (F p) instance IsPrimeChar p => Division (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + => Division (F p) #-} recip = fromMaybe (error "recip: not unit") . recipUnit {-# INLINE recip #-} a / b = a * recip b @@ -304,6 +339,8 @@ instance IsPrimeChar p => Division (F p) where {-# INLINE (^) #-} instance IsPrimeChar p => P.Fractional (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'True) + => P.Fractional (F p) #-} (/) = C.coerce ((P./) :: WrapAlgebra (F p) -> WrapAlgebra (F p) -> WrapAlgebra (F p)) {-# INLINE (/) #-} From e370be02012d79d712308dd94660e94f02217c20 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Wed, 8 Jul 2020 21:59:07 +0900 Subject: [PATCH 04/62] INLINing --- halg-core/src/Algebra/Field/Prime.hs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index b8291f9a..0d217a6b 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -121,15 +121,19 @@ liftBinF f = unwrapBinF $ \x y -> wrapF $ fromIntegral $ f x y instance {-# OVERLAPPING #-} HasPrimeField Nat where type CharInfo n = KnownNat n + {-# INLINE charInfo_ #-} charInfo_ = fromIntegral . natVal + {-# INLINE liftFUnary_ #-} liftFUnary_ f = \(F i :: F p) -> case sing @WORD_MAX_BOUND %<= sing @p of STrue -> F $ f i SFalse -> F $ f i + {-# INLINE unwrapF #-} unwrapF f = \(F i :: F p) -> case sing @WORD_MAX_BOUND %<= sing @p of STrue -> f i SFalse -> f i + {-# INLINE wrapF_ #-} wrapF_ s = (case sing @WORD_MAX_BOUND %<= sing @p of STrue -> F s From c93e53ea64969e3ce451309196b2aaa28f680a75 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Wed, 8 Jul 2020 23:48:57 +0900 Subject: [PATCH 05/62] Various tests for Prime Fields (failing for inspection test) --- halg-core-test/package.yaml | 22 ++++ .../src/Algebra/Field/Prime/Test.hs | 11 +- .../test/Algebra/Field/PrimeSpec.hs | 105 ++++++++++++++++++ halg-core-test/test/Spec.hs | 1 + halg-core/src/Algebra/Field/Prime.hs | 4 +- halg-core/test/Spec.hs | 2 - hie.yaml | 2 + 7 files changed, 140 insertions(+), 7 deletions(-) create mode 100644 halg-core-test/test/Algebra/Field/PrimeSpec.hs create mode 100644 halg-core-test/test/Spec.hs delete mode 100644 halg-core/test/Spec.hs diff --git a/halg-core-test/package.yaml b/halg-core-test/package.yaml index f52bbddd..ddaf9b79 100644 --- a/halg-core-test/package.yaml +++ b/halg-core-test/package.yaml @@ -37,3 +37,25 @@ dependencies: library: source-dirs: src ghc-options: -Wall -Wno-orphans + + +tests: + halg-core-specs: + build-tools: + - hspec-discover + ghc-options: + - -Wall + - -threaded + - -rtsopts + - -with-rtsopts=-N + - -O2 + main: Spec.hs + source-dirs: test + dependencies: + - halg-core + - halg-core-test + - singletons + - QuickCheck + - arithmoi + - hspec + - inspection-testing diff --git a/halg-core-test/src/Algebra/Field/Prime/Test.hs b/halg-core-test/src/Algebra/Field/Prime/Test.hs index 60e85fcd..9374c0a3 100644 --- a/halg-core-test/src/Algebra/Field/Prime/Test.hs +++ b/halg-core-test/src/Algebra/Field/Prime/Test.hs @@ -4,13 +4,16 @@ module Algebra.Field.Prime.Test where import Algebra.Field.Finite.Test -import Algebra.Field.Prime (F, IsPrimeChar) -import Prelude (Maybe (..), Monad) -import Test.QuickCheck (Arbitrary (..)) +import Algebra.Field.Prime (F, IsPrimeChar, modNat) +import Data.Proxy +import Data.Reflection +import Prelude (Maybe (..), Monad, fromIntegral, (-), (<$>)) +import Test.QuickCheck (Arbitrary (..), resize) import Test.SmallCheck.Series (Serial (..)) instance IsPrimeChar p => Arbitrary (F p) where - arbitrary = arbitraryFiniteField (Nothing :: Maybe (F p)) + arbitrary = modNat <$> + resize (fromIntegral (reflect (Proxy :: Proxy p)) - 1) arbitrary instance (Monad m, IsPrimeChar p) => Serial m (F p) where series = seriesFiniteField (Nothing :: Maybe (F p)) diff --git a/halg-core-test/test/Algebra/Field/PrimeSpec.hs b/halg-core-test/test/Algebra/Field/PrimeSpec.hs new file mode 100644 index 00000000..bcfbe876 --- /dev/null +++ b/halg-core-test/test/Algebra/Field/PrimeSpec.hs @@ -0,0 +1,105 @@ +{-# LANGUAGE DataKinds, DerivingStrategies, GADTs #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, KindSignatures, NoImplicitPrelude #-} +{-# LANGUAGE PolyKinds, RankNTypes, ScopedTypeVariables, TemplateHaskell #-} +{-# LANGUAGE TypeApplications #-} +{-# OPTIONS_GHC -Wno-orphans #-} +{-# OPTIONS_GHC -dsuppress-idinfo -dsuppress-coercions + -dsuppress-type-applications + -dsuppress-module-prefixes -dsuppress-type-signatures + -dsuppress-uniques + #-} +module Algebra.Field.PrimeSpec where +import Algebra.Field.Finite.Test () +import Algebra.Field.Prime +import Algebra.Field.Prime.Test () +import AlgebraicPrelude +import qualified AlgebraicPrelude as NA +import Data.Proxy (Proxy (..)) +import Data.Singletons.Prelude +import GHC.TypeLits (Nat) +import Math.NumberTheory.Primes +import qualified Prelude as P +import Test.Hspec +import Test.Hspec.QuickCheck +import Test.Inspection hiding (Property, property, (===)) +import qualified Test.Inspection as IT +import Test.QuickCheck hiding (elements) +import qualified Test.QuickCheck as QC +import Unsafe.Coerce (unsafeCoerce) + +bigEnoughPrime :: Prime Integer +bigEnoughPrime = precPrime $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int + +n102F59 :: F 59 +n102F59 = 102 + +n102F59Manual :: F 59 +n102F59Manual = unsafeCoerce (102 `mod` 59 :: Int) + +f59AddPrelude :: F 59 -> F 59 -> F 59 +f59AddPrelude = (P.+) + +f59AddAlgebra :: F 59 -> F 59 -> F 59 +f59AddAlgebra = (NA.+) + +f59AddManual :: F 59 -> F 59 -> F 59 +f59AddManual = unsafeCoerce $ \(l :: Int) (r :: Int) -> + (l + r) `mod` 59 + +checkInspection + :: IT.Result -> Expectation +checkInspection IT.Success{} = pure () +checkInspection (IT.Failure msg) = + fail msg + +spec :: Spec +spec = do + describe "F p" $ do + prop "is a field (for small primes)" $ \(SmallPrime p) -> + tabulate "p" [show p] $ + reifyPrimeField p $ property . isField + prop "is a field (for big primes)" $ \(BigPrime p) -> + tabulate "p" [show p] $ + reifyPrimeField p $ property . isField + describe "optimisation for small primes (F 59)" $ do + it "literal doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'n102F59 `doesNotUse` 'SLT) + describe "(Prelude.+)" $ do + it "doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'f59AddPrelude `doesNotUse` 'SLT) + it "has the same core as \a b -> (a + b) `mod` 59" + $ checkInspection $(inspectTest $ 'f59AddPrelude IT.=== 'f59AddManual) + describe "(NA.+)" $ do + it "doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'SLT) + it "has the same core as \a b -> (a + b) `mod` 59" + $ checkInspection $(inspectTest $ 'f59AddAlgebra IT.=== 'f59AddManual) + +newtype SmallPrime = SmallPrime { runSmallPrime :: Integer } + deriving newtype (Show) + +instance Arbitrary SmallPrime where + arbitrary = SmallPrime . unPrime + <$> QC.elements (take 1000 primes) + +newtype BigPrime = BigPrime { runBigPrime :: Integer } + deriving newtype (Show) + +instance Arbitrary BigPrime where + arbitrary = BigPrime . unPrime + <$> QC.elements (take 1000 [bigEnoughPrime ..]) + +isField :: IsPrimeChar (p :: Nat) => Proxy (F p) -> F p -> F p -> F p -> Property +isField _ e f g = + 1 * e === e .&&. e * 1 === e .&&. e + 0 === e + .&&. (0 + e === e) .&&. (e - e === 0) + .&&. (e /= 0 ==> e * recip e === 1 .&&. recip e * e === 1) + .&&. e + f === f + e .&&. e * f === f * e + .&&. e * (f * g) === (e * f) * g + .&&. e + (f + g) === (e + f) + g + .&&. e * (f + g) === e*f + e*g + +instance Testable IT.Result where + property IT.Success{} = property True + property (IT.Failure msg) = error $ "Inspection failure: " ++ msg diff --git a/halg-core-test/test/Spec.hs b/halg-core-test/test/Spec.hs new file mode 100644 index 00000000..a824f8c3 --- /dev/null +++ b/halg-core-test/test/Spec.hs @@ -0,0 +1 @@ +{-# OPTIONS_GHC -F -pgmF hspec-discover #-} diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 0d217a6b..6b4e0c0e 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -12,7 +12,9 @@ module Algebra.Field.Prime modNat, modNat', modRat, modRat', FiniteField(..), order, -- * Auxiliary interfaces - HasPrimeField(..) + HasPrimeField(..), + -- ** Internals + wrapF, liftFUnary, liftBinF ) where import Algebra.Arithmetic (modPow) import Algebra.Field.Finite diff --git a/halg-core/test/Spec.hs b/halg-core/test/Spec.hs deleted file mode 100644 index cd4753fc..00000000 --- a/halg-core/test/Spec.hs +++ /dev/null @@ -1,2 +0,0 @@ -main :: IO () -main = putStrLn "Test suite not yet implemented" diff --git a/hie.yaml b/hie.yaml index d9c33df8..5f31174a 100644 --- a/hie.yaml +++ b/hie.yaml @@ -41,6 +41,8 @@ cradle: - path: "halg-core/src" component: "halg-core:lib" + - path: "halg-core-test/test" + component: "halg-core-test:test:halg-core-specs" - path: "halg-heaps/src" component: "halg-heaps:lib" From cef0fbda30389832dad0101b0e0fb1c961932db9 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 00:38:19 +0900 Subject: [PATCH 06/62] More robust inspection test --- halg-core-test/package.yaml | 2 + .../test/Algebra/Field/PrimeSpec.hs | 107 +++++++++++++++--- 2 files changed, 93 insertions(+), 16 deletions(-) diff --git a/halg-core-test/package.yaml b/halg-core-test/package.yaml index ddaf9b79..d0b09306 100644 --- a/halg-core-test/package.yaml +++ b/halg-core-test/package.yaml @@ -58,4 +58,6 @@ tests: - QuickCheck - arithmoi - hspec + - integer-gmp + - template-haskell - inspection-testing diff --git a/halg-core-test/test/Algebra/Field/PrimeSpec.hs b/halg-core-test/test/Algebra/Field/PrimeSpec.hs index bcfbe876..2f3ec484 100644 --- a/halg-core-test/test/Algebra/Field/PrimeSpec.hs +++ b/halg-core-test/test/Algebra/Field/PrimeSpec.hs @@ -1,8 +1,8 @@ {-# LANGUAGE DataKinds, DerivingStrategies, GADTs #-} -{-# LANGUAGE GeneralizedNewtypeDeriving, KindSignatures, NoImplicitPrelude #-} -{-# LANGUAGE PolyKinds, RankNTypes, ScopedTypeVariables, TemplateHaskell #-} -{-# LANGUAGE TypeApplications #-} -{-# OPTIONS_GHC -Wno-orphans #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, KindSignatures, MagicHash #-} +{-# LANGUAGE NoImplicitPrelude, PolyKinds, RankNTypes, ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell, TypeApplications #-} +{-# OPTIONS_GHC -Wno-orphans -O2 #-} {-# OPTIONS_GHC -dsuppress-idinfo -dsuppress-coercions -dsuppress-type-applications -dsuppress-module-prefixes -dsuppress-type-signatures @@ -16,7 +16,10 @@ import AlgebraicPrelude import qualified AlgebraicPrelude as NA import Data.Proxy (Proxy (..)) import Data.Singletons.Prelude -import GHC.TypeLits (Nat) +import GHC.Base (modInt#) +import GHC.Integer +import GHC.TypeLits (Nat, natVal) +import Language.Haskell.TH import Math.NumberTheory.Primes import qualified Prelude as P import Test.Hspec @@ -31,6 +34,10 @@ bigEnoughPrime :: Prime Integer bigEnoughPrime = precPrime $ floor @Double $ sqrt $ fromIntegral $ maxBound @Int +type LargeP = $(litT $ numTyLit $ unPrime + $ nextPrime $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int) + n102F59 :: F 59 n102F59 = 102 @@ -43,52 +50,120 @@ f59AddPrelude = (P.+) f59AddAlgebra :: F 59 -> F 59 -> F 59 f59AddAlgebra = (NA.+) -f59AddManual :: F 59 -> F 59 -> F 59 -f59AddManual = unsafeCoerce $ \(l :: Int) (r :: Int) -> +f59AddManual :: Int -> Int -> Int +f59AddManual = \l r -> (l + r) `mod` 59 +fLargeAddPrelude :: F LargeP -> F LargeP -> F LargeP +fLargeAddPrelude = (P.+) + +fLargeAddAlgebra :: F LargeP -> F LargeP -> F LargeP +fLargeAddAlgebra = (NA.+) + +fLargeAddManual :: Integer -> Integer -> Integer +fLargeAddManual = \ l r -> + (l + r) `mod` natVal @LargeP Proxy + checkInspection :: IT.Result -> Expectation checkInspection IT.Success{} = pure () checkInspection (IT.Failure msg) = fail msg +n43 :: Int +n43 = 43 + +litLarge :: F LargeP +litLarge = $( + let p = unPrime $ nextPrime $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int + in litE $ integerL $ p*3 `div` 2 + ) + +litLargeAnswer :: Integer +litLargeAnswer = $( + let p = unPrime $ nextPrime $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int + in litE $ integerL $ (p*3 `div` 2) `mod` p + ) + spec :: Spec spec = do describe "F p" $ do prop "is a field (for small primes)" $ \(SmallPrime p) -> tabulate "p" [show p] $ reifyPrimeField p $ property . isField + prop "is a field (for small, but medium primes)" $ \(MediumPrime p) -> + tabulate "p" [show p] $ + reifyPrimeField p $ property . isField prop "is a field (for big primes)" $ \(BigPrime p) -> tabulate "p" [show p] $ reifyPrimeField p $ property . isField describe "optimisation for small primes (F 59)" $ do - it "literal doesn't contain type-natural comparison" - $ checkInspection $(inspectTest $ 'n102F59 `doesNotUse` 'SLT) + describe "literal" $ do + it "doesn't contain type-classes" + $ checkInspection $(inspectTest $ hasNoTypeClasses 'n102F59) + it "is an immediate value modulo casting" + $ checkInspection $(inspectTest $ 'n102F59 ==- 'n43) describe "(Prelude.+)" $ do - it "doesn't contain type-natural comparison" - $ checkInspection $(inspectTest $ 'f59AddPrelude `doesNotUse` 'SLT) - it "has the same core as \a b -> (a + b) `mod` 59" - $ checkInspection $(inspectTest $ 'f59AddPrelude IT.=== 'f59AddManual) + it "has the same core representation as (NA.+) modulo casting" $ + checkInspection $(inspectTest $ 'f59AddPrelude ==- 'f59AddAlgebra) describe "(NA.+)" $ do + it "doesn't contain type-classes" $ do + checkInspection $(inspectTest $ hasNoTypeClasses 'f59AddAlgebra) it "doesn't contain type-natural comparison" $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'SLT) + it "doesn't contain Integer type" $ + checkInspection $(inspectTest $ 'f59AddAlgebra `hasNoType` ''Integer) + it "doesn't contain modInteger operation" + $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'modInteger) it "has the same core as \a b -> (a + b) `mod` 59" - $ checkInspection $(inspectTest $ 'f59AddAlgebra IT.=== 'f59AddManual) + $ checkInspection $(inspectTest $ 'f59AddAlgebra ==- 'f59AddManual) + describe ("optimisation for big prime (F " ++ show (natVal @LargeP Proxy) ++ ")") $ do + describe "literal" $ do + it "doesn't contain type-classes" + $ checkInspection $(inspectTest $ hasNoTypeClasses 'litLarge) + it "is an immediate value modulo casting" + $ checkInspection $(inspectTest $ 'litLarge ==- 'litLargeAnswer) + describe "(Prelude.+)" $ do + it "has the same core representation as (NA.+) modulo casting" $ + checkInspection $(inspectTest $ 'fLargeAddPrelude ==- 'fLargeAddAlgebra) + describe "(NA.+)" $ do + it "doesn't contain type-classes" $ do + checkInspection $(inspectTest $ hasNoTypeClasses 'fLargeAddAlgebra) + it "doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `doesNotUse` 'SLT) + it "doesn't contain Integer type" $ + checkInspection $(inspectTest $ 'fLargeAddAlgebra `hasNoType` ''Int) + it "doesn't contain modInt# operation" + $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `doesNotUse` 'modInt#) + it "has the same core as \a b -> (a + b) `mod` p" + $ checkInspection $(inspectTest $ 'fLargeAddAlgebra ==- 'fLargeAddManual) newtype SmallPrime = SmallPrime { runSmallPrime :: Integer } deriving newtype (Show) instance Arbitrary SmallPrime where arbitrary = SmallPrime . unPrime - <$> QC.elements (take 1000 primes) + <$> QC.elements (take 10 primes) + +newtype MediumPrime = MediumPrime { runMediumPrime :: Integer } + deriving newtype (Show) + +instance Arbitrary MediumPrime where + arbitrary = MediumPrime . unPrime + <$> QC.elements + (take 10 [nextPrime + $ floor @Double $ sqrt + $ fromIntegral $ unPrime bigEnoughPrime + .. ]) newtype BigPrime = BigPrime { runBigPrime :: Integer } deriving newtype (Show) instance Arbitrary BigPrime where arbitrary = BigPrime . unPrime - <$> QC.elements (take 1000 [bigEnoughPrime ..]) + <$> QC.elements (take 10 [bigEnoughPrime ..]) isField :: IsPrimeChar (p :: Nat) => Proxy (F p) -> F p -> F p -> F p -> Property isField _ e f g = From 2e461e2e30e3669426fc8c7625a1587bdacddacc Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 00:39:19 +0900 Subject: [PATCH 07/62] Changes the type-level logic to determine the internal representation --- halg-core/src/Algebra/Field/Prime.hs | 63 ++++++++++--------- .../Algebra/Ring/Polynomial/FactoriseSpec.hs | 4 +- .../src/Algebra/Field/Galois.hs | 2 +- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 6b4e0c0e..2b8bb173 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -36,12 +36,14 @@ import Data.Singletons.Prelude import GHC.Read import GHC.TypeLits (KnownNat) import GHC.TypeNats (Nat, natVal) +import GHC.TypeNats (type (<=?)) import Language.Haskell.TH (litT, numTyLit) import Numeric.Algebra (char) import Numeric.Algebra (Natural) import qualified Numeric.Algebra as NA import Numeric.Semiring.ZeroProduct (ZeroProductSemiring) import qualified Prelude as P +import Unsafe.Coerce (unsafeCoerce) -- | Prime field of characteristic @p@. -- @p@ should be prime, and not statically checked. @@ -54,16 +56,16 @@ type WORD_MAX_BOUND = type F' (p :: k) = F_Aux k p type family F_Aux (k :: Type) (p :: k) where F_Aux Nat p = - F_Nat_Aux (WORD_MAX_BOUND <= p) + F_Nat_Aux (WORD_MAX_BOUND <=? p) F_Aux k p = Integer type family F_Nat_Aux (oob :: Bool) where F_Nat_Aux 'True = Integer F_Nat_Aux 'False = Int -instance {-# OVERLAPPING #-} KnownNat p => NFData (F p) where +instance {-# OVERLAPPING #-} SingI (WORD_MAX_BOUND <=? p) => NFData (F p) where {-# INLINE rnf #-} - rnf = case sing @WORD_MAX_BOUND %<= sing @p of + rnf = case sing @(WORD_MAX_BOUND <=? p) of STrue -> rnf . runF SFalse -> rnf .runF @@ -121,26 +123,26 @@ liftBinF {-# INLINE liftBinF #-} liftBinF f = unwrapBinF $ \x y -> wrapF $ fromIntegral $ f x y -instance {-# OVERLAPPING #-} HasPrimeField Nat where - type CharInfo n = KnownNat n +instance {-# OVERLAPPING #-} HasPrimeField Nat where + type CharInfo n = (KnownNat n, SingI (WORD_MAX_BOUND <=? n)) {-# INLINE charInfo_ #-} charInfo_ = fromIntegral . natVal {-# INLINE liftFUnary_ #-} liftFUnary_ f = \(F i :: F p) -> - case sing @WORD_MAX_BOUND %<= sing @p of + case sing @(WORD_MAX_BOUND <=? p) of STrue -> F $ f i SFalse -> F $ f i {-# INLINE unwrapF #-} unwrapF f = \(F i :: F p) -> - case sing @WORD_MAX_BOUND %<= sing @p of + case sing @(WORD_MAX_BOUND <=? p) of STrue -> f i SFalse -> f i {-# INLINE wrapF_ #-} wrapF_ s = - (case sing @WORD_MAX_BOUND %<= sing @p of + (case sing @(WORD_MAX_BOUND <=? p) of STrue -> F s SFalse -> F s) - :: forall p. KnownNat p => F (p :: Nat) + :: forall p. SingI (WORD_MAX_BOUND <=? p) => F (p :: Nat) instance HasPrimeField Type where type CharInfo n = Reifies n Integer @@ -167,7 +169,9 @@ modNat' _ i = wrapF $ reifyPrimeField :: Integer -> (forall p. IsPrimeChar (p :: Nat) => Proxy (F p) -> a) -> a -reifyPrimeField p f = reifyNat p (f . proxyF) +reifyPrimeField p f = reifyNat p $ \(_ :: Proxy p) -> + withSingI (unsafeCoerce $ sing @WORD_MAX_BOUND %<= sing @p :: Sing (WORD_MAX_BOUND <=? p)) + $ f $ Proxy @(F p) withPrimeField :: Integer -> (forall p. IsPrimeChar (p :: Nat) => F p) -> Integer withPrimeField p f = reifyPrimeField p $ unwrapF toInteger . asProxyTypeOf f @@ -175,11 +179,8 @@ withPrimeField p f = reifyPrimeField p $ unwrapF toInteger . asProxyTypeOf f naturalRepr :: IsPrimeChar p => F p -> Integer naturalRepr = unwrapF toInteger -proxyF :: Proxy (a :: k) -> Proxy (F a) -proxyF Proxy = Proxy - instance IsPrimeChar p => Eq (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Eq (F p) #-} (==) = unwrapBinF (==) @@ -189,7 +190,7 @@ instance IsPrimeChar p => Normed (F p) where liftNorm = modNat instance IsPrimeChar p => P.Num (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => P.Num (F p) #-} fromInteger = fromInteger' {-# INLINE fromInteger #-} @@ -220,7 +221,7 @@ pows = flip $ \n -> liftFUnary $ \a -> (WrapIntegral $ fromInteger $ reflect $ Proxy @p) (toInteger n) instance IsPrimeChar p => NA.Additive (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Additive (F p) #-} (+) = liftBinF (P.+) {-# INLINE (+) #-} @@ -228,7 +229,7 @@ instance IsPrimeChar p => NA.Additive (F p) where {-# INLINE sinnum1p #-} instance IsPrimeChar p => NA.Multiplicative (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Multiplicative (F p) #-} (*) = liftBinF (P.*) {-# INLINE (*) #-} @@ -237,7 +238,7 @@ instance IsPrimeChar p => NA.Multiplicative (F p) where {-# INLINE pow1p #-} instance IsPrimeChar p => NA.Monoidal (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Monoidal (F p) #-} zero = wrapF 0 {-# INLINE zero #-} @@ -245,31 +246,31 @@ instance IsPrimeChar p => NA.Monoidal (F p) where {-# INLINE sinnum #-} instance IsPrimeChar p => NA.LeftModule Natural (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => LeftModule Natural (F p) #-} (.*) n = liftFUnary $ \p -> fromIntegral n P.* p {-# INLINE (.*) #-} instance IsPrimeChar p => NA.RightModule Natural (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => RightModule Natural (F p) #-} (*.) = flip (.*) {-# INLINE (*.) #-} instance IsPrimeChar p => NA.LeftModule Integer (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => LeftModule Integer (F p) #-} (.*) n = liftFUnary $ \p -> fromIntegral n P.* p {-# INLINE (.*) #-} instance IsPrimeChar p => NA.RightModule Integer (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => RightModule Integer (F p) #-} (*.) = flip (.*) {-# INLINE (*.) #-} instance IsPrimeChar p => NA.Group (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Group (F p) #-} (-) = liftBinF (P.-) {-# INLINE (-) #-} @@ -282,24 +283,24 @@ instance IsPrimeChar p => NA.Abelian (F p) instance IsPrimeChar p => NA.Semiring (F p) instance IsPrimeChar p => NA.Rig (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Rig (F p) #-} fromNatural = modNat . P.fromIntegral {-# INLINE fromNatural #-} instance IsPrimeChar p => NA.Ring (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Ring (F p) #-} fromInteger = modNat {-# INLINE fromInteger #-} instance IsPrimeChar p => NA.DecidableZero (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => DecidableZero (F p) #-} isZero = unwrapF (== 0) instance IsPrimeChar p => NA.Unital (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Unital (F p) #-} one = wrapF 1 {-# INLINE one #-} @@ -307,7 +308,7 @@ instance IsPrimeChar p => NA.Unital (F p) where {-# INLINE pow #-} instance IsPrimeChar p => DecidableUnits (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => DecidableUnits (F p) #-} isUnit = unwrapF (/= 0) {-# INLINE isUnit #-} @@ -320,7 +321,7 @@ instance IsPrimeChar p => DecidableUnits (F p) where {-# INLINE recipUnit #-} instance (IsPrimeChar p) => DecidableAssociates (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => DecidableAssociates (F p) #-} isAssociate p n = (isZero p && isZero n) || (not (isZero p) && not (isZero n)) @@ -335,7 +336,7 @@ instance (IsPrimeChar p) => ZeroProductSemiring (F p) instance (IsPrimeChar p) => Euclidean (F p) instance IsPrimeChar p => Division (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'False) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Division (F p) #-} recip = fromMaybe (error "recip: not unit") . recipUnit {-# INLINE recip #-} @@ -345,7 +346,7 @@ instance IsPrimeChar p => Division (F p) where {-# INLINE (^) #-} instance IsPrimeChar p => P.Fractional (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <= p) ~ 'True) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'True) => P.Fractional (F p) #-} (/) = C.coerce ((P./) :: WrapAlgebra (F p) -> WrapAlgebra (F p) -> WrapAlgebra (F p)) {-# INLINE (/) #-} diff --git a/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs b/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs index 7752dcd6..2ca6d789 100644 --- a/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs +++ b/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs @@ -38,10 +38,10 @@ regressions = ξ :: GF 2 5 ξ = primitive -instance KnownNat n => Arbitrary (F n) where +instance IsPrimeChar n => Arbitrary (F n) where arbitrary = QC.elements $ Fin.elements $ Proxy @(F n) -instance (KnownNat p, KnownNat n, ConwayPolynomial p n) +instance (IsPrimeChar p, KnownNat n, ConwayPolynomial p n) => Arbitrary (GF p n) where arbitrary = QC.elements $ Fin.elements $ Proxy @(GF p n) diff --git a/halg-galois-fields/src/Algebra/Field/Galois.hs b/halg-galois-fields/src/Algebra/Field/Galois.hs index cab9896f..a96cc22d 100644 --- a/halg-galois-fields/src/Algebra/Field/Galois.hs +++ b/halg-galois-fields/src/Algebra/Field/Galois.hs @@ -195,7 +195,7 @@ generateIrreducible p n = let f = varX^n + sum [ injectCoeff c * (varX^i) | c <- cs | i <- [0..n P.- 1]] return f -withIrreducible :: forall p a. KnownNat p +withIrreducible :: forall p a. IsPrimeChar p => Unipol (F p) -> (forall f (n :: Nat). (Reifies f (Unipol (F p))) => Proxy (GF' p n f) -> a) -> a From 74e75a09eed49b75445bfb1d9566cfc612fb6ce9 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 00:51:53 +0900 Subject: [PATCH 08/62] Slightly more efficient factorisation --- halg-factor/src/Algebra/Ring/Polynomial/Factorise.hs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/halg-factor/src/Algebra/Ring/Polynomial/Factorise.hs b/halg-factor/src/Algebra/Ring/Polynomial/Factorise.hs index 2fba131c..34259226 100644 --- a/halg-factor/src/Algebra/Ring/Polynomial/Factorise.hs +++ b/halg-factor/src/Algebra/Ring/Polynomial/Factorise.hs @@ -26,7 +26,8 @@ import Control.Lens (both, ifoldl, (%~), (&)) import Control.Monad (guard, replicateM) import Control.Monad (when) import Control.Monad.Loops (iterateUntil, untilJust) -import Control.Monad.Random (MonadRandom, uniform) +import Control.Monad.Random (MonadRandom, getRandomR, + uniform) import Control.Monad.ST.Strict (ST, runST) import Control.Monad.Trans (lift) import Control.Monad.Trans.Loop (continue, foreach, while) @@ -87,7 +88,7 @@ equalDegreeSplitM f d | otherwise = do let q = fromIntegral $ order (Proxy :: Proxy k) els = elements (Proxy :: Proxy k) - e <- uniform [1..n P.- 1] + e <- getRandomR (1, n P.- 1) cs <- replicateM (fromIntegral e) $ uniform els let a = var 0 ^ fromIntegral e + sum (zipWith (*) (map injectCoeff cs) [var 0 ^ l | l <-[0..]]) From 1773506879b3750c418b402226adf5a5ff1f929c Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 17:08:01 +0900 Subject: [PATCH 09/62] Corrects precondition for F p --- halg-bridge-singular/src/Algebra/Bridge/Singular/Syntax.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halg-bridge-singular/src/Algebra/Bridge/Singular/Syntax.hs b/halg-bridge-singular/src/Algebra/Bridge/Singular/Syntax.hs index 7f28bef8..eef2ebbd 100644 --- a/halg-bridge-singular/src/Algebra/Bridge/Singular/Syntax.hs +++ b/halg-bridge-singular/src/Algebra/Bridge/Singular/Syntax.hs @@ -88,7 +88,7 @@ instance SingularCoeff Integer where coeffType _ = IntegerCoeff -instance KnownNat p => SingularCoeff (F p) where +instance IsPrimeChar p => SingularCoeff (F p) where parseSingularCoeff = rationalP coeffType = Char . char From 8cb711209f7fe4074022ec2478bd78e18ceaca6e Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 17:16:42 +0900 Subject: [PATCH 10/62] arithmoi version constraints --- halg-core-test/package.yaml | 2 +- halg-factor/package.yaml | 2 +- stack-804.yaml | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/halg-core-test/package.yaml b/halg-core-test/package.yaml index d0b09306..183025e5 100644 --- a/halg-core-test/package.yaml +++ b/halg-core-test/package.yaml @@ -56,7 +56,7 @@ tests: - halg-core-test - singletons - QuickCheck - - arithmoi + - arithmoi >= 0.9 - hspec - integer-gmp - template-haskell diff --git a/halg-factor/package.yaml b/halg-factor/package.yaml index 3bcb785e..637d1c6f 100644 --- a/halg-factor/package.yaml +++ b/halg-factor/package.yaml @@ -32,7 +32,7 @@ library: - MonadRandom - algebra - algebraic-prelude - - arithmoi + - arithmoi >= 0.9 - containers - control-monad-loop - dlist diff --git a/stack-804.yaml b/stack-804.yaml index d23f01a9..8d8b317a 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -23,6 +23,7 @@ extra-deps: - singletons-presburger-0.3.0.0 - sized-0.3.0.0 - type-natural-0.8.1.0 +- arithmoi-0.11.0.1 - unamb-0.2.7 - parser-combinators-1.1.0 -- megaparsec-7.0.5 \ No newline at end of file +- megaparsec-7.0.5 From e727b29da18ae82131a0a4882043e30ef1b943fe Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 17:27:27 +0900 Subject: [PATCH 11/62] Fixes 8.0.4 dependency --- stack-804.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stack-804.yaml b/stack-804.yaml index 8d8b317a..45e49c13 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -23,7 +23,9 @@ extra-deps: - singletons-presburger-0.3.0.0 - sized-0.3.0.0 - type-natural-0.8.1.0 -- arithmoi-0.11.0.1 +- arithmoi-0.9.0.0 - unamb-0.2.7 - parser-combinators-1.1.0 - megaparsec-7.0.5 +- exact-pi-0.5.0.1@sha256:55e343462be57d692dc6b5fd27d2f52c39052cb402ea03692e4dc460fa69a5d0,2121 +- semirings-0.5.3@sha256:4b0d243f88bb07c0673978a37b6b9fd16da44f15e8d552fb08795d9a88a3dc76,3791 From c1963c0ab2252625d0b7f68187597a0e446578d5 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 17:36:48 +0900 Subject: [PATCH 12/62] Removes unused constraint --- halg-core/src/Algebra/Field/Prime.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 2b8bb173..47a0d094 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -1,9 +1,8 @@ {-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving, LambdaCase, MultiParamTypeClasses #-} -{-# LANGUAGE MultiWayIf, PolyKinds, QuantifiedConstraints, RankNTypes #-} -{-# LANGUAGE ScopedTypeVariables, TemplateHaskell, TypeApplications #-} -{-# LANGUAGE TypeFamilies, TypeOperators, UndecidableInstances #-} -{-# LANGUAGE UndecidableSuperClasses #-} +{-# LANGUAGE MultiWayIf, PolyKinds, RankNTypes, ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell, TypeApplications, TypeFamilies #-} +{-# LANGUAGE TypeOperators, UndecidableInstances, UndecidableSuperClasses #-} {-# OPTIONS_GHC -fplugin Data.Singletons.TypeNats.Presburger #-} -- | Prime fields module Algebra.Field.Prime From de32505d4236afa8069fa2e9595863e20435fc42 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 18:07:05 +0900 Subject: [PATCH 13/62] Workarounds for 8.4 --- halg-core/src/Algebra/Field/Prime.hs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 47a0d094..489a1b08 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -64,7 +64,7 @@ type family F_Nat_Aux (oob :: Bool) where instance {-# OVERLAPPING #-} SingI (WORD_MAX_BOUND <=? p) => NFData (F p) where {-# INLINE rnf #-} - rnf = case sing @(WORD_MAX_BOUND <=? p) of + rnf = case sing :: Sing (WORD_MAX_BOUND <=? p) of STrue -> rnf . runF SFalse -> rnf .runF @@ -128,17 +128,17 @@ instance {-# OVERLAPPING #-} HasPrimeField Nat where charInfo_ = fromIntegral . natVal {-# INLINE liftFUnary_ #-} liftFUnary_ f = \(F i :: F p) -> - case sing @(WORD_MAX_BOUND <=? p) of + case sing :: Sing (WORD_MAX_BOUND <=? p) of STrue -> F $ f i SFalse -> F $ f i {-# INLINE unwrapF #-} unwrapF f = \(F i :: F p) -> - case sing @(WORD_MAX_BOUND <=? p) of + case sing :: Sing (WORD_MAX_BOUND <=? p) of STrue -> f i SFalse -> f i {-# INLINE wrapF_ #-} wrapF_ s = - (case sing @(WORD_MAX_BOUND <=? p) of + (case sing :: Sing (WORD_MAX_BOUND <=? p) of STrue -> F s SFalse -> F s) :: forall p. SingI (WORD_MAX_BOUND <=? p) => F (p :: Nat) @@ -169,7 +169,9 @@ reifyPrimeField :: Integer -> (forall p. IsPrimeChar (p :: Nat) => Proxy (F p) -> a) -> a reifyPrimeField p f = reifyNat p $ \(_ :: Proxy p) -> - withSingI (unsafeCoerce $ sing @WORD_MAX_BOUND %<= sing @p :: Sing (WORD_MAX_BOUND <=? p)) + withSingI (unsafeCoerce $ + (sing :: Sing WORD_MAX_BOUND) + %<= (sing :: Sing p) :: Sing (WORD_MAX_BOUND <=? p)) $ f $ Proxy @(F p) withPrimeField :: Integer -> (forall p. IsPrimeChar (p :: Nat) => F p) -> Integer From 564ffdb28f60b96fef9287f60877190e4832b2dd Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 18:12:21 +0900 Subject: [PATCH 14/62] Separates Optimisation-related tests to distinct module --- .../test/Algebra/Field/PrimeSpec.hs | 127 ++---------------- .../Algebra/Field/PrimeSpec/Optimisation.hs | 117 ++++++++++++++++ 2 files changed, 131 insertions(+), 113 deletions(-) create mode 100644 halg-core-test/test/Algebra/Field/PrimeSpec/Optimisation.hs diff --git a/halg-core-test/test/Algebra/Field/PrimeSpec.hs b/halg-core-test/test/Algebra/Field/PrimeSpec.hs index 2f3ec484..82c7ba0d 100644 --- a/halg-core-test/test/Algebra/Field/PrimeSpec.hs +++ b/halg-core-test/test/Algebra/Field/PrimeSpec.hs @@ -9,26 +9,20 @@ -dsuppress-uniques #-} module Algebra.Field.PrimeSpec where +import Algebra.Field.PrimeSpec.Optimisation + import Algebra.Field.Finite.Test () import Algebra.Field.Prime import Algebra.Field.Prime.Test () import AlgebraicPrelude -import qualified AlgebraicPrelude as NA import Data.Proxy (Proxy (..)) -import Data.Singletons.Prelude -import GHC.Base (modInt#) -import GHC.Integer -import GHC.TypeLits (Nat, natVal) +import GHC.TypeLits (Nat) import Language.Haskell.TH import Math.NumberTheory.Primes -import qualified Prelude as P import Test.Hspec import Test.Hspec.QuickCheck -import Test.Inspection hiding (Property, property, (===)) -import qualified Test.Inspection as IT import Test.QuickCheck hiding (elements) import qualified Test.QuickCheck as QC -import Unsafe.Coerce (unsafeCoerce) bigEnoughPrime :: Prime Integer bigEnoughPrime = precPrime $ floor @Double @@ -38,107 +32,18 @@ type LargeP = $(litT $ numTyLit $ unPrime $ nextPrime $ floor @Double $ sqrt $ fromIntegral $ maxBound @Int) -n102F59 :: F 59 -n102F59 = 102 - -n102F59Manual :: F 59 -n102F59Manual = unsafeCoerce (102 `mod` 59 :: Int) - -f59AddPrelude :: F 59 -> F 59 -> F 59 -f59AddPrelude = (P.+) - -f59AddAlgebra :: F 59 -> F 59 -> F 59 -f59AddAlgebra = (NA.+) - -f59AddManual :: Int -> Int -> Int -f59AddManual = \l r -> - (l + r) `mod` 59 - -fLargeAddPrelude :: F LargeP -> F LargeP -> F LargeP -fLargeAddPrelude = (P.+) - -fLargeAddAlgebra :: F LargeP -> F LargeP -> F LargeP -fLargeAddAlgebra = (NA.+) - -fLargeAddManual :: Integer -> Integer -> Integer -fLargeAddManual = \ l r -> - (l + r) `mod` natVal @LargeP Proxy - -checkInspection - :: IT.Result -> Expectation -checkInspection IT.Success{} = pure () -checkInspection (IT.Failure msg) = - fail msg - -n43 :: Int -n43 = 43 - -litLarge :: F LargeP -litLarge = $( - let p = unPrime $ nextPrime $ floor @Double - $ sqrt $ fromIntegral $ maxBound @Int - in litE $ integerL $ p*3 `div` 2 - ) - -litLargeAnswer :: Integer -litLargeAnswer = $( - let p = unPrime $ nextPrime $ floor @Double - $ sqrt $ fromIntegral $ maxBound @Int - in litE $ integerL $ (p*3 `div` 2) `mod` p - ) - spec :: Spec -spec = do - describe "F p" $ do - prop "is a field (for small primes)" $ \(SmallPrime p) -> - tabulate "p" [show p] $ - reifyPrimeField p $ property . isField - prop "is a field (for small, but medium primes)" $ \(MediumPrime p) -> - tabulate "p" [show p] $ - reifyPrimeField p $ property . isField - prop "is a field (for big primes)" $ \(BigPrime p) -> - tabulate "p" [show p] $ - reifyPrimeField p $ property . isField - describe "optimisation for small primes (F 59)" $ do - describe "literal" $ do - it "doesn't contain type-classes" - $ checkInspection $(inspectTest $ hasNoTypeClasses 'n102F59) - it "is an immediate value modulo casting" - $ checkInspection $(inspectTest $ 'n102F59 ==- 'n43) - describe "(Prelude.+)" $ do - it "has the same core representation as (NA.+) modulo casting" $ - checkInspection $(inspectTest $ 'f59AddPrelude ==- 'f59AddAlgebra) - describe "(NA.+)" $ do - it "doesn't contain type-classes" $ do - checkInspection $(inspectTest $ hasNoTypeClasses 'f59AddAlgebra) - it "doesn't contain type-natural comparison" - $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'SLT) - it "doesn't contain Integer type" $ - checkInspection $(inspectTest $ 'f59AddAlgebra `hasNoType` ''Integer) - it "doesn't contain modInteger operation" - $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'modInteger) - it "has the same core as \a b -> (a + b) `mod` 59" - $ checkInspection $(inspectTest $ 'f59AddAlgebra ==- 'f59AddManual) - describe ("optimisation for big prime (F " ++ show (natVal @LargeP Proxy) ++ ")") $ do - describe "literal" $ do - it "doesn't contain type-classes" - $ checkInspection $(inspectTest $ hasNoTypeClasses 'litLarge) - it "is an immediate value modulo casting" - $ checkInspection $(inspectTest $ 'litLarge ==- 'litLargeAnswer) - describe "(Prelude.+)" $ do - it "has the same core representation as (NA.+) modulo casting" $ - checkInspection $(inspectTest $ 'fLargeAddPrelude ==- 'fLargeAddAlgebra) - describe "(NA.+)" $ do - it "doesn't contain type-classes" $ do - checkInspection $(inspectTest $ hasNoTypeClasses 'fLargeAddAlgebra) - it "doesn't contain type-natural comparison" - $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `doesNotUse` 'SLT) - it "doesn't contain Integer type" $ - checkInspection $(inspectTest $ 'fLargeAddAlgebra `hasNoType` ''Int) - it "doesn't contain modInt# operation" - $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `doesNotUse` 'modInt#) - it "has the same core as \a b -> (a + b) `mod` p" - $ checkInspection $(inspectTest $ 'fLargeAddAlgebra ==- 'fLargeAddManual) +spec = describe "F p" $ do + prop "is a field (for small primes)" $ \(SmallPrime p) -> + tabulate "p" [show p] $ + reifyPrimeField p $ property . isField + prop "is a field (for small, but medium primes)" $ \(MediumPrime p) -> + tabulate "p" [show p] $ + reifyPrimeField p $ property . isField + prop "is a field (for big primes)" $ \(BigPrime p) -> + tabulate "p" [show p] $ + reifyPrimeField p $ property . isField + optimisationSpecs newtype SmallPrime = SmallPrime { runSmallPrime :: Integer } deriving newtype (Show) @@ -174,7 +79,3 @@ isField _ e f g = .&&. e * (f * g) === (e * f) * g .&&. e + (f + g) === (e + f) + g .&&. e * (f + g) === e*f + e*g - -instance Testable IT.Result where - property IT.Success{} = property True - property (IT.Failure msg) = error $ "Inspection failure: " ++ msg diff --git a/halg-core-test/test/Algebra/Field/PrimeSpec/Optimisation.hs b/halg-core-test/test/Algebra/Field/PrimeSpec/Optimisation.hs new file mode 100644 index 00000000..364aed8e --- /dev/null +++ b/halg-core-test/test/Algebra/Field/PrimeSpec/Optimisation.hs @@ -0,0 +1,117 @@ +{-# LANGUAGE DataKinds, DerivingStrategies, GADTs #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, KindSignatures, MagicHash #-} +{-# LANGUAGE NoImplicitPrelude, PolyKinds, RankNTypes, ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell, TypeApplications #-} +{-# OPTIONS_GHC -fno-hpc -Wno-orphans -O2 #-} +{-# OPTIONS_GHC -dsuppress-idinfo -dsuppress-coercions + -dsuppress-type-applications + -dsuppress-module-prefixes -dsuppress-type-signatures + -dsuppress-uniques + #-} +module Algebra.Field.PrimeSpec.Optimisation (optimisationSpecs) where +import Algebra.Field.Prime +import AlgebraicPrelude +import qualified AlgebraicPrelude as NA +import Data.Proxy (Proxy (..)) +import Data.Singletons.Prelude +import GHC.Base (modInt#) +import GHC.Integer +import GHC.TypeLits (natVal) +import Language.Haskell.TH +import Math.NumberTheory.Primes +import qualified Prelude as P +import Test.Hspec +import Test.Inspection + +type LargeP = $(litT $ numTyLit $ unPrime + $ nextPrime $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int) + +n102F59 :: F 59 +n102F59 = 102 + +f59AddPrelude :: F 59 -> F 59 -> F 59 +f59AddPrelude = (P.+) + +f59AddAlgebra :: F 59 -> F 59 -> F 59 +f59AddAlgebra = (NA.+) + +f59AddManual :: Int -> Int -> Int +f59AddManual = \l r -> + (l + r) `mod` 59 + +fLargeAddPrelude :: F LargeP -> F LargeP -> F LargeP +fLargeAddPrelude = (P.+) + +fLargeAddAlgebra :: F LargeP -> F LargeP -> F LargeP +fLargeAddAlgebra = (NA.+) + +fLargeAddManual :: Integer -> Integer -> Integer +fLargeAddManual = \ l r -> + (l + r) `mod` natVal @LargeP Proxy + +checkInspection + :: Result -> Expectation +checkInspection Success{} = pure () +checkInspection (Failure msg) = + fail msg + +n43 :: Int +n43 = 43 + +litLarge :: F LargeP +litLarge = $( + let p = unPrime $ nextPrime $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int + in litE $ integerL $ p*3 `div` 2 + ) + +litLargeAnswer :: Integer +litLargeAnswer = $( + let p = unPrime $ nextPrime $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int + in litE $ integerL $ (p*3 `div` 2) `mod` p + ) + +optimisationSpecs :: Spec +optimisationSpecs = do + describe "optimisation for small primes (F 59)" $ do + describe "literal" $ do + it "doesn't contain type-classes" + $ checkInspection $(inspectTest $ hasNoTypeClasses 'n102F59) + it "is an immediate value modulo casting" + $ checkInspection $(inspectTest $ 'n102F59 ==- 'n43) + describe "(Prelude.+)" $ do + it "has the same core representation as (NA.+) modulo casting" $ + checkInspection $(inspectTest $ 'f59AddPrelude ==- 'f59AddAlgebra) + describe "(NA.+)" $ do + it "doesn't contain type-classes" $ do + checkInspection $(inspectTest $ hasNoTypeClasses 'f59AddAlgebra) + it "doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'SLT) + it "doesn't contain Integer type" $ + checkInspection $(inspectTest $ 'f59AddAlgebra `hasNoType` ''Integer) + it "doesn't contain modInteger operation" + $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'modInteger) + it "has the same core as \a b -> (a + b) `mod` 59" + $ checkInspection $(inspectTest $ 'f59AddAlgebra ==- 'f59AddManual) + describe ("optimisation for big prime (F " ++ show (natVal @LargeP Proxy) ++ ")") $ do + describe "literal" $ do + it "doesn't contain type-classes" + $ checkInspection $(inspectTest $ hasNoTypeClasses 'litLarge) + it "is an immediate value modulo casting" + $ checkInspection $(inspectTest $ 'litLarge ==- 'litLargeAnswer) + describe "(Prelude.+)" $ do + it "has the same core representation as (NA.+) modulo casting" $ + checkInspection $(inspectTest $ 'fLargeAddPrelude ==- 'fLargeAddAlgebra) + describe "(NA.+)" $ do + it "doesn't contain type-classes" $ do + checkInspection $(inspectTest $ hasNoTypeClasses 'fLargeAddAlgebra) + it "doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `doesNotUse` 'SLT) + it "doesn't contain Integer type" $ + checkInspection $(inspectTest $ 'fLargeAddAlgebra `hasNoType` ''Int) + it "doesn't contain modInt# operation" + $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `doesNotUse` 'modInt#) + it "has the same core as \a b -> (a + b) `mod` p" + $ checkInspection $(inspectTest $ 'fLargeAddAlgebra ==- 'fLargeAddManual) From 6106135a9b6554733e773266efa952b785fc77b9 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 19:08:23 +0900 Subject: [PATCH 15/62] Lower bound for inspection-testing --- halg-core-test/package.yaml | 2 +- stack-804.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/halg-core-test/package.yaml b/halg-core-test/package.yaml index 183025e5..e9843074 100644 --- a/halg-core-test/package.yaml +++ b/halg-core-test/package.yaml @@ -60,4 +60,4 @@ tests: - hspec - integer-gmp - template-haskell - - inspection-testing + - inspection-testing >= 0.3 diff --git a/stack-804.yaml b/stack-804.yaml index 45e49c13..067687f1 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -29,3 +29,4 @@ extra-deps: - megaparsec-7.0.5 - exact-pi-0.5.0.1@sha256:55e343462be57d692dc6b5fd27d2f52c39052cb402ea03692e4dc460fa69a5d0,2121 - semirings-0.5.3@sha256:4b0d243f88bb07c0673978a37b6b9fd16da44f15e8d552fb08795d9a88a3dc76,3791 +- inspection-testing-0.4.2.4@sha256:10c2fe69eee3c66a4e1fa2f49173f1ff1142b131ed5a6eda986258ff2370aa76,7371 \ No newline at end of file From 9cb1efb95976e82a99733dc78d411eb6bda63a51 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 19:26:18 +0900 Subject: [PATCH 16/62] QuickCheck tabulate --- .gitlab-ci.yml | 2 ++ halg-core-test/package.yaml | 2 +- stack-804.yaml | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4ab07d91..d081284d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,12 +56,14 @@ before_script: - echo "$STACK_YAML" - stack setup - stack build --no-terminal --test --no-run-tests --coverage + - stack build --no-terminal --test --no-run-tests --flag halg-core-test:optimisation-test halg-core-test:exe:halg-optimisation-test .test-script: &test-script stage: test script: - stack setup - stack --no-terminal test --no-rerun-tests --coverage + - stack --no-terminal exec -- halg-optimisation-test build:ghc-8.4: <<: *header-ghc-84 diff --git a/halg-core-test/package.yaml b/halg-core-test/package.yaml index e9843074..5c74e9d9 100644 --- a/halg-core-test/package.yaml +++ b/halg-core-test/package.yaml @@ -55,7 +55,7 @@ tests: - halg-core - halg-core-test - singletons - - QuickCheck + - QuickCheck >= 2.12 - arithmoi >= 0.9 - hspec - integer-gmp diff --git a/stack-804.yaml b/stack-804.yaml index 067687f1..f09f6298 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -16,6 +16,7 @@ packages: - 'halg-polyn-parser' - 'halg-polynomials' +allow-newer: true extra-deps: - control-monad-loop-0.1 - equational-reasoning-0.5.1.0 @@ -29,4 +30,6 @@ extra-deps: - megaparsec-7.0.5 - exact-pi-0.5.0.1@sha256:55e343462be57d692dc6b5fd27d2f52c39052cb402ea03692e4dc460fa69a5d0,2121 - semirings-0.5.3@sha256:4b0d243f88bb07c0673978a37b6b9fd16da44f15e8d552fb08795d9a88a3dc76,3791 -- inspection-testing-0.4.2.4@sha256:10c2fe69eee3c66a4e1fa2f49173f1ff1142b131ed5a6eda986258ff2370aa76,7371 \ No newline at end of file +- inspection-testing-0.4.2.4@sha256:10c2fe69eee3c66a4e1fa2f49173f1ff1142b131ed5a6eda986258ff2370aa76,7371 +- QuickCheck-2.12.6.1 + From dbdfb25106624ddb1b96b1a97836b56ab9010c27 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 20:05:16 +0900 Subject: [PATCH 17/62] Depends to custom `inspection-testing` fork --- stack-802.yaml | 33 --------------------------------- stack-804.yaml | 4 ++-- stack-806.yaml | 2 ++ stack-808.yaml | 4 +++- stack-810.yaml | 4 +++- 5 files changed, 10 insertions(+), 37 deletions(-) delete mode 100644 stack-802.yaml diff --git a/stack-802.yaml b/stack-802.yaml deleted file mode 100644 index dce6a055..00000000 --- a/stack-802.yaml +++ /dev/null @@ -1,33 +0,0 @@ -resolver: lts-11.4 -skip-ghc-check: true -packages: -- 'computational-algebra' -- 'algebraic-prelude' -- 'halg-algebraic' -- 'halg-algorithms' -- 'halg-bridge-singular' -- 'halg-core' -- 'halg-core-test' -- 'halg-factor' -- 'halg-galois-fields' -- 'halg-heaps' -- 'halg-matrices' -- 'halg-polyn-parser' -- 'halg-polynomials' - -flags: - computational-algebra: - examples: true - profile: false - -extra-deps: -- algebra-4.3 -- ghc-typelits-presburger-0.2.0.5 -- unamb-0.2.5 -- hspec-smallcheck-0.5.0 -- control-monad-loop-0.1 -- type-natural-0.8.0.1 -- equational-reasoning-0.5.1.0 -- sized-0.3.0.0 -- parser-combinators-1.1.0 -- megaparsec-7.0.5 \ No newline at end of file diff --git a/stack-804.yaml b/stack-804.yaml index f09f6298..74555a1d 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -30,6 +30,6 @@ extra-deps: - megaparsec-7.0.5 - exact-pi-0.5.0.1@sha256:55e343462be57d692dc6b5fd27d2f52c39052cb402ea03692e4dc460fa69a5d0,2121 - semirings-0.5.3@sha256:4b0d243f88bb07c0673978a37b6b9fd16da44f15e8d552fb08795d9a88a3dc76,3791 -- inspection-testing-0.4.2.4@sha256:10c2fe69eee3c66a4e1fa2f49173f1ff1142b131ed5a6eda986258ff2370aa76,7371 - QuickCheck-2.12.6.1 - +- git: https://github.com/konn/inspection-testing + commit: f78c8e24a01605baf92b64b192fad3b9d7c4bae7 diff --git a/stack-806.yaml b/stack-806.yaml index 25c45d19..814803e3 100644 --- a/stack-806.yaml +++ b/stack-806.yaml @@ -25,3 +25,5 @@ extra-deps: - sized-0.4.0.0 - unamb-0.2.7 - control-monad-loop-0.1 +- git: https://github.com/konn/inspection-testing + commit: f78c8e24a01605baf92b64b192fad3b9d7c4bae7 diff --git a/stack-808.yaml b/stack-808.yaml index fa3ab6f6..1d9b1264 100644 --- a/stack-808.yaml +++ b/stack-808.yaml @@ -20,4 +20,6 @@ extra-deps: - algebra-4.3.1@rev:2 - unamb-0.2.7 - control-monad-loop-0.1 -- repa-3.4.1.4 \ No newline at end of file +- repa-3.4.1.4 +- git: https://github.com/konn/inspection-testing + commit: f78c8e24a01605baf92b64b192fad3b9d7c4bae7 diff --git a/stack-810.yaml b/stack-810.yaml index 5834225f..65084c6e 100644 --- a/stack-810.yaml +++ b/stack-810.yaml @@ -20,4 +20,6 @@ extra-deps: - algebra-4.3.1@rev:2 - control-monad-loop-0.1 - repa-3.4.1.4 -- unamb-0.2.7 \ No newline at end of file +- unamb-0.2.7 +- git: https://github.com/konn/inspection-testing + commit: f78c8e24a01605baf92b64b192fad3b9d7c4bae7 From 6db4a2b73bf51ace260b1e0f5e97b7a46c8dba89 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 20:06:57 +0900 Subject: [PATCH 18/62] Corrects GitLab CI --- .gitlab-ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d081284d..4ab07d91 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,14 +56,12 @@ before_script: - echo "$STACK_YAML" - stack setup - stack build --no-terminal --test --no-run-tests --coverage - - stack build --no-terminal --test --no-run-tests --flag halg-core-test:optimisation-test halg-core-test:exe:halg-optimisation-test .test-script: &test-script stage: test script: - stack setup - stack --no-terminal test --no-rerun-tests --coverage - - stack --no-terminal exec -- halg-optimisation-test build:ghc-8.4: <<: *header-ghc-84 From 285018ea1c64036430a94a3e3980d1aa97e15d2d Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 20:19:52 +0900 Subject: [PATCH 19/62] Corrects commit --- stack-804.yaml | 4 ++-- stack-806.yaml | 4 ++-- stack-808.yaml | 4 ++-- stack-810.yaml | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/stack-804.yaml b/stack-804.yaml index 74555a1d..7e4dc67f 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -31,5 +31,5 @@ extra-deps: - exact-pi-0.5.0.1@sha256:55e343462be57d692dc6b5fd27d2f52c39052cb402ea03692e4dc460fa69a5d0,2121 - semirings-0.5.3@sha256:4b0d243f88bb07c0673978a37b6b9fd16da44f15e8d552fb08795d9a88a3dc76,3791 - QuickCheck-2.12.6.1 -- git: https://github.com/konn/inspection-testing - commit: f78c8e24a01605baf92b64b192fad3b9d7c4bae7 +- git: https://github.com/konn/inspection-testing.git + commit: b3ea6650bf613dd008d4392eaf359b2ab962cbcd diff --git a/stack-806.yaml b/stack-806.yaml index 814803e3..85e73a26 100644 --- a/stack-806.yaml +++ b/stack-806.yaml @@ -25,5 +25,5 @@ extra-deps: - sized-0.4.0.0 - unamb-0.2.7 - control-monad-loop-0.1 -- git: https://github.com/konn/inspection-testing - commit: f78c8e24a01605baf92b64b192fad3b9d7c4bae7 +- git: https://github.com/konn/inspection-testing.git + commit: b3ea6650bf613dd008d4392eaf359b2ab962cbcd diff --git a/stack-808.yaml b/stack-808.yaml index 1d9b1264..617bff16 100644 --- a/stack-808.yaml +++ b/stack-808.yaml @@ -21,5 +21,5 @@ extra-deps: - unamb-0.2.7 - control-monad-loop-0.1 - repa-3.4.1.4 -- git: https://github.com/konn/inspection-testing - commit: f78c8e24a01605baf92b64b192fad3b9d7c4bae7 +- git: https://github.com/konn/inspection-testing.git + commit: b3ea6650bf613dd008d4392eaf359b2ab962cbcd diff --git a/stack-810.yaml b/stack-810.yaml index 65084c6e..827d325d 100644 --- a/stack-810.yaml +++ b/stack-810.yaml @@ -21,5 +21,5 @@ extra-deps: - control-monad-loop-0.1 - repa-3.4.1.4 - unamb-0.2.7 -- git: https://github.com/konn/inspection-testing - commit: f78c8e24a01605baf92b64b192fad3b9d7c4bae7 +- git: https://github.com/konn/inspection-testing.git + commit: b3ea6650bf613dd008d4392eaf359b2ab962cbcd From 4ac656878e10f002b026e43b1938d3cc4210bd5c Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 20:38:32 +0900 Subject: [PATCH 20/62] Updates 8.4.3 dependencies (too tired...) --- stack-804.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/stack-804.yaml b/stack-804.yaml index 7e4dc67f..b7bed562 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -16,7 +16,6 @@ packages: - 'halg-polyn-parser' - 'halg-polynomials' -allow-newer: true extra-deps: - control-monad-loop-0.1 - equational-reasoning-0.5.1.0 @@ -31,5 +30,11 @@ extra-deps: - exact-pi-0.5.0.1@sha256:55e343462be57d692dc6b5fd27d2f52c39052cb402ea03692e4dc460fa69a5d0,2121 - semirings-0.5.3@sha256:4b0d243f88bb07c0673978a37b6b9fd16da44f15e8d552fb08795d9a88a3dc76,3791 - QuickCheck-2.12.6.1 +- hspec-core-2.6.1 +- repa-3.4.1.4 +- repa-algorithms-3.4.1.3 +- quickcheck-instances-0.3.19 +- hspec-2.6.1 +- hspec-discover-2.6.1 - git: https://github.com/konn/inspection-testing.git commit: b3ea6650bf613dd008d4392eaf359b2ab962cbcd From 4c2f1835276b3da97576107d9235b04bfa0c062b Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 21:13:00 +0900 Subject: [PATCH 21/62] Updates commit --- stack-804.yaml | 2 +- stack-806.yaml | 2 +- stack-808.yaml | 2 +- stack-810.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/stack-804.yaml b/stack-804.yaml index b7bed562..483d8759 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -37,4 +37,4 @@ extra-deps: - hspec-2.6.1 - hspec-discover-2.6.1 - git: https://github.com/konn/inspection-testing.git - commit: b3ea6650bf613dd008d4392eaf359b2ab962cbcd + commit: defdd6e3536fd7ef59d09384375f0a46d9b475a0 diff --git a/stack-806.yaml b/stack-806.yaml index 85e73a26..9a4c76fd 100644 --- a/stack-806.yaml +++ b/stack-806.yaml @@ -26,4 +26,4 @@ extra-deps: - unamb-0.2.7 - control-monad-loop-0.1 - git: https://github.com/konn/inspection-testing.git - commit: b3ea6650bf613dd008d4392eaf359b2ab962cbcd + commit: defdd6e3536fd7ef59d09384375f0a46d9b475a0 diff --git a/stack-808.yaml b/stack-808.yaml index 617bff16..c6501dce 100644 --- a/stack-808.yaml +++ b/stack-808.yaml @@ -22,4 +22,4 @@ extra-deps: - control-monad-loop-0.1 - repa-3.4.1.4 - git: https://github.com/konn/inspection-testing.git - commit: b3ea6650bf613dd008d4392eaf359b2ab962cbcd + commit: defdd6e3536fd7ef59d09384375f0a46d9b475a0 diff --git a/stack-810.yaml b/stack-810.yaml index 827d325d..8d3dccbd 100644 --- a/stack-810.yaml +++ b/stack-810.yaml @@ -22,4 +22,4 @@ extra-deps: - repa-3.4.1.4 - unamb-0.2.7 - git: https://github.com/konn/inspection-testing.git - commit: b3ea6650bf613dd008d4392eaf359b2ab962cbcd + commit: defdd6e3536fd7ef59d09384375f0a46d9b475a0 From 8d3d4cc5b5816b5a785cfd781709a95da22c55b7 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 22:06:21 +0900 Subject: [PATCH 22/62] Special treatment for inspection testing --- .gitlab-ci.yml | 4 ++ .hspec-failures | 1 + .../Inspection.hs} | 6 +-- halg-core-test/package.yaml | 37 ++++++++++++++++++- .../test/Algebra/Field/PrimeSpec.hs | 3 -- hie.yaml | 2 + stack-804.yaml | 3 +- stack-806.yaml | 2 - stack-808.yaml | 2 - 9 files changed, 46 insertions(+), 14 deletions(-) create mode 100644 .hspec-failures rename halg-core-test/{test/Algebra/Field/PrimeSpec/Optimisation.hs => opt-test/Inspection.hs} (97%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4ab07d91..48ab32ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,8 +11,10 @@ stages: .cached_dirs: &cached-dirs paths: - '.stack-work/' + - '.stack-no-coverage/' - '.stack-root/' - '*/.stack-work' + - '*/.stack-no-coverage' - '.apt/' - '.hspec-failures' @@ -56,12 +58,14 @@ before_script: - echo "$STACK_YAML" - stack setup - stack build --no-terminal --test --no-run-tests --coverage + - stack build --no-terminal --work-dir=.stack-no-coverage --flag halg-core-test:opt-test halg-core-test:exe:halg-core-opt-test .test-script: &test-script stage: test script: - stack setup - stack --no-terminal test --no-rerun-tests --coverage + - stack exec --work-dir=.stack-no-coverage -- halg-core-opt-test build:ghc-8.4: <<: *header-ghc-84 diff --git a/.hspec-failures b/.hspec-failures new file mode 100644 index 00000000..55f98986 --- /dev/null +++ b/.hspec-failures @@ -0,0 +1 @@ +FailureReport {failureReportSeed = 1324859739, failureReportMaxSuccess = 100, failureReportMaxSize = 100, failureReportMaxDiscardRatio = 10, failureReportPaths = []} \ No newline at end of file diff --git a/halg-core-test/test/Algebra/Field/PrimeSpec/Optimisation.hs b/halg-core-test/opt-test/Inspection.hs similarity index 97% rename from halg-core-test/test/Algebra/Field/PrimeSpec/Optimisation.hs rename to halg-core-test/opt-test/Inspection.hs index 364aed8e..b8885be1 100644 --- a/halg-core-test/test/Algebra/Field/PrimeSpec/Optimisation.hs +++ b/halg-core-test/opt-test/Inspection.hs @@ -8,7 +8,7 @@ -dsuppress-module-prefixes -dsuppress-type-signatures -dsuppress-uniques #-} -module Algebra.Field.PrimeSpec.Optimisation (optimisationSpecs) where +module Inspection (main) where import Algebra.Field.Prime import AlgebraicPrelude import qualified AlgebraicPrelude as NA @@ -73,8 +73,8 @@ litLargeAnswer = $( in litE $ integerL $ (p*3 `div` 2) `mod` p ) -optimisationSpecs :: Spec -optimisationSpecs = do +main :: IO () +main = hspec $ do describe "optimisation for small primes (F 59)" $ do describe "literal" $ do it "doesn't contain type-classes" diff --git a/halg-core-test/package.yaml b/halg-core-test/package.yaml index 5c74e9d9..1226647a 100644 --- a/halg-core-test/package.yaml +++ b/halg-core-test/package.yaml @@ -34,10 +34,45 @@ dependencies: - smallcheck - type-natural +flags: + opt-test: + description: "Whether to build optimisation test" + manual: true + default: false + library: source-dirs: src ghc-options: -Wall -Wno-orphans +executables: + halg-core-opt-test: + when: + - condition: flag(opt-test) + then: + buildable: true + else: + buildable: false + + ghc-options: + - -Wall + - -threaded + - -rtsopts + - -with-rtsopts=-N + - -O2 + - -fno-hpc + - -main-is Inspection + main: Inspection.hs + source-dirs: opt-test + dependencies: + - halg-core + - halg-core-test + - singletons + - QuickCheck >= 2.12 + - arithmoi >= 0.9 + - hspec + - integer-gmp + - template-haskell + - inspection-testing >= 0.3 tests: halg-core-specs: @@ -58,6 +93,4 @@ tests: - QuickCheck >= 2.12 - arithmoi >= 0.9 - hspec - - integer-gmp - template-haskell - - inspection-testing >= 0.3 diff --git a/halg-core-test/test/Algebra/Field/PrimeSpec.hs b/halg-core-test/test/Algebra/Field/PrimeSpec.hs index 82c7ba0d..abcc975e 100644 --- a/halg-core-test/test/Algebra/Field/PrimeSpec.hs +++ b/halg-core-test/test/Algebra/Field/PrimeSpec.hs @@ -9,8 +9,6 @@ -dsuppress-uniques #-} module Algebra.Field.PrimeSpec where -import Algebra.Field.PrimeSpec.Optimisation - import Algebra.Field.Finite.Test () import Algebra.Field.Prime import Algebra.Field.Prime.Test () @@ -43,7 +41,6 @@ spec = describe "F p" $ do prop "is a field (for big primes)" $ \(BigPrime p) -> tabulate "p" [show p] $ reifyPrimeField p $ property . isField - optimisationSpecs newtype SmallPrime = SmallPrime { runSmallPrime :: Integer } deriving newtype (Show) diff --git a/hie.yaml b/hie.yaml index 5f31174a..7e843530 100644 --- a/hie.yaml +++ b/hie.yaml @@ -43,6 +43,8 @@ cradle: component: "halg-core:lib" - path: "halg-core-test/test" component: "halg-core-test:test:halg-core-specs" + - path: "halg-core-test/opt-test" + component: "halg-core-test:exe:halg-core-opt-test" - path: "halg-heaps/src" component: "halg-heaps:lib" diff --git a/stack-804.yaml b/stack-804.yaml index 483d8759..3ef50781 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -36,5 +36,4 @@ extra-deps: - quickcheck-instances-0.3.19 - hspec-2.6.1 - hspec-discover-2.6.1 -- git: https://github.com/konn/inspection-testing.git - commit: defdd6e3536fd7ef59d09384375f0a46d9b475a0 +- inspection-testing-0.4.2.4@sha256:10c2fe69eee3c66a4e1fa2f49173f1ff1142b131ed5a6eda986258ff2370aa76,7371 diff --git a/stack-806.yaml b/stack-806.yaml index 9a4c76fd..25c45d19 100644 --- a/stack-806.yaml +++ b/stack-806.yaml @@ -25,5 +25,3 @@ extra-deps: - sized-0.4.0.0 - unamb-0.2.7 - control-monad-loop-0.1 -- git: https://github.com/konn/inspection-testing.git - commit: defdd6e3536fd7ef59d09384375f0a46d9b475a0 diff --git a/stack-808.yaml b/stack-808.yaml index c6501dce..4294d051 100644 --- a/stack-808.yaml +++ b/stack-808.yaml @@ -21,5 +21,3 @@ extra-deps: - unamb-0.2.7 - control-monad-loop-0.1 - repa-3.4.1.4 -- git: https://github.com/konn/inspection-testing.git - commit: defdd6e3536fd7ef59d09384375f0a46d9b475a0 From 42d0f07d5518cc74df21315ff8cd0b4a11888a9d Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 9 Jul 2020 22:29:22 +0900 Subject: [PATCH 23/62] Backslashes --- halg-core-test/opt-test/Inspection.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/halg-core-test/opt-test/Inspection.hs b/halg-core-test/opt-test/Inspection.hs index b8885be1..91adb95f 100644 --- a/halg-core-test/opt-test/Inspection.hs +++ b/halg-core-test/opt-test/Inspection.hs @@ -93,7 +93,7 @@ main = hspec $ do checkInspection $(inspectTest $ 'f59AddAlgebra `hasNoType` ''Integer) it "doesn't contain modInteger operation" $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'modInteger) - it "has the same core as \a b -> (a + b) `mod` 59" + it "has the same core as \\a b -> (a + b) `mod` 59" $ checkInspection $(inspectTest $ 'f59AddAlgebra ==- 'f59AddManual) describe ("optimisation for big prime (F " ++ show (natVal @LargeP Proxy) ++ ")") $ do describe "literal" $ do @@ -113,5 +113,5 @@ main = hspec $ do checkInspection $(inspectTest $ 'fLargeAddAlgebra `hasNoType` ''Int) it "doesn't contain modInt# operation" $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `doesNotUse` 'modInt#) - it "has the same core as \a b -> (a + b) `mod` p" + it "has the same core as \\a b -> (a + b) `mod` p" $ checkInspection $(inspectTest $ 'fLargeAddAlgebra ==- 'fLargeAddManual) From 141c1bf75eb58adfe9e181e398560eb9e6be39a0 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Fri, 10 Jul 2020 20:50:49 +0900 Subject: [PATCH 24/62] Various optimisation --- .../src/Algebra/Field/Prime/Test.hs | 5 +- halg-core/src/Algebra/Field/Prime.hs | 59 +++++++++++++++---- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/halg-core-test/src/Algebra/Field/Prime/Test.hs b/halg-core-test/src/Algebra/Field/Prime/Test.hs index 9374c0a3..c081c0a0 100644 --- a/halg-core-test/src/Algebra/Field/Prime/Test.hs +++ b/halg-core-test/src/Algebra/Field/Prime/Test.hs @@ -4,16 +4,15 @@ module Algebra.Field.Prime.Test where import Algebra.Field.Finite.Test -import Algebra.Field.Prime (F, IsPrimeChar, modNat) +import Algebra.Field.Prime (F, IsPrimeChar, charInfo, modNat) import Data.Proxy -import Data.Reflection import Prelude (Maybe (..), Monad, fromIntegral, (-), (<$>)) import Test.QuickCheck (Arbitrary (..), resize) import Test.SmallCheck.Series (Serial (..)) instance IsPrimeChar p => Arbitrary (F p) where arbitrary = modNat <$> - resize (fromIntegral (reflect (Proxy :: Proxy p)) - 1) arbitrary + resize (fromIntegral (charInfo (Proxy :: Proxy p)) - 1) arbitrary instance (Monad m, IsPrimeChar p) => Serial m (F p) where series = seriesFiniteField (Nothing :: Maybe (F p)) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 489a1b08..07155225 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -6,7 +6,7 @@ {-# OPTIONS_GHC -fplugin Data.Singletons.TypeNats.Presburger #-} -- | Prime fields module Algebra.Field.Prime - ( F(), IsPrimeChar, + ( F(), IsPrimeChar, charInfo, naturalRepr, reifyPrimeField, withPrimeField, modNat, modNat', modRat, modRat', FiniteField(..), order, @@ -90,6 +90,9 @@ class HasPrimeField kind where -> F (p :: kind) -> a charInfo :: IsPrimeChar p => pxy p -> Integer +{-# SPECIALISE INLINE + charInfo :: ((WORD_MAX_BOUND <=? p) ~ 'False, KnownNat p) + => pxy p -> Integer #-} {-# INLINE charInfo #-} charInfo = charInfo_ @@ -98,13 +101,21 @@ liftFUnary :: forall p. IsPrimeChar p => (forall x. Integral x => x -> x) -> F p -> F p +{-# SPECIALISE INLINE + liftFUnary :: ((WORD_MAX_BOUND <=? p) ~ 'False, KnownNat p) + => (forall x. Integral x => x -> x) + -> F p -> F p #-} liftFUnary f = liftFUnary_ $ (`mod` fromInteger (charInfo @p Proxy)) . f wrapF :: forall p. (IsPrimeChar p) => (forall x. Integral x => x) - -> F (p :: kind) + -> F p +{-# SPECIALISE INLINE + wrapF :: ((WORD_MAX_BOUND <=? p) ~ 'False, KnownNat p) + => (forall x. Integral x => x) + -> F p #-} {-# INLINE wrapF #-} wrapF = \s -> wrapF_ (unwrapIntegral $ s `rem` fromInteger (charInfo @p Proxy)) @@ -113,6 +124,10 @@ unwrapBinF => (forall x. Integral x => x -> x -> a) -> F p -> F p -> a {-# INLINE unwrapBinF #-} +{-# SPECIALISE INLINE + unwrapBinF :: ((WORD_MAX_BOUND <=? p) ~ 'False, KnownNat p) + => (forall x. Integral x => x -> x -> a) + -> F p -> F p -> a #-} unwrapBinF f = unwrapF $ \i -> unwrapF $ \j -> f i (fromIntegral j) liftBinF @@ -120,6 +135,11 @@ liftBinF => (forall x. Integral x => x -> x -> x) -> F p -> F p -> F p {-# INLINE liftBinF #-} +{-# SPECIALISE INLINE + liftBinF :: ((WORD_MAX_BOUND <=? p) ~ 'False, KnownNat p) + => (forall x. Integral x => x -> x -> x) + -> F p -> F p -> F p + #-} liftBinF f = unwrapBinF $ \x y -> wrapF $ fromIntegral $ f x y instance {-# OVERLAPPING #-} HasPrimeField Nat where @@ -150,10 +170,14 @@ instance HasPrimeField Type where wrapF_ = F unwrapF f = \(F p) -> f p -class (HasPrimeField k, Reifies p Integer, CharInfo p) - => IsPrimeChar (p :: k) -instance (HasPrimeField k, Reifies p Integer, CharInfo p) +class (HasPrimeField k, CharInfo p) => IsPrimeChar (p :: k) +instance (HasPrimeField k, CharInfo p) + => IsPrimeChar (p :: k) where + {-# SPECIALISE instance + ( KnownNat p, (WORD_MAX_BOUND <=? p) ~ 'False + ) + => IsPrimeChar p #-} modNat :: IsPrimeChar (p :: k) => Integer -> F p modNat = modNat' Proxy @@ -161,7 +185,7 @@ modNat = modNat' Proxy modNat' :: forall proxy (p :: k). IsPrimeChar p => proxy (F p) -> Integer -> F p modNat' _ i = wrapF $ - let p = reflect (Proxy :: Proxy p) + let p = charInfo (Proxy :: Proxy p) in unwrapIntegral $ fromInteger i `rem` fromInteger p {-# INLINE modNat' #-} @@ -209,9 +233,11 @@ instance IsPrimeChar p => P.Num (F p) where {-# INLINE (*) #-} abs = id + {-# INLINE abs #-} signum = liftFUnary $ \case 0 -> 0 _ -> 1 + {-# INLINE signum #-} pows :: forall p a1. (P.Integral a1, IsPrimeChar p) => F p -> a1 -> F p {-# INLINE pows #-} @@ -219,7 +245,7 @@ pows = flip $ \n -> liftFUnary $ \a -> unwrapIntegral $ modPow (WrapIntegral a) - (WrapIntegral $ fromInteger $ reflect $ Proxy @p) (toInteger n) + (WrapIntegral $ fromInteger $ charInfo $ Proxy @p) (toInteger n) instance IsPrimeChar p => NA.Additive (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) @@ -245,6 +271,8 @@ instance IsPrimeChar p => NA.Monoidal (F p) where {-# INLINE zero #-} sinnum n = liftFUnary $ \k -> P.fromIntegral n P.* k {-# INLINE sinnum #-} + sumWith f = foldl' (\a b -> a + f b) zero + {-# INLINE sumWith #-} instance IsPrimeChar p => NA.LeftModule Natural (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) @@ -279,6 +307,13 @@ instance IsPrimeChar p => NA.Group (F p) where negate = liftFUnary P.negate {-# INLINE negate #-} + subtract = liftBinF P.subtract + {-# INLINE subtract #-} + + times n = liftFUnary $ unwrapIntegral . + NA.times n . WrapIntegral + {-# INLINE times #-} + instance IsPrimeChar p => NA.Abelian (F p) instance IsPrimeChar p => NA.Semiring (F p) @@ -307,6 +342,8 @@ instance IsPrimeChar p => NA.Unital (F p) where {-# INLINE one #-} pow = pows {-# INLINE pow #-} + productWith f = foldl' (\a b -> a * f b) one + {-# INLINE productWith #-} instance IsPrimeChar p => DecidableUnits (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) @@ -343,11 +380,13 @@ instance IsPrimeChar p => Division (F p) where {-# INLINE recip #-} a / b = a * recip b {-# INLINE (/) #-} + (\\) = flip (/) + {-# INLINE (\\) #-} (^) = pows {-# INLINE (^) #-} instance IsPrimeChar p => P.Fractional (F p) where - {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'True) + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => P.Fractional (F p) #-} (/) = C.coerce ((P./) :: WrapAlgebra (F p) -> WrapAlgebra (F p) -> WrapAlgebra (F p)) {-# INLINE (/) #-} @@ -362,10 +401,9 @@ instance IsPrimeChar p => P.Fractional (F p) where instance IsPrimeChar p => NA.Commutative (F p) instance IsPrimeChar p => NA.Characteristic (F p) where - char _ = fromIntegral $ reflect (Proxy :: Proxy p) + char _ = fromIntegral $ charInfo (Proxy :: Proxy p) {-# INLINE char #-} - instance IsPrimeChar p => Show (F p) where showsPrec d = unwrapF $ showsPrec d @@ -374,6 +412,7 @@ instance IsPrimeChar p => PrettyCoeff (F p) where if | p == 0 -> Vanished | p == 1 -> OneCoeff | otherwise -> Positive $ showsPrec d p + {-# INLINE showsCoeff #-} instance IsPrimeChar p => FiniteField (F p) where power _ = 1 From 003ea60127fa444284a467bc5da33f8abcb722ba Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Fri, 10 Jul 2020 21:10:08 +0900 Subject: [PATCH 25/62] Another optimisation --- halg-core/src/Algebra/Field/Prime.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 07155225..31f57383 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -241,11 +241,11 @@ instance IsPrimeChar p => P.Num (F p) where pows :: forall p a1. (P.Integral a1, IsPrimeChar p) => F p -> a1 -> F p {-# INLINE pows #-} -pows = flip $ \n -> liftFUnary $ \a -> - unwrapIntegral $ +pows = flip $ \n -> unwrapF $ \a -> + wrapF_ $ fromIntegral $ modPow (WrapIntegral a) - (WrapIntegral $ fromInteger $ charInfo $ Proxy @p) (toInteger n) + (WrapIntegral $ fromInteger $ charInfo $ Proxy @p) n instance IsPrimeChar p => NA.Additive (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) From 914ecddf94ca259b4210af8399de57bc2aef0e83 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Fri, 10 Jul 2020 21:10:29 +0900 Subject: [PATCH 26/62] More inspection tests --- halg-core-test/opt-test/Inspection.hs | 40 ++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/halg-core-test/opt-test/Inspection.hs b/halg-core-test/opt-test/Inspection.hs index 91adb95f..783854e7 100644 --- a/halg-core-test/opt-test/Inspection.hs +++ b/halg-core-test/opt-test/Inspection.hs @@ -9,6 +9,7 @@ -dsuppress-uniques #-} module Inspection (main) where +import Algebra.Arithmetic (modPow) import Algebra.Field.Prime import AlgebraicPrelude import qualified AlgebraicPrelude as NA @@ -50,6 +51,18 @@ fLargeAddManual :: Integer -> Integer -> Integer fLargeAddManual = \ l r -> (l + r) `mod` natVal @LargeP Proxy +f59ProductSum :: [[F 59]] -> F 59 +f59ProductSum xs = product $ map sum xs + +f59PowPrelude :: F 59 -> Natural -> F 59 +f59PowPrelude = (P.^) + +f59PowAlgebra :: F 59 -> Natural -> F 59 +f59PowAlgebra = (NA.^) + +f59ModPow :: WrapIntegral Int -> Natural -> WrapIntegral Int +f59ModPow i n = modPow i 59 n + checkInspection :: Result -> Expectation checkInspection Success{} = pure () @@ -95,6 +108,31 @@ main = hspec $ do $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'modInteger) it "has the same core as \\a b -> (a + b) `mod` 59" $ checkInspection $(inspectTest $ 'f59AddAlgebra ==- 'f59AddManual) + describe "productSum" $ do + it "doesn't contain type-classes" $ + checkInspection $(inspectTest $ hasNoTypeClasses 'f59ProductSum) + it "doesn't contain modInteger" $ + checkInspection $(inspectTest $ 'f59ProductSum `doesNotUse` 'modInteger) + + describe "(P.^)" $ do + it "doesn't contain type-classes" $ do + checkInspection $(inspectTest $ hasNoTypeClasses 'f59PowPrelude) + it "doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'f59PowPrelude `doesNotUse` 'SLT) + it "doesn't contain modInteger operation" + $ checkInspection $(inspectTest $ 'f59PowPrelude `doesNotUse` 'modInteger) + + describe "(NA.^)" $ do + it "is almost the same as modPow" $ + checkInspection + $(inspectTest + $ 'f59PowAlgebra ==- 'f59ModPow + ) + it "doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'f59PowAlgebra `doesNotUse` 'SLT) + it "doesn't contain modInteger operation" + $ checkInspection $(inspectTest $ 'f59PowAlgebra `doesNotUse` 'modInteger) + describe ("optimisation for big prime (F " ++ show (natVal @LargeP Proxy) ++ ")") $ do describe "literal" $ do it "doesn't contain type-classes" @@ -109,7 +147,7 @@ main = hspec $ do checkInspection $(inspectTest $ hasNoTypeClasses 'fLargeAddAlgebra) it "doesn't contain type-natural comparison" $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `doesNotUse` 'SLT) - it "doesn't contain Integer type" $ + it "doesn't contain Int type" $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `hasNoType` ''Int) it "doesn't contain modInt# operation" $ checkInspection $(inspectTest $ 'fLargeAddAlgebra `doesNotUse` 'modInt#) From f22b5f849dfd19ccd0937d5fa1a18a459b9c7314 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Fri, 10 Jul 2020 21:27:19 +0900 Subject: [PATCH 27/62] Adds benchmark results --- .../prime-field-simple/integer-only.txt | 88 +++++++++++++++++++ .../succinct-prime-field.txt | 82 +++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 bench-results/prime-field-simple/integer-only.txt create mode 100644 bench-results/prime-field-simple/succinct-prime-field.txt diff --git a/bench-results/prime-field-simple/integer-only.txt b/bench-results/prime-field-simple/integer-only.txt new file mode 100644 index 00000000..9b7f01a8 --- /dev/null +++ b/bench-results/prime-field-simple/integer-only.txt @@ -0,0 +1,88 @@ +Benchmark prime-field-simple-bench: RUNNING... +benchmarked recip a middle/F 2 +time 236.5 ns (234.5 ns .. 239.1 ns) + 0.999 R² (0.999 R² .. 1.000 R²) +mean 238.5 ns (237.5 ns .. 239.8 ns) +std dev 3.900 ns (3.025 ns .. 5.268 ns) + +benchmarked recip a middle/F 5 +time 445.6 ns (438.8 ns .. 455.0 ns) + 0.998 R² (0.996 R² .. 0.999 R²) +mean 441.3 ns (437.4 ns .. 445.5 ns) +std dev 13.78 ns (11.92 ns .. 16.17 ns) +variance introduced by outliers: 14% (moderately inflated) + +benchmarked recip a middle/F 59 +time 470.6 ns (457.6 ns .. 478.1 ns) + 0.998 R² (0.996 R² .. 0.999 R²) +mean 446.8 ns (443.7 ns .. 450.5 ns) +std dev 11.70 ns (9.072 ns .. 14.86 ns) +variance introduced by outliers: 11% (moderately inflated) + +benchmarked recip a middle/F 12379 +time 457.8 ns (451.8 ns .. 465.7 ns) + 0.997 R² (0.995 R² .. 0.999 R²) +mean 459.4 ns (455.5 ns .. 463.8 ns) +std dev 14.73 ns (10.99 ns .. 20.33 ns) +variance introduced by outliers: 14% (moderately inflated) + +benchmarked recip a middle/F 3037000507 (large) +time 448.0 ns (442.6 ns .. 456.2 ns) + 0.998 R² (0.997 R² .. 1.000 R²) +mean 453.2 ns (451.0 ns .. 455.8 ns) +std dev 8.157 ns (6.273 ns .. 11.28 ns) + +benchmarked product of units/F 2 +time 35.52 ns (34.46 ns .. 36.34 ns) + 0.996 R² (0.993 R² .. 0.998 R²) +mean 34.56 ns (34.31 ns .. 34.98 ns) +std dev 1.063 ns (743.3 ps .. 1.477 ns) +variance introduced by outliers: 13% (moderately inflated) + +benchmarked product of units/F 5 +time 122.0 ns (120.9 ns .. 123.2 ns) + 0.999 R² (0.999 R² .. 1.000 R²) +mean 123.7 ns (123.2 ns .. 124.2 ns) +std dev 1.586 ns (1.390 ns .. 1.842 ns) + +benchmarked product of units/F 59 +time 1.842 μs (1.824 μs .. 1.861 μs) + 0.998 R² (0.997 R² .. 0.999 R²) +mean 1.908 μs (1.892 μs .. 1.932 μs) +std dev 67.15 ns (49.45 ns .. 95.64 ns) +variance introduced by outliers: 18% (moderately inflated) + +benchmarked product of units/F 12379 +time 402.7 μs (398.1 μs .. 408.7 μs) + 0.998 R² (0.996 R² .. 0.999 R²) +mean 407.4 μs (404.5 μs .. 411.1 μs) +std dev 11.25 μs (8.789 μs .. 14.38 μs) +variance introduced by outliers: 11% (moderately inflated) + +benchmarked sum of prefix-products/F 2 +time 60.04 ns (58.63 ns .. 60.96 ns) + 0.998 R² (0.996 R² .. 0.999 R²) +mean 60.09 ns (59.64 ns .. 60.68 ns) +std dev 1.708 ns (1.419 ns .. 2.164 ns) +variance introduced by outliers: 13% (moderately inflated) + +benchmarked sum of prefix-products/F 5 +time 397.5 ns (395.1 ns .. 401.8 ns) + 1.000 R² (0.999 R² .. 1.000 R²) +mean 405.8 ns (404.3 ns .. 407.3 ns) +std dev 5.011 ns (4.065 ns .. 6.083 ns) + +benchmarked sum of prefix-products/F 59 +time 57.07 μs (54.78 μs .. 58.87 μs) + 0.990 R² (0.977 R² .. 0.997 R²) +mean 56.48 μs (55.73 μs .. 58.21 μs) +std dev 3.521 μs (1.921 μs .. 6.767 μs) +variance introduced by outliers: 38% (moderately inflated) + +benchmarking sum of prefix-products/F 6197 ... took 62.59 s, total 56 iterations +benchmarked sum of prefix-products/F 6197 +time 1.004 s (980.0 ms .. 1.028 s) + 0.999 R² (0.997 R² .. 1.000 R²) +mean 1.024 s (1.011 s .. 1.039 s) +std dev 23.68 ms (17.85 ms .. 29.82 ms) + diff --git a/bench-results/prime-field-simple/succinct-prime-field.txt b/bench-results/prime-field-simple/succinct-prime-field.txt new file mode 100644 index 00000000..aaf639b7 --- /dev/null +++ b/bench-results/prime-field-simple/succinct-prime-field.txt @@ -0,0 +1,82 @@ +Benchmark prime-field-simple-bench: RUNNING... +benchmarked recip a middle/F 2 +time 155.1 ns (154.1 ns .. 155.9 ns) + 1.000 R² (0.999 R² .. 1.000 R²) +mean 154.3 ns (153.7 ns .. 154.9 ns) +std dev 1.829 ns (1.560 ns .. 2.296 ns) + +benchmarked recip a middle/F 5 +time 337.0 ns (332.3 ns .. 342.2 ns) + 0.999 R² (0.998 R² .. 0.999 R²) +mean 333.5 ns (331.6 ns .. 335.4 ns) +std dev 6.518 ns (5.487 ns .. 7.813 ns) + +benchmarked recip a middle/F 59 +time 327.0 ns (319.3 ns .. 335.0 ns) + 0.996 R² (0.993 R² .. 0.999 R²) +mean 338.7 ns (333.5 ns .. 353.1 ns) +std dev 25.57 ns (11.58 ns .. 46.73 ns) +variance introduced by outliers: 48% (moderately inflated) + +benchmarked recip a middle/F 12379 +time 336.6 ns (333.3 ns .. 340.5 ns) + 0.999 R² (0.999 R² .. 1.000 R²) +mean 336.0 ns (334.5 ns .. 337.5 ns) +std dev 5.277 ns (4.665 ns .. 6.132 ns) + +benchmarked recip a middle/F 3037000507 (large) +time 475.0 ns (470.7 ns .. 479.8 ns) + 0.999 R² (0.999 R² .. 1.000 R²) +mean 478.1 ns (476.1 ns .. 480.2 ns) +std dev 6.954 ns (5.536 ns .. 8.713 ns) + +benchmarked product of units/F 2 +time 11.53 ns (11.37 ns .. 11.72 ns) + 0.999 R² (0.999 R² .. 0.999 R²) +mean 11.45 ns (11.39 ns .. 11.50 ns) +std dev 185.6 ps (157.3 ps .. 218.1 ps) + +benchmarked product of units/F 5 +time 52.47 ns (52.10 ns .. 52.87 ns) + 0.999 R² (0.999 R² .. 1.000 R²) +mean 52.13 ns (51.90 ns .. 52.38 ns) +std dev 833.1 ps (663.3 ps .. 1.106 ns) + +benchmarked product of units/F 59 +time 711.1 ns (704.1 ns .. 723.4 ns) + 0.999 R² (0.999 R² .. 1.000 R²) +mean 706.9 ns (705.2 ns .. 709.3 ns) +std dev 6.973 ns (4.830 ns .. 11.14 ns) + +benchmarked product of units/F 12379 +time 148.8 μs (146.6 μs .. 150.7 μs) + 0.998 R² (0.997 R² .. 0.999 R²) +mean 154.1 μs (151.5 μs .. 160.9 μs) +std dev 14.10 μs (8.022 μs .. 21.62 μs) +variance introduced by outliers: 60% (severely inflated) + +benchmarked sum of prefix-products/F 2 +time 8.807 ns (8.729 ns .. 8.884 ns) + 1.000 R² (0.999 R² .. 1.000 R²) +mean 8.827 ns (8.793 ns .. 8.859 ns) +std dev 109.4 ps (95.53 ps .. 126.7 ps) + +benchmarked sum of prefix-products/F 5 +time 144.2 ns (143.1 ns .. 145.3 ns) + 1.000 R² (0.999 R² .. 1.000 R²) +mean 144.0 ns (143.5 ns .. 144.8 ns) +std dev 2.105 ns (1.366 ns .. 3.271 ns) + +benchmarked sum of prefix-products/F 59 +time 19.70 μs (19.55 μs .. 19.90 μs) + 0.998 R² (0.995 R² .. 1.000 R²) +mean 19.74 μs (19.66 μs .. 19.93 μs) +std dev 406.5 ns (199.0 ns .. 802.2 ns) + +benchmarking sum of prefix-products/F 6197 ... took 39.75 s, total 56 iterations +benchmarked sum of prefix-products/F 6197 +time 611.1 ms (589.5 ms .. 638.2 ms) + 0.997 R² (0.993 R² .. 1.000 R²) +mean 602.3 ms (594.5 ms .. 611.2 ms) +std dev 14.69 ms (10.77 ms .. 19.51 ms) + From 80300518070d72e29833ecf50f29a5a83f6e49ea Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Fri, 10 Jul 2020 21:28:02 +0900 Subject: [PATCH 28/62] Unused imports --- halg-core/src/Algebra/Ring/Polynomial/Monomial.hs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs b/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs index ac439231..09075911 100644 --- a/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs +++ b/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs @@ -28,13 +28,12 @@ import AlgebraicPrelude hiding (lex) import Control.DeepSeq (NFData (..)) import qualified Control.Foldl as Fl import Control.Lens (Ixed (..), imap, makeLenses, - makeWrapped, (%~), (&), (.~), _1, - _2, _Wrapped) + makeWrapped, (%~), (&), (.~), + _Wrapped) import qualified Data.Coerce as DC import Data.Constraint ((:=>) (..), Dict (..)) import qualified Data.Constraint as C import Data.Constraint.Forall (Forall, inst) -import Data.Functor.Identity (Identity (..)) import Data.Hashable (Hashable (..)) import Data.Kind (Type) import Data.Maybe (catMaybes) From d97c5eb12fc06f3871f896cb9f68023cb5e1c53c Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 01:37:19 +0900 Subject: [PATCH 29/62] Removes garbage --- bench-results/factor-simple/integer-rep.csv | 5 ----- 1 file changed, 5 deletions(-) diff --git a/bench-results/factor-simple/integer-rep.csv b/bench-results/factor-simple/integer-rep.csv index 692e9044..c1f641fe 100644 --- a/bench-results/factor-simple/integer-rep.csv +++ b/bench-results/factor-simple/integer-rep.csv @@ -1,9 +1,4 @@ Name,Mean,MeanLB,MeanUB,Stddev,StddevLB,StddevUB -Name,Mean,MeanLB,MeanUB,Stddev,StddevLB,StddevUB -irreducible/F 2/2,7.264150009518554e-5,7.152787574293286e-5,7.561699542290982e-5,5.944043209466715e-6,2.453403763097677e-6,1.1702813025393934e-5 -irreducible/F 2/3,1.092884733823993e-4,1.0892632663283031e-4,1.0969018490746347e-4,1.3459746438518478e-6,1.0632243910435613e-6,1.7129619700444039e-6 -irreducible/F 2/4,1.46426671429747e-4,1.4535882884154227e-4,1.483138790457574e-4,4.853059819672197e-6,3.0718057636027256e-6,7.854771064585636e-6 -Name,Mean,MeanLB,MeanUB,Stddev,StddevLB,StddevUB irreducible/F 2/2,7.208673573686793e-5,7.089030602531608e-5,7.602989221138268e-5,6.5808782930658304e-6,2.0494905906732154e-6,1.3281934975089511e-5 irreducible/F 2/3,1.0893896301661859e-4,1.087123385498305e-4,1.0917626918501725e-4,7.593824137518804e-7,6.235124796051714e-7,9.612951820481203e-7 irreducible/F 2/4,1.4521931513164689e-4,1.4471514592355594e-4,1.4609554193487407e-4,2.1055759630399193e-6,1.4193159061560957e-6,3.2848070300705517e-6 From d6d2a2a3fe45f6dbe190a664fca465f8dfa8b543 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 01:37:29 +0900 Subject: [PATCH 30/62] Adds succinct version bench results --- bench-results/factor-simple/succinct.csv | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 bench-results/factor-simple/succinct.csv diff --git a/bench-results/factor-simple/succinct.csv b/bench-results/factor-simple/succinct.csv new file mode 100644 index 00000000..13539530 --- /dev/null +++ b/bench-results/factor-simple/succinct.csv @@ -0,0 +1,47 @@ +Name,Mean,MeanLB,MeanUB,Stddev,StddevLB,StddevUB +irreducible/F 2/2,8.773333167463124e-5,8.750641807905479e-5,8.807007642030523e-5,9.304122689335198e-7,6.893064438041168e-7,1.5010412019472778e-6 +irreducible/F 2/3,1.367726481466475e-4,1.3563734362986838e-4,1.4026309437932416e-4,6.5552796376954194e-6,1.4949133064044918e-6,1.2380407286549047e-5 +irreducible/F 2/4,1.8269288981310786e-4,1.8217684595618768e-4,1.8320636746136976e-4,1.762417718287894e-6,1.367361450496774e-6,2.286702190800152e-6 +irreducible/F 2/5,2.477219364461627e-4,2.473023256131557e-4,2.486263994269796e-4,2.0179451477904124e-6,1.1824029793638885e-6,3.6001794404451122e-6 +irreducible/F 2/20,4.03319177522235e-3,4.02408379634791e-3,4.045070609177615e-3,3.276822192637915e-5,2.5836466333903874e-5,4.363710961627616e-5 +irreducible/F 59/2,1.1250068673173105e-4,1.1212926893905283e-4,1.1316752787071147e-4,1.5777893892294078e-6,1.1613341824077878e-6,2.6419473491978302e-6 +irreducible/F 59/3,2.3223246012411572e-4,2.3170224030478106e-4,2.3291250985168149e-4,2.064644819491742e-6,1.7445104512253725e-6,2.640543753104028e-6 +irreducible/F 59/4,4.1452492901389944e-4,4.0891401864926613e-4,4.2810135495495997e-4,2.7190839281613763e-5,6.229385858789437e-6,4.430162667727906e-5 +irreducible/F 59/5,6.608830437439413e-4,6.594307873045284e-4,6.62262728827462e-4,4.831264827935087e-6,4.019593317575904e-6,5.831608153545574e-6 +irreducible/F 12379/2,1.47606081025926e-4,1.4719660999477026e-4,1.4816229206604084e-4,1.5526975168031952e-6,1.0227194604331877e-6,2.6243073451738885e-6 +irreducible/F 12379/3,3.357366780983203e-4,3.348592466997109e-4,3.3667094971504886e-4,3.0397633978181243e-6,2.417249548415558e-6,3.981646496371646e-6 +irreducible/F 12379/4,6.459375614024729e-4,6.43452662966242e-4,6.495339472282861e-4,9.701078426749282e-6,6.894645093778764e-6,1.3525407245130075e-5 +irreducible/F 12379/5,1.0798969847534382e-3,1.0749942096599967e-3,1.0926665629483576e-3,2.505354628918578e-5,9.873176944232597e-6,4.819925141516394e-5 +irreducible/F 12379/20,4.752869917186583e-2,4.742495237103174e-2,4.766636395589569e-2,2.3363989792111043e-4,1.8117521764341064e-4,3.194427506130206e-4 +irreducible/GF 2 5/degree 2,2.6070510552269016e-3,2.601901731483869e-3,2.6139395694688146e-3,2.043607418638975e-5,1.605700149950761e-5,2.9444356319279154e-5 +irreducible/GF 2 5/degree 3,7.590767041062582e-3,7.572855473649871e-3,7.62609260122718e-3,7.460754469384551e-5,3.829683678967434e-5,1.2002954067419267e-4 +irreducible/GF 2 5/degree 4,1.7023510088991525e-2,1.6980742584074494e-2,1.7097828902554006e-2,1.4346898369468742e-4,8.534426110067751e-5,2.5358178663555944e-4 +irreducible/GF 2 5/degree 5,2.9295549029335077e-2,2.9201845103203644e-2,2.9446846094706602e-2,2.579755290083891e-4,1.6065057030701383e-4,3.7805735374861184e-4 +irreducible/GF 2 5/degree 20,1.6003179621654762,1.597383428075,1.6049706013133331,6.385135741976878e-3,2.9671358412104594e-3,8.710988074850197e-3 +product of polynomials of degree one/F 59/factors 5,4.095962575314789e-4,4.0783475441193135e-4,4.146390360381596e-4,9.672325550915498e-6,3.521820229493818e-6,1.9332405244466084e-5 +product of polynomials of degree one/F 59/factors 10,1.3752819735464601e-3,1.3722186315481809e-3,1.3810546442032982e-3,1.4416983662223172e-5,8.27507082884512e-6,2.4984987947279544e-5 +product of polynomials of degree one/F 59/factors 20,2.09824111417531e-3,2.0931543018148564e-3,2.1036402420552733e-3,1.8041850206099932e-5,1.422443927214944e-5,2.3647484381675885e-5 +product of polynomials of degree one/F 59/factors 50,6.962856250450621e-3,6.944125234408469e-3,6.9842699566081e-3,5.984984885874931e-5,4.7176890817403164e-5,8.0243756245612e-5 +product of polynomials of degree one/F 59/factors 100,1.7324052004797696e-2,1.728176666961604e-2,1.7378432947267552e-2,1.1829701815849274e-4,8.438868028521784e-5,1.5562523195688596e-4 +product of polynomials of degree one/F 12379/factors 5,1.0042507350635722e-3,1.0001910738153671e-3,1.017979822255345e-3,2.1701955590931214e-5,9.673032944982742e-6,4.687371149049851e-5 +product of polynomials of degree one/F 12379/factors 10,2.409411013020973e-3,2.3983947389708644e-3,2.438879339000777e-3,5.194876301985126e-5,2.8593475651837838e-5,1.1419755790624143e-4 +product of polynomials of degree one/F 12379/factors 20,6.791083260546888e-3,6.769092840293132e-3,6.85260462361362e-3,1.0183159805227291e-4,4.76532174739178e-5,1.889225983484542e-4 +product of polynomials of degree one/F 12379/factors 50,3.770287240514451e-2,3.7627302844352e-2,3.7770317258560365e-2,1.5642516336537588e-4,1.2067607575367491e-4,1.9038294979407966e-4 +product of polynomials of degree one/F 12379/factors 100,0.5133400671022222,0.5120794646322222,0.5154907171288888,2.684689976702015e-3,1.2515893739638746e-3,3.439977996838952e-3 +product of polynomials of degree one/GF 2 5/factors 5,5.950579791063102e-3,5.936570286842756e-3,5.976438834148005e-3,5.660453150498568e-5,3.6666818892752074e-5,9.518368823415542e-5 +product of polynomials of degree one/GF 2 5/factors 10,3.3075709635252505e-2,3.2975293005682416e-2,3.317462773728659e-2,2.2211256096725152e-4,1.6769355892952344e-4,3.41622242356047e-4 +product of polynomials of degree one/GF 2 5/factors 20,0.10703995161738096,0.10678069265380952,0.10740502185,5.375175627476836e-4,3.716286918983524e-4,7.844008445327295e-4 +product of polynomials of degree one/GF 2 5/factors 50,0.2203820258315476,0.21959497203750003,0.22179577824000002,1.8517812738120872e-3,1.035573427800105e-3,2.8396948184852213e-3 +randomly generated polynomials/F 2/degree 5,2.0398884099539745e-4,2.0336189201311996e-4,2.0525480131983724e-4,2.8534823795810815e-6,1.8103266662880511e-6,4.1627512034613326e-6 +randomly generated polynomials/F 2/degree 10,4.0429151625044033e-4,4.0304580327930054e-4,4.0618857035187823e-4,5.043999927513805e-6,3.5339868792186615e-6,7.01511518416992e-6 +randomly generated polynomials/F 2/degree 50,2.5000158690074076e-2,2.493975440030226e-2,2.5091654906722157e-2,1.669526091094712e-4,1.0909182696043438e-4,2.198206668220071e-4 +randomly generated polynomials/F 2/degree 100,0.5645041157109126,0.5632374513463889,0.5663865619647221,2.625667585286944e-3,1.825152259503313e-3,3.542624713888584e-3 +randomly generated polynomials/F 59/degree 5,4.328280345619941e-4,4.310917193238077e-4,4.376550766589994e-4,9.504281477671013e-6,4.326380421873337e-6,1.855769844031806e-5 +randomly generated polynomials/F 59/degree 10,1.4277934532919223e-3,1.4219128163453936e-3,1.4400240393813274e-3,2.8630832943029578e-5,1.0067874725498842e-5,4.8297545505048077e-5 +randomly generated polynomials/F 59/degree 50,0.2817617971257143,0.2813942721066667,0.2821907444880952,6.667110689290824e-4,4.7356335354439686e-4,1.0295187786847815e-3 +randomly generated polynomials/F 12379/degree 5,5.44288308339946e-4,5.4283548647894e-4,5.470641308779212e-4,6.725253046557752e-6,4.243082086006262e-6,1.1492029658161423e-5 +randomly generated polynomials/F 12379/degree 10,2.9423582207185285e-3,2.924040840780297e-3,3.00794702872545e-3,1.0405849130882006e-4,2.3482982582900816e-5,2.1632902337349197e-4 +randomly generated polynomials/F 12379/degree 50,0.17365914054063492,0.17335345637277777,0.17412582271801585,6.152828941969353e-4,3.621195344933377e-4,9.153697760574074e-4 +randomly generated polynomials/GF 2 5/degree 5,2.471227188660412e-2,2.4645946206329036e-2,2.4772784954520077e-2,1.421041948310729e-4,1.1074627331126484e-4,1.9403648127709614e-4 +randomly generated polynomials/GF 2 5/degree 10,8.285994654070904e-2,8.271089768942345e-2,8.305596714837661e-2,3.055860515291243e-4,2.322558431615353e-4,3.8547121555958263e-4 +randomly generated polynomials/GF 2 5/degree 25,0.8201825134884126,0.8184502785078571,0.8224240676984127,3.3300548872144653e-3,2.0864745111437233e-3,4.605345574677959e-3 From 07e3b5ab5284a7215b5eb91ecf92573a83c4e722 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 17:17:13 +0900 Subject: [PATCH 31/62] Profiling for factorisation --- computational-algebra/package.yaml | 1 - halg-factor/app/Main.hs | 6 ---- halg-factor/app/factor-deg50-prof.hs | 50 ++++++++++++++++++++++++++++ halg-factor/package.yaml | 33 +++++++++++++++++- hie.yaml | 2 ++ stack-prof.yaml | 44 ++++++++++++++++++++++++ 6 files changed, 128 insertions(+), 8 deletions(-) delete mode 100644 halg-factor/app/Main.hs create mode 100644 halg-factor/app/factor-deg50-prof.hs create mode 100644 stack-prof.yaml diff --git a/computational-algebra/package.yaml b/computational-algebra/package.yaml index ba90dee6..2c15933a 100644 --- a/computational-algebra/package.yaml +++ b/computational-algebra/package.yaml @@ -57,7 +57,6 @@ library: when: - condition: flag(profile) ghc-options: - - -prof - -fprof-auto-exported _exe-defaults: &exe-defaults diff --git a/halg-factor/app/Main.hs b/halg-factor/app/Main.hs deleted file mode 100644 index de1c1ab3..00000000 --- a/halg-factor/app/Main.hs +++ /dev/null @@ -1,6 +0,0 @@ -module Main where - -import Lib - -main :: IO () -main = someFunc diff --git a/halg-factor/app/factor-deg50-prof.hs b/halg-factor/app/factor-deg50-prof.hs new file mode 100644 index 00000000..2cae5bbd --- /dev/null +++ b/halg-factor/app/factor-deg50-prof.hs @@ -0,0 +1,50 @@ +{-# LANGUAGE DataKinds, GADTs, LambdaCase, NoImplicitPrelude #-} +{-# LANGUAGE OverloadedLabels, PolyKinds, TypeApplications, TypeOperators #-} +module Main where +import Algebra.Field.Prime +import Algebra.Prelude.Core +import Algebra.Ring.Polynomial.Factorise +import Algebra.Ring.Polynomial.Univariate +import Control.Exception (evaluate) +import Control.Monad.Random +import System.Environment + +type Seed = Int +randomPoly + :: (Random k, CoeffRing k) + => Seed -> Proxy k -> Natural -> Unipol k +randomPoly _ _ 0 = one +randomPoly seed _ deg = + sum $ zipWith (\i -> (#x^ i *) . injectCoeff) [deg, pred deg ..] + $ one : withSeed seed (replicateM (fromIntegral deg) getRandom) + +withSeed :: Seed -> Rand StdGen a -> a +withSeed = flip evalRand . mkStdGen + +f2_rand_deg50 :: Unipol (F 2) +f2_rand_deg50 = + randomPoly (-6593109385820112487) (Proxy @(F 2)) 100 + +f59_rand_deg50 :: Unipol (F 59) +f59_rand_deg50 = + randomPoly (-3071815209415553516) Proxy 100 + +main :: IO () +main = getArgs >>= \case + ["2"] -> void $ evaluate $ withSeed 6147031469590640211 + $ factorise f2_rand_deg50 + ["59"] -> void $ evaluate $ withSeed 7650165946084592722 + $ factorise f59_rand_deg100 + ["2", "100"] -> void $ evaluate $ withSeed 6147031469590640211 + $ factorise f2_rand_deg100 + ["59", "100"] -> void $ evaluate $ withSeed 7650165946084592722 + $ factorise f59_rand_deg100 + _ -> error "Arguments must be one of 2 or 59" + +f2_rand_deg100 :: Unipol (F 2) +f2_rand_deg100 = + randomPoly 919154999066204904 (Proxy @(F 2)) 100 + +f59_rand_deg100 :: Unipol (F 59) +f59_rand_deg100 = + randomPoly (-3354538193028255891) Proxy 100 diff --git a/halg-factor/package.yaml b/halg-factor/package.yaml index d7ec1346..f5ae7c25 100644 --- a/halg-factor/package.yaml +++ b/halg-factor/package.yaml @@ -25,6 +25,12 @@ description: Please see the project Web Site = 4.7 && < 5 +flags: + profile: + manual: true + default: false + description: Whether to build profiling executables or not (default false). + library: source-dirs: src ghc-options: -Wall @@ -49,10 +55,35 @@ library: default-extensions: - NoImplicitPrelude -executables: {} +executables: + factor-deg50-prof: + source-dirs: app + ghc-options: + - -Wall + - -O2 + - -rtsopts + - -threaded + main: factor-deg50-prof.hs + dependencies: + - halg-factor + - halg-core + - halg-polynomials + - base + - MonadRandom + - deepseq tests: halg-factor-specs: + when: + - condition: flag(profile) + then: + buildable: true + ghc-options: + - -prof + - -fprof-auto-exported + else: + buildable: false + source-dirs: test ghc-options: -Wall main: Spec.hs diff --git a/hie.yaml b/hie.yaml index 53d0c6b1..12aebc49 100644 --- a/hie.yaml +++ b/hie.yaml @@ -12,6 +12,8 @@ cradle: component: "halg-factor:lib" - path: "halg-factor/test" component: "halg-factor:test:halg-factor-specs" + - path: "halg-factor/app/factor-deg50-prof.hs" + component: "halg-factor:exe:factor-deg50-prof" - path: "halg-factor/bench/factor-simple-bench.hs" component: "halg-factor:bench:factor-simple-bench" diff --git a/stack-prof.yaml b/stack-prof.yaml new file mode 100644 index 00000000..cdb0206d --- /dev/null +++ b/stack-prof.yaml @@ -0,0 +1,44 @@ +resolver: lts-14.21 + +flags: + computational-algebra: + profile: true + halg-factor: + profile: true + +work-dir: .stack-prof + +build: + executable-profiling: true + library-profiling: true + +apply-ghc-options: everything +rebuild-ghc-options: true +ghc-options: + "$everything": -fno-prof-auto + "$locals": -fprof-auto + +packages: +- 'computational-algebra' +- 'algebraic-prelude' +- 'halg-algebraic' +- 'halg-algorithms' +- 'halg-bridge-singular' +- 'halg-core' +- 'halg-core-test' +- 'halg-factor' +- 'halg-galois-fields' +- 'halg-heaps' +- 'halg-matrices' +- 'halg-polyn-parser' +- 'halg-polynomials' + +extra-deps: +- equational-reasoning-0.6.0.1 +- ghc-typelits-presburger-0.3.0.0 +- singletons-presburger-0.3.0.1 +- type-natural-0.8.3.1 +- algebra-4.3.1@rev:2 +- sized-0.4.0.0 +- unamb-0.2.7 +- control-monad-loop-0.1 From 2da0a937328321a70ec6ca663699e5289778d8e5 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 19:08:11 +0900 Subject: [PATCH 32/62] Profiling reconfiguration --- .vscode/settings.json | 3 ++- computational-algebra/package.yaml | 5 ----- halg-factor/package.yaml | 18 ++++++++---------- stack-prof.yaml | 2 +- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ac49639b..514395cc 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,6 @@ "editor.tabCompletion": "onlySnippets", "files.exclude": { "heap-poly": true - } + }, + "stylishHaskell.showConsoleOnError": false } \ No newline at end of file diff --git a/computational-algebra/package.yaml b/computational-algebra/package.yaml index 2c15933a..f270eee4 100644 --- a/computational-algebra/package.yaml +++ b/computational-algebra/package.yaml @@ -54,10 +54,6 @@ dependencies: library: source-dirs: src ghc-options: -Wall - when: - - condition: flag(profile) - ghc-options: - - -fprof-auto-exported _exe-defaults: &exe-defaults source-dirs: examples @@ -110,7 +106,6 @@ _profile-cond: &profile-cond - -rtsopts - -eventlog - -prof - - -fprof-auto-exported _examples: &examples algebraic: diff --git a/halg-factor/package.yaml b/halg-factor/package.yaml index f5ae7c25..8e8890f7 100644 --- a/halg-factor/package.yaml +++ b/halg-factor/package.yaml @@ -74,16 +74,6 @@ executables: tests: halg-factor-specs: - when: - - condition: flag(profile) - then: - buildable: true - ghc-options: - - -prof - - -fprof-auto-exported - else: - buildable: false - source-dirs: test ghc-options: -Wall main: Spec.hs @@ -105,6 +95,14 @@ tests: benchmarks: factor-simple-bench: + when: + - condition: flag(profile) + then: + buildable: true + ghc-options: + - -prof + else: + buildable: false source-dirs: bench main: factor-simple-bench.hs dependencies: diff --git a/stack-prof.yaml b/stack-prof.yaml index cdb0206d..884d5b8e 100644 --- a/stack-prof.yaml +++ b/stack-prof.yaml @@ -16,7 +16,7 @@ apply-ghc-options: everything rebuild-ghc-options: true ghc-options: "$everything": -fno-prof-auto - "$locals": -fprof-auto + "$locals": -fno-prof-auto packages: - 'computational-algebra' From bce0e35215b749157f534177e68230e57fac1cee Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 19:08:39 +0900 Subject: [PATCH 33/62] Aggressive optimisation --- algebraic-prelude/src/AlgebraicPrelude.hs | 130 +++++++++++++++++++--- halg-core-test/opt-test/Inspection.hs | 26 +++++ halg-core/src/Algebra/Field/Prime.hs | 72 ++++++++---- 3 files changed, 193 insertions(+), 35 deletions(-) diff --git a/algebraic-prelude/src/AlgebraicPrelude.hs b/algebraic-prelude/src/AlgebraicPrelude.hs index 546a4fb1..82fb2696 100644 --- a/algebraic-prelude/src/AlgebraicPrelude.hs +++ b/algebraic-prelude/src/AlgebraicPrelude.hs @@ -1,8 +1,9 @@ -{-# LANGUAGE ConstraintKinds, FlexibleContexts, FlexibleInstances #-} -{-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses #-} -{-# LANGUAGE NoImplicitPrelude, NoRebindableSyntax, StandaloneDeriving #-} -{-# LANGUAGE TemplateHaskell, TypeFamilies, UndecidableInstances #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# LANGUAGE ConstraintKinds, FlexibleContexts, FlexibleInstances #-} +{-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses #-} +{-# LANGUAGE NoImplicitPrelude, NoRebindableSyntax, ScopedTypeVariables #-} +{-# LANGUAGE StandaloneDeriving, TemplateHaskell, TypeFamilies #-} +{-# LANGUAGE UndecidableInstances #-} +{-# OPTIONS_GHC -O2 -fno-warn-orphans #-} -- | This module provides drop-in replacement for @'Prelude'@ module in base package, -- based on algebraic hierarchy provided by -- package. @@ -87,6 +88,7 @@ import BasicPrelude as AlgebraicPrelude hidin (^), (^^)) import qualified Control.Lens.TH as L +import Data.Coerce (coerce) import qualified Data.Ratio as P import qualified Data.Semigroup as Semi import Foreign.Storable (Storable) @@ -369,34 +371,55 @@ newtype WrapIntegral a = WrapIntegral { unwrapIntegral :: a } deriving (Read, Show, Eq, Ord, P.Num, P.Real, P.Enum, P.Integral, Storable) instance (P.Num a) => Additive (WrapIntegral a) where + {-# SPECIALISE instance Additive (WrapIntegral Int) #-} + {-# SPECIALISE instance Additive (WrapIntegral Word) #-} + {-# SPECIALISE instance Additive (WrapIntegral Integer) #-} WrapIntegral a + WrapIntegral b = WrapIntegral (a P.+ b) {-# INLINE (+) #-} sinnum1p n (WrapIntegral a) = WrapIntegral ((1 P.+ fromIntegral n) P.* a) {-# INLINE sinnum1p #-} instance (P.Num a) => LeftModule Natural (WrapIntegral a) where + {-# SPECIALISE instance LeftModule Natural (WrapIntegral Int) #-} + {-# SPECIALISE instance LeftModule Natural (WrapIntegral Word) #-} + {-# SPECIALISE instance LeftModule Natural (WrapIntegral Integer) #-} n .* WrapIntegral r = WrapIntegral (P.fromIntegral n P.* r) {-# INLINE (.*) #-} instance (P.Num a) => RightModule Natural (WrapIntegral a) where + {-# SPECIALISE instance RightModule Natural (WrapIntegral Int) #-} + {-# SPECIALISE instance RightModule Natural (WrapIntegral Word) #-} + {-# SPECIALISE instance RightModule Natural (WrapIntegral Integer) #-} WrapIntegral r *. n = WrapIntegral (r P.* P.fromIntegral n) {-# INLINE (*.) #-} instance (P.Num a) => Monoidal (WrapIntegral a) where + {-# SPECIALISE instance Monoidal (WrapIntegral Int) #-} + {-# SPECIALISE instance Monoidal (WrapIntegral Word) #-} + {-# SPECIALISE instance Monoidal (WrapIntegral Integer) #-} zero = WrapIntegral (P.fromInteger 0) {-# INLINE zero #-} sinnum n (WrapIntegral a) = WrapIntegral (fromIntegral n P.* a) {-# INLINE sinnum #-} instance (P.Num a) => LeftModule Integer (WrapIntegral a) where + {-# SPECIALISE instance LeftModule Integer (WrapIntegral Int) #-} + {-# SPECIALISE instance LeftModule Integer (WrapIntegral Word) #-} + {-# SPECIALISE instance LeftModule Integer (WrapIntegral Integer) #-} n .* WrapIntegral r = WrapIntegral (P.fromIntegral n P.* r) {-# INLINE (.*) #-} instance (P.Num a) => RightModule Integer (WrapIntegral a) where + {-# SPECIALISE instance RightModule Integer (WrapIntegral Int) #-} + {-# SPECIALISE instance RightModule Integer (WrapIntegral Word) #-} + {-# SPECIALISE instance RightModule Integer (WrapIntegral Integer) #-} WrapIntegral r *. n = WrapIntegral (r P.* P.fromIntegral n) {-# INLINE (*.) #-} instance (P.Num a) => Group (WrapIntegral a) where + {-# SPECIALISE instance Group (WrapIntegral Int) #-} + {-# SPECIALISE instance Group (WrapIntegral Word) #-} + {-# SPECIALISE instance Group (WrapIntegral Integer) #-} negate (WrapIntegral a) = WrapIntegral $ P.negate a {-# INLINE negate #-} WrapIntegral a - WrapIntegral b = WrapIntegral (a P.- b) @@ -407,34 +430,64 @@ instance (P.Num a) => Group (WrapIntegral a) where {-# INLINE times #-} instance (P.Num a) => Multiplicative (WrapIntegral a) where + {-# SPECIALISE instance Multiplicative (WrapIntegral Int) #-} + {-# SPECIALISE instance Multiplicative (WrapIntegral Word) #-} + {-# SPECIALISE instance Multiplicative (WrapIntegral Integer) #-} WrapIntegral p * WrapIntegral q = WrapIntegral (p P.* q) {-# INLINE (*) #-} pow1p (WrapIntegral p) n = WrapIntegral (p P.^ (n + 1)) {-# INLINE pow1p #-} instance (P.Num a) => Unital (WrapIntegral a) where + {-# SPECIALISE instance Unital (WrapIntegral Int) #-} + {-# SPECIALISE instance Unital (WrapIntegral Word) #-} + {-# SPECIALISE instance Unital (WrapIntegral Integer) #-} one = WrapIntegral $ P.fromInteger 1 {-# INLINE one #-} pow (WrapIntegral a) n = WrapIntegral $ a P.^ n {-# INLINE pow #-} -instance P.Num a => Abelian (WrapIntegral a) -instance P.Num a => Semiring (WrapIntegral a) +instance P.Num a => Abelian (WrapIntegral a) where + {-# SPECIALISE instance Abelian (WrapIntegral Int) #-} + {-# SPECIALISE instance Abelian (WrapIntegral Word) #-} + {-# SPECIALISE instance Abelian (WrapIntegral Integer) #-} +instance P.Num a => Semiring (WrapIntegral a) where + {-# SPECIALISE instance Semiring (WrapIntegral Int) #-} + {-# SPECIALISE instance Semiring (WrapIntegral Word) #-} + {-# SPECIALISE instance Semiring (WrapIntegral Integer) #-} instance P.Num a => Rig (WrapIntegral a) where + {-# SPECIALISE instance Rig (WrapIntegral Int) #-} + {-# SPECIALISE instance Rig (WrapIntegral Word) #-} + {-# SPECIALISE instance Rig (WrapIntegral Integer) #-} fromNatural = WrapIntegral . P.fromIntegral {-# INLINE fromNatural #-} instance P.Num a => Ring (WrapIntegral a) where + {-# SPECIALISE instance Ring (WrapIntegral Int) #-} + {-# SPECIALISE instance Ring (WrapIntegral Word) #-} + {-# SPECIALISE instance Ring (WrapIntegral Integer) #-} fromInteger = WrapIntegral . P.fromInteger {-# INLINE fromInteger #-} -instance P.Num a => Commutative (WrapIntegral a) +instance P.Num a => Commutative (WrapIntegral a) where + {-# SPECIALISE instance Commutative (WrapIntegral Int) #-} + {-# SPECIALISE instance Commutative (WrapIntegral Word) #-} + {-# SPECIALISE instance Commutative (WrapIntegral Integer) #-} instance (P.Num a, Eq a) => DecidableZero (WrapIntegral a) where - isZero (WrapIntegral a) = a == 0 + {-# SPECIALISE instance DecidableZero (WrapIntegral Int) #-} + {-# SPECIALISE instance DecidableZero (WrapIntegral Word) #-} + {-# SPECIALISE instance DecidableZero (WrapIntegral Integer) #-} + isZero = (== 0) {-# INLINE isZero #-} -instance (Eq a, P.Integral a) => ZeroProductSemiring (WrapIntegral a) +instance (Eq a, P.Integral a) => ZeroProductSemiring (WrapIntegral a) where + {-# SPECIALISE instance ZeroProductSemiring (WrapIntegral Int) #-} + {-# SPECIALISE instance ZeroProductSemiring (WrapIntegral Word) #-} + {-# SPECIALISE instance ZeroProductSemiring (WrapIntegral Integer) #-} instance (Eq a, P.Integral a) => DecidableUnits (WrapIntegral a) where + {-# SPECIALISE instance DecidableUnits (WrapIntegral Int) #-} + {-# SPECIALISE instance DecidableUnits (WrapIntegral Word) #-} + {-# SPECIALISE instance DecidableUnits (WrapIntegral Integer) #-} isUnit (WrapIntegral r) = r == 1 || r == P.negate 1 {-# INLINE isUnit #-} @@ -445,16 +498,28 @@ instance (Eq a, P.Integral a) => DecidableUnits (WrapIntegral a) where {-# INLINE recipUnit #-} instance (Eq a, P.Integral a) => DecidableAssociates (WrapIntegral a) where + {-# SPECIALISE instance DecidableAssociates (WrapIntegral Int) #-} + {-# SPECIALISE instance DecidableAssociates (WrapIntegral Word) #-} + {-# SPECIALISE instance DecidableAssociates (WrapIntegral Integer) #-} isAssociate (WrapIntegral a) (WrapIntegral b) = P.abs a == P.abs b {-# INLINE isAssociate #-} instance (Eq a, P.Integral a) => UnitNormalForm (WrapIntegral a) where + {-# SPECIALISE instance UnitNormalForm (WrapIntegral Int) #-} + {-# SPECIALISE instance UnitNormalForm (WrapIntegral Word) #-} + {-# SPECIALISE instance UnitNormalForm (WrapIntegral Integer) #-} splitUnit (WrapIntegral 0) = (WrapIntegral 1, WrapIntegral 0) splitUnit (WrapIntegral a) = (WrapIntegral $ P.signum a, WrapIntegral $ P.abs a) {-# INLINE splitUnit #-} -instance (Eq a, P.Integral a) => IntegralDomain (WrapIntegral a) +instance (Eq a, P.Integral a) => IntegralDomain (WrapIntegral a) where + {-# SPECIALISE instance IntegralDomain (WrapIntegral Int) #-} + {-# SPECIALISE instance IntegralDomain (WrapIntegral Word) #-} + {-# SPECIALISE instance IntegralDomain (WrapIntegral Integer) #-} instance (Eq a, P.Integral a) => GCDDomain (WrapIntegral a) where + {-# SPECIALISE instance GCDDomain (WrapIntegral Int) #-} + {-# SPECIALISE instance GCDDomain (WrapIntegral Word) #-} + {-# SPECIALISE instance GCDDomain (WrapIntegral Integer) #-} gcd (WrapIntegral a) (WrapIntegral b) = WrapIntegral (P.gcd a b) {-# INLINE gcd #-} @@ -462,21 +527,51 @@ instance (Eq a, P.Integral a) => GCDDomain (WrapIntegral a) where {-# INLINE lcm #-} instance (Eq a, P.Integral a) => Euclidean (WrapIntegral a) where - divide (WrapIntegral f) (WrapIntegral g) = - let (q, r) = P.divMod f g - in (WrapIntegral q, WrapIntegral r) + {-# SPECIALISE instance Euclidean (WrapIntegral Int) #-} + {-# SPECIALISE instance Euclidean (WrapIntegral Integer) #-} + {-# SPECIALISE instance Euclidean (WrapIntegral Word) #-} + divide = coerce (P.divMod :: a -> a -> (a,a)) + {-# SPECIALISE INLINE divide + :: WrapIntegral Int -> WrapIntegral Int + -> (WrapIntegral Int, WrapIntegral Int) #-} + {-# SPECIALISE INLINE divide + :: WrapIntegral Integer -> WrapIntegral Integer + -> (WrapIntegral Integer, WrapIntegral Integer) #-} + {-# SPECIALISE INLINE divide + :: WrapIntegral Word -> WrapIntegral Word + -> (WrapIntegral Word, WrapIntegral Word) #-} {-# INLINE divide #-} + degree (WrapIntegral 0) = Nothing degree (WrapIntegral a) = Just $ P.fromIntegral (P.abs a) {-# INLINE degree #-} quot (WrapIntegral a) (WrapIntegral b) = WrapIntegral $ P.div a b + {-# SPECIALISE INLINE quot + :: WrapIntegral Int -> WrapIntegral Int -> WrapIntegral Int #-} + {-# SPECIALISE INLINE quot + :: WrapIntegral Integer -> WrapIntegral Integer -> WrapIntegral Integer #-} + {-# SPECIALISE INLINE quot + :: WrapIntegral Word -> WrapIntegral Word -> WrapIntegral Word #-} {-# INLINE quot #-} + rem (WrapIntegral a) (WrapIntegral b) = WrapIntegral $ P.mod a b + {-# SPECIALISE INLINE rem + :: WrapIntegral Int -> WrapIntegral Int -> WrapIntegral Int #-} + {-# SPECIALISE INLINE rem + :: WrapIntegral Integer -> WrapIntegral Integer -> WrapIntegral Integer #-} + {-# SPECIALISE INLINE rem + :: WrapIntegral Word -> WrapIntegral Word -> WrapIntegral Word #-} {-# INLINE rem #-} -instance (Eq a, P.Integral a) => PID (WrapIntegral a) -instance (Eq a, P.Integral a) => UFD (WrapIntegral a) +instance (Eq a, P.Integral a) => PID (WrapIntegral a) where + {-# SPECIALISE instance PID (WrapIntegral Int) #-} + {-# SPECIALISE instance PID (WrapIntegral Word) #-} + {-# SPECIALISE instance PID (WrapIntegral Integer) #-} +instance (Eq a, P.Integral a) => UFD (WrapIntegral a) where + {-# SPECIALISE instance UFD (WrapIntegral Int) #-} + {-# SPECIALISE instance UFD (WrapIntegral Word) #-} + {-# SPECIALISE instance UFD (WrapIntegral Integer) #-} -- | Turning types from @'Numeric.Algebra'@ into Prelude's Num instances. -- @@ -537,8 +632,11 @@ instance Euclidean a => P.Num (Fraction a) where instance Euclidean d => P.Fractional (Fraction d) where {-# SPECIALISE instance P.Fractional (Fraction Integer) #-} fromRational r = fromInteger' (P.numerator r) % fromInteger' (P.denominator r) + {-# INLINE fromRational #-} recip = NA.recip + {-# INLINE recip #-} (/) = (NA./) + {-# INLINE (/) #-} -- | @'Monoid'@ instances for @'Additive'@s. -- N.B. Unlike @'WrapNum'@, @'P.Num'@ instance is diff --git a/halg-core-test/opt-test/Inspection.hs b/halg-core-test/opt-test/Inspection.hs index 783854e7..10503b04 100644 --- a/halg-core-test/opt-test/Inspection.hs +++ b/halg-core-test/opt-test/Inspection.hs @@ -60,6 +60,20 @@ f59PowPrelude = (P.^) f59PowAlgebra :: F 59 -> Natural -> F 59 f59PowAlgebra = (NA.^) +f59RecipAlgebra :: F 59 -> F 59 +f59RecipAlgebra = (NA.recip) + +f59RecipPrelude :: F 59 -> F 59 +f59RecipPrelude = (P.recip) + +f59RecipManual :: WrapIntegral Int -> WrapIntegral Int +f59RecipManual = \k -> + let (_,_,r) = head $ euclid 59 k + in r `rem` 59 + +inspect $ coreOf 'f59RecipAlgebra +inspect $ coreOf 'f59RecipPrelude + f59ModPow :: WrapIntegral Int -> Natural -> WrapIntegral Int f59ModPow i n = modPow i 59 n @@ -133,6 +147,18 @@ main = hspec $ do it "doesn't contain modInteger operation" $ checkInspection $(inspectTest $ 'f59PowAlgebra `doesNotUse` 'modInteger) + describe ("NA.recip") $ do + it "doesn't contain type-classes" $ do + checkInspection $(inspectTest $ hasNoTypeClasses 'f59RecipAlgebra) + it "doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'f59RecipAlgebra `doesNotUse` 'SLT) + it "doesn't contain Int type" $ + checkInspection $(inspectTest $ 'f59RecipAlgebra `hasNoType` ''Integer) + it "doesn't contain modInteger operation" + $ checkInspection $(inspectTest $ 'f59RecipAlgebra `doesNotUse` 'modInteger) + it "has the same core as \\a -> euclid 59 a `mod` p" + $ checkInspection $(inspectTest $ 'f59RecipAlgebra ==- 'f59RecipManual) + describe ("optimisation for big prime (F " ++ show (natVal @LargeP Proxy) ++ ")") $ do describe "literal" $ do it "doesn't contain type-classes" diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 687f7b2e..f89282b1 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -3,6 +3,7 @@ {-# LANGUAGE MultiWayIf, PolyKinds, RankNTypes, ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell, TypeApplications, TypeFamilies #-} {-# LANGUAGE TypeOperators, UndecidableInstances, UndecidableSuperClasses #-} +{-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -fplugin Data.Singletons.TypeNats.Presburger #-} -- | Prime fields module Algebra.Field.Prime @@ -163,6 +164,38 @@ instance {-# OVERLAPPING #-} HasPrimeField Nat where SFalse -> F s) :: forall p. SingI (WORD_MAX_BOUND <=? p) => F (p :: Nat) + +minus :: IsPrimeChar p => F p -> F p -> F p +{-# INLINE minus #-} +{-# SPECIALISE INLINE minus + :: (KnownNat p, (WORD_MAX_BOUND <=? p) ~ 'False) + => F p -> F p -> F p + #-} +minus = liftBinF (P.-) + +mulP :: IsPrimeChar p => F p -> F p -> F p +{-# INLINE mulP #-} +{-# SPECIALISE INLINE mulP + :: (KnownNat p, (WORD_MAX_BOUND <=? p) ~ 'False) + => F p -> F p -> F p + #-} +mulP = liftBinF (P.*) + +plus :: IsPrimeChar p => F p -> F p -> F p +{-# INLINE plus #-} +{-# SPECIALISE INLINE plus + :: (KnownNat p, (WORD_MAX_BOUND <=? p) ~ 'False) + => F p -> F p -> F p + #-} +plus = liftBinF (P.+) + +negP :: IsPrimeChar p => F p -> F p +{-# INLINE negP #-} +{-# SPECIALISE INLINE negP + :: (KnownNat p, (WORD_MAX_BOUND <=? p) ~ 'False) + => F p -> F p #-} +negP = liftFUnary P.negate + instance HasPrimeField Type where type CharInfo n = Reifies n Integer charInfo_ = reflect @@ -217,19 +250,19 @@ instance IsPrimeChar p => Normed (F p) where instance IsPrimeChar p => P.Num (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => P.Num (F p) #-} - fromInteger = fromInteger' + fromInteger = modNat {-# INLINE fromInteger #-} - (+) = C.coerce ((P.+) :: WrapAlgebra (F p) -> WrapAlgebra (F p) -> WrapAlgebra (F p)) + (+) = plus {-# INLINE (+) #-} - (-) = C.coerce ((P.-) :: WrapAlgebra (F p) -> WrapAlgebra (F p) -> WrapAlgebra (F p)) + (-) = minus {-# INLINE (-) #-} - negate = C.coerce (P.negate :: WrapAlgebra (F p) -> WrapAlgebra (F p)) + negate = negP {-# INLINE negate #-} - (*) = C.coerce ((P.*) :: WrapAlgebra (F p) -> WrapAlgebra (F p) -> WrapAlgebra (F p)) + (*) = mulP {-# INLINE (*) #-} abs = id @@ -250,7 +283,7 @@ pows = flip $ \n -> unwrapF $ \a -> instance IsPrimeChar p => NA.Additive (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Additive (F p) #-} - (+) = liftBinF (P.+) + (+) = plus {-# INLINE (+) #-} sinnum1p n = liftFUnary $ \k -> (1 P.+ P.fromIntegral n) P.* k {-# INLINE sinnum1p #-} @@ -258,10 +291,10 @@ instance IsPrimeChar p => NA.Additive (F p) where instance IsPrimeChar p => NA.Multiplicative (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Multiplicative (F p) #-} - (*) = liftBinF (P.*) + (*) = mulP {-# INLINE (*) #-} - pow1p n p = pows n (p P.+ 1) + pow1p n = pows n . succ {-# INLINE pow1p #-} instance IsPrimeChar p => NA.Monoidal (F p) where @@ -301,17 +334,16 @@ instance IsPrimeChar p => NA.RightModule Integer (F p) where instance IsPrimeChar p => NA.Group (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Group (F p) #-} - (-) = liftBinF (P.-) + (-) = minus {-# INLINE (-) #-} - negate = liftFUnary P.negate + negate = negP {-# INLINE negate #-} - subtract = liftBinF P.subtract + subtract = flip minus {-# INLINE subtract #-} - times n = liftFUnary $ unwrapIntegral . - NA.times n . WrapIntegral + times n = liftFUnary (fromIntegral n P.*) {-# INLINE times #-} instance IsPrimeChar p => NA.Abelian (F p) @@ -351,11 +383,10 @@ instance IsPrimeChar p => DecidableUnits (F p) where isUnit = unwrapF (/= 0) {-# INLINE isUnit #-} - recipUnit = unwrapF $ \k -> - let p = WrapIntegral $ fromInteger $ charInfo @p Proxy - (u,_,r) = head $ euclid p (WrapIntegral k) - in if u == 1 - then Just $ wrapF $ fromIntegral $ unwrapIntegral $ r `rem` p else Nothing + recipUnit = \k -> + if k == 0 + then Nothing + else Just $ recip k {-# INLINE recipUnit #-} instance (IsPrimeChar p) => DecidableAssociates (F p) where @@ -376,7 +407,10 @@ instance (IsPrimeChar p) => Euclidean (F p) instance IsPrimeChar p => Division (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => Division (F p) #-} - recip = fromMaybe (error "recip: not unit") . recipUnit + recip = unwrapF $ \k -> + let p = WrapIntegral $ fromInteger $ charInfo @p Proxy + (_,_,r) = head $ euclid p (WrapIntegral k) + in wrapF_ $ fromIntegral $ r `rem` p {-# INLINE recip #-} a / b = a * recip b {-# INLINE (/) #-} From 6b14124e99c8a4a972251c3a5ca903da1fe65a1a Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 20:09:03 +0900 Subject: [PATCH 34/62] instance modification --- halg-core/src/Algebra/Field/Prime.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index f89282b1..65025349 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -422,14 +422,14 @@ instance IsPrimeChar p => Division (F p) where instance IsPrimeChar p => P.Fractional (F p) where {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) => P.Fractional (F p) #-} - (/) = C.coerce ((P./) :: WrapAlgebra (F p) -> WrapAlgebra (F p) -> WrapAlgebra (F p)) + (/) = (NA./) {-# INLINE (/) #-} fromRational r = modNat (R.numerator r) * recip (modNat $ R.denominator r) {-# INLINE fromRational #-} - recip = C.coerce (P.recip :: WrapAlgebra (F p) -> WrapAlgebra (F p)) + recip = NA.recip {-# INLINE recip #-} instance IsPrimeChar p => NA.Commutative (F p) From 33e086a6ed78b3f863ccf02834f17fc3e5768ebf Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 22:01:38 +0900 Subject: [PATCH 35/62] Adds euclidean benchmark --- .../factor-simple/integer-rep-new.csv | 47 +++++++++++++++++++ bench-results/factor-simple/succinct-new.csv | 47 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 bench-results/factor-simple/integer-rep-new.csv create mode 100644 bench-results/factor-simple/succinct-new.csv diff --git a/bench-results/factor-simple/integer-rep-new.csv b/bench-results/factor-simple/integer-rep-new.csv new file mode 100644 index 00000000..222ccf5a --- /dev/null +++ b/bench-results/factor-simple/integer-rep-new.csv @@ -0,0 +1,47 @@ +Name,Mean,MeanLB,MeanUB,Stddev,StddevLB,StddevUB +irreducible/F 2/2,3.570360771304021e-5,3.544240422611313e-5,3.60299789855077e-5,9.873860268847077e-7,7.893916348309927e-7,1.2156599104688837e-6 +irreducible/F 2/3,5.510282530035983e-5,5.471630613894476e-5,5.56366414607671e-5,1.4646759022948028e-6,1.0065261278262659e-6,2.08937844909733e-6 +irreducible/F 2/4,7.23257781361664e-5,7.19332543932266e-5,7.285662074066566e-5,1.5376033385408229e-6,1.2332062743117534e-6,2.1361697907404833e-6 +irreducible/F 2/5,9.954425794177229e-5,9.863564889933808e-5,1.0067187817453331e-4,3.4680352330679086e-6,2.507437341253104e-6,5.440066291473403e-6 +irreducible/F 2/20,1.96658456157507e-3,1.955922539093657e-3,1.9783566720264403e-3,3.7986990508804784e-5,3.000805032989176e-5,5.281913914034325e-5 +irreducible/F 59/2,7.179775663197276e-5,7.066273907460598e-5,7.43501825857972e-5,5.541268685351624e-6,2.124287919592129e-6,9.246160541385774e-6 +irreducible/F 59/3,1.600087620451669e-4,1.5935483318300244e-4,1.6125520460688543e-4,2.896981608837714e-6,1.983149924106845e-6,4.573833954328017e-6 +irreducible/F 59/4,3.131581040360241e-4,3.11618361411295e-4,3.1528662425075077e-4,6.362551950512464e-6,5.073027762885133e-6,8.463295159469987e-6 +irreducible/F 59/5,5.55179417638091e-4,5.529438587164127e-4,5.586760878694226e-4,9.727168332742041e-6,6.759794141886859e-6,1.5771989884077853e-5 +irreducible/F 12379/2,1.0247012351067303e-4,1.0188550213366403e-4,1.0328473125324216e-4,2.3552428867817473e-6,1.7297209049260155e-6,3.2245337507117373e-6 +irreducible/F 12379/3,2.611523027169032e-4,2.5992271384068453e-4,2.631875132298004e-4,5.36187341863343e-6,3.2055060923352426e-6,9.340092583667423e-6 +irreducible/F 12379/4,5.57326517161399e-4,5.545610278357486e-4,5.621930589548017e-4,1.220423190916298e-5,8.190363630502004e-6,1.843592069517166e-5 +irreducible/F 12379/5,9.879597932702456e-4,9.833143387637496e-4,9.930840052240853e-4,1.6927101129698375e-5,1.3795983292429458e-5,2.1544116836396202e-5 +irreducible/F 12379/20,5.6233873223278434e-2,5.572936833504273e-2,5.6632217476565744e-2,8.819794742729304e-4,7.10993723799107e-4,1.1463212049613338e-3 +irreducible/GF 2 5/degree 2,1.1550462380143765e-3,1.1489990604585524e-3,1.1646729542618083e-3,2.4851444374252015e-5,1.796316342396401e-5,3.368982334443184e-5 +irreducible/GF 2 5/degree 3,3.5236304095392058e-3,3.5031940941139448e-3,3.554209583046032e-3,7.948667119141017e-5,5.9821744030878394e-5,1.0883267573198383e-4 +irreducible/GF 2 5/degree 4,7.766318735585421e-3,7.711284435301006e-3,7.860537196897567e-3,2.0517093098283001e-4,1.4742558832954813e-4,3.4227459058763137e-4 +irreducible/GF 2 5/degree 5,1.3428644976328286e-2,1.3325633032544672e-2,1.3580975705917668e-2,3.2982160423849366e-4,2.4753719875307e-4,4.0774566375493854e-4 +irreducible/GF 2 5/degree 20,0.7353310105153175,0.7326050668461905,0.7383567580727778,4.784523105202509e-3,3.3603582633461577e-3,7.18441466081063e-3 +product of polynomials of degree one/F 59/factors 5,2.7945153405044233e-4,2.77760064314247e-4,2.8218083612537807e-4,7.0165522055354595e-6,5.281252197478781e-6,1.1272496433459441e-5 +product of polynomials of degree one/F 59/factors 10,1.0909964840380719e-3,1.0861824012219686e-3,1.0971348585350218e-3,1.8529514711612922e-5,1.5528622670822355e-5,2.2609327171062228e-5 +product of polynomials of degree one/F 59/factors 20,1.750928620460106e-3,1.7369266437957482e-3,1.7740127049103327e-3,6.0491898253126496e-5,3.750652689372537e-5,9.158486560901484e-5 +product of polynomials of degree one/F 59/factors 50,6.7011488030450225e-3,6.6652665077882e-3,6.748362414058223e-3,1.2139002707348506e-4,9.97693360618588e-5,1.4956854570570297e-4 +product of polynomials of degree one/F 59/factors 100,1.8858779012933324e-2,1.871731481500209e-2,1.9002490355240133e-2,3.437988350907675e-4,2.8836574517834975e-4,4.2085568705157165e-4 +product of polynomials of degree one/F 12379/factors 5,7.908433124309735e-4,7.869872829561638e-4,7.955143728036893e-4,1.3937675630049593e-5,1.1701403863931635e-5,1.7930967870682583e-5 +product of polynomials of degree one/F 12379/factors 10,2.1382427062143793e-3,2.1273352625515926e-3,2.159009641534148e-3,4.8218616510558125e-5,3.3547007959038724e-5,7.980026716659558e-5 +product of polynomials of degree one/F 12379/factors 20,7.0098699844588054e-3,6.947704385700996e-3,7.119189783120668e-3,2.361183071634196e-4,1.617556289836127e-4,3.832572700274657e-4 +product of polynomials of degree one/F 12379/factors 50,0.1021405477423016,0.10087448303444443,0.10516692412999999,3.082671029911737e-3,1.0727698658551297e-3,4.993678671533935e-3 +product of polynomials of degree one/F 12379/factors 100,0.35826412825115084,0.35669732732638887,0.36036035368095237,3.190452631944996e-3,2.2885409921462175e-3,4.324370523169414e-3 +product of polynomials of degree one/GF 2 5/factors 5,2.703936082164327e-3,2.6871902344745018e-3,2.7283458461836527e-3,7.170465833049564e-5,5.091564978319378e-5,9.804133878301483e-5 +product of polynomials of degree one/GF 2 5/factors 10,1.5367005922813365e-2,1.5213424094167545e-2,1.566250858083797e-2,5.134949511061674e-4,3.0556009128831184e-4,8.613183598057203e-4 +product of polynomials of degree one/GF 2 5/factors 20,4.999565697896171e-2,4.9649073292737225e-2,5.056977202678571e-2,8.493429238991406e-4,5.860664922585023e-4,1.213531249090757e-3 +product of polynomials of degree one/GF 2 5/factors 50,0.10221447263337302,0.10152410337373016,0.10292486006444443,1.229821043067587e-3,7.895898436888788e-4,1.9536632280289876e-3 +randomly generated polynomials/F 2/degree 5,8.081591434614316e-5,8.037659986211832e-5,8.149408627443859e-5,1.879698987350442e-6,1.5097684900438634e-6,2.437624264991005e-6 +randomly generated polynomials/F 2/degree 10,1.6559449344411868e-4,1.6473932326899643e-4,1.670546078532041e-4,3.712680507572183e-6,2.8895955580257274e-6,5.3865957094613244e-6 +randomly generated polynomials/F 2/degree 50,2.7885439907608264e-2,2.7637975175106168e-2,2.8177339676528603e-2,5.865047797123461e-4,4.2070683833493605e-4,7.746144573546426e-4 +randomly generated polynomials/F 2/degree 100,0.16546817668825398,0.16420362567142857,0.1677557722311111,2.8291790896603788e-3,1.164742724486042e-3,4.221053070599991e-3 +randomly generated polynomials/F 59/degree 5,3.380638607638257e-4,3.360686224399812e-4,3.4033490824347465e-4,7.303284709385708e-6,6.161043946164882e-6,9.268516409027075e-6 +randomly generated polynomials/F 59/degree 10,1.3559838934248637e-3,1.3478685197588736e-3,1.3652501182758775e-3,3.0243177376587137e-5,2.5117247034599872e-5,3.9922885552500255e-5 +randomly generated polynomials/F 59/degree 50,0.3337248188359127,0.3307645220628571,0.3372772769661905,5.583252028099677e-3,4.209800836904338e-3,7.339442301915286e-3 +randomly generated polynomials/F 12379/degree 5,4.756691594526751e-4,4.724744913552097e-4,4.814364973968647e-4,1.3542618846397172e-5,9.061646469758918e-6,2.443459060376066e-5 +randomly generated polynomials/F 12379/degree 10,2.9851311400912236e-3,2.970012768098193e-3,3.0039809378395103e-3,5.605114301857877e-5,4.194279194177524e-5,7.196376597189469e-5 +randomly generated polynomials/F 12379/degree 50,0.5090215944968254,0.5067757062007143,0.5122446974104762,4.504322761769863e-3,2.2042711659543235e-3,5.915760675391901e-3 +randomly generated polynomials/GF 2 5/degree 5,1.1683872379831416e-2,1.159667182229899e-2,1.1787254197941325e-2,2.5769594818919324e-4,2.1922028157272567e-4,3.104156912623136e-4 +randomly generated polynomials/GF 2 5/degree 10,3.9932990986735487e-2,3.8556914334798534e-2,4.438935143559461e-2,4.626394391397771e-3,6.62161263227129e-4,8.466208757869553e-3 +randomly generated polynomials/GF 2 5/degree 25,0.3773316780274206,0.37524038685333333,0.38007457774992065,3.8448920444698644e-3,2.4419859360137143e-3,5.8708480223780835e-3 diff --git a/bench-results/factor-simple/succinct-new.csv b/bench-results/factor-simple/succinct-new.csv new file mode 100644 index 00000000..86b7944a --- /dev/null +++ b/bench-results/factor-simple/succinct-new.csv @@ -0,0 +1,47 @@ +Name,Mean,MeanLB,MeanUB,Stddev,StddevLB,StddevUB +irreducible/F 2/2,4.483878266268493e-5,4.416643992303832e-5,4.595726013694892e-5,3.0551899925252097e-6,1.7226871466382537e-6,4.552805659666285e-6 +irreducible/F 2/3,6.928588587510005e-5,6.869553472579677e-5,7.029930692478516e-5,2.7239235390405884e-6,1.8841327633151613e-6,4.1754038882554164e-6 +irreducible/F 2/4,9.236881268425528e-5,9.0857720065004e-5,9.566802088290579e-5,6.547305682050335e-6,3.1112937484715356e-6,1.0851412554937598e-5 +irreducible/F 2/5,1.27636240473337e-4,1.2636874546047706e-4,1.293472817475927e-4,5.0413657542582085e-6,3.4044251161078718e-6,6.814393092701126e-6 +irreducible/F 2/20,2.9932833755950505e-3,2.961310685114611e-3,3.06525061326602e-3,1.5332735283286048e-4,6.10900753185394e-5,2.713137778109702e-4 +irreducible/F 59/2,5.7767509418979863e-5,5.728812819847188e-5,5.8544253510127706e-5,1.978573656891714e-6,1.352270584764411e-6,2.76172085865372e-6 +irreducible/F 59/3,1.2721057944875213e-4,1.2582470848383615e-4,1.3060890759228542e-4,6.933785826520979e-6,4.271666518101984e-6,1.182944275810903e-5 +irreducible/F 59/4,2.391277334961264e-4,2.3724730131927224e-4,2.4344825974730312e-4,9.222843879317395e-6,6.476748950120256e-6,1.5307667972340063e-5 +irreducible/F 59/5,4.18350460041483e-4,4.136466067722218e-4,4.258930200432607e-4,2.0261029334004516e-5,1.5140156806678301e-5,2.686046597180196e-5 +irreducible/F 12379/2,8.14189653717544e-5,8.053160271137661e-5,8.295385441528511e-5,3.741526987685697e-6,2.660522446482232e-6,5.351650636306859e-6 +irreducible/F 12379/3,1.982769902182404e-4,1.964185521493655e-4,2.0112310056867371e-4,7.850245825336528e-6,5.473256414146418e-6,1.0788224443271078e-5 +irreducible/F 12379/4,4.0822063239187453e-4,4.0434806526043997e-4,4.1728733336654093e-4,1.7923024604554377e-5,9.970043153737878e-6,3.1692145089023153e-5 +irreducible/F 12379/5,7.232466748024385e-4,7.161016028590778e-4,7.344147162136847e-4,2.987695368242231e-5,2.0418364519458082e-5,4.0645932467459e-5 +irreducible/F 12379/20,4.0360940446640424e-2,4.002600362141158e-2,4.114692545136522e-2,1.043822629833654e-3,4.731734738814054e-4,1.8931737784534633e-3 +irreducible/GF 2 5/degree 2,2.486927415033284e-3,2.452362613383082e-3,2.5569656544836036e-3,1.54262612072831e-4,5.896829115807094e-5,2.409681463342162e-4 +irreducible/GF 2 5/degree 3,7.561093141108224e-3,7.47501603036353e-3,7.699183997540801e-3,3.159767666649861e-4,2.200327153031604e-4,4.6086330221474937e-4 +irreducible/GF 2 5/degree 4,1.720315217110044e-2,1.6956294637068475e-2,1.7672012123355577e-2,8.737948881330611e-4,3.768815699049429e-4,1.2725351884153267e-3 +irreducible/GF 2 5/degree 5,2.9684087627413116e-2,2.9370342285363435e-2,3.0441765997009936e-2,1.0053278326706812e-3,5.6954434272815e-4,1.7533549695909882e-3 +irreducible/GF 2 5/degree 20,1.6040137471524207,1.5897950856687302,1.6569997629725002,4.196513104010069e-2,2.527031373533238e-3,7.030249769834535e-2 +product of polynomials of degree one/F 59/factors 5,2.2895468589085235e-4,2.2625566963042397e-4,2.3224526496673633e-4,1.0200312765017524e-5,7.458016651152605e-6,1.3126223869043216e-5 +product of polynomials of degree one/F 59/factors 10,8.683836111287402e-4,8.568474045313006e-4,8.891421189180215e-4,5.106508823597057e-5,3.079118957078516e-5,7.915953496859685e-5 +product of polynomials of degree one/F 59/factors 20,1.3614796209357866e-3,1.3426288886225378e-3,1.3918759624935216e-3,8.066723338616858e-5,5.1222678872012586e-5,1.162579584662306e-4 +product of polynomials of degree one/F 59/factors 50,5.21936056787801e-3,5.123535433071565e-3,5.345682208668091e-3,3.4624365717356116e-4,2.4124993675123734e-4,4.6585672425353817e-4 +product of polynomials of degree one/F 59/factors 100,1.6838794000423773e-2,1.6456914728074534e-2,1.7404333325267484e-2,1.192381056763154e-3,9.791036880687153e-4,1.475225279131405e-3 +product of polynomials of degree one/F 12379/factors 5,6.846953458215472e-4,6.769537604985353e-4,6.992159812419921e-4,3.426791697660611e-5,2.2891846685162836e-5,5.1253136366800575e-5 +product of polynomials of degree one/F 12379/factors 10,1.6894063695433387e-3,1.663339920784447e-3,1.7203778675003408e-3,9.614328764998835e-5,7.89365799139586e-5,1.264339313388912e-4 +product of polynomials of degree one/F 12379/factors 20,5.1775423629900315e-3,5.126047539285693e-3,5.253315109546575e-3,1.899935753913066e-4,1.3508383042988765e-4,2.840268432780954e-4 +product of polynomials of degree one/F 12379/factors 50,7.676143787187786e-2,7.544868385149218e-2,8.026832789343435e-2,3.516847229642631e-3,1.3149252701377939e-3,5.7334813090756664e-3 +product of polynomials of degree one/F 12379/factors 100,0.2712782265086111,0.2679641409394445,0.28095004777666666,9.652130156326138e-3,1.3244982106566348e-3,1.6234104678602063e-2 +product of polynomials of degree one/GF 2 5/factors 5,5.786236287410383e-3,5.712811041777309e-3,5.930325274887435e-3,3.1041026187087086e-4,1.7516231151039918e-4,5.532980150674494e-4 +product of polynomials of degree one/GF 2 5/factors 10,3.321842308122885e-2,3.26957265052718e-2,3.464650029710186e-2,1.7661504860265163e-3,6.350531789302784e-4,3.2857650077687253e-3 +product of polynomials of degree one/GF 2 5/factors 20,0.11018512950277777,0.10869800044333333,0.11146266721666667,2.3463584878942478e-3,1.62363458119511e-3,3.460538084035391e-3 +product of polynomials of degree one/GF 2 5/factors 50,0.22063491581099207,0.21856111811555556,0.22472717090476188,4.963320613923196e-3,2.356688347277968e-3,7.574866103783916e-3 +randomly generated polynomials/F 2/degree 5,1.057727524894183e-4,1.0457766309203462e-4,1.0757960862013794e-4,5.033265825147623e-6,3.698524147533896e-6,8.155975719641567e-6 +randomly generated polynomials/F 2/degree 10,2.2230673864706094e-4,2.1974366773442878e-4,2.2785678534915522e-4,1.1909647916924703e-5,7.881257356941743e-6,1.9753781015569043e-5 +randomly generated polynomials/F 2/degree 50,4.6832394728492245e-2,4.60645458237037e-2,4.813940742391534e-2,2.019883833040445e-3,1.147250347228251e-3,3.135815806009859e-3 +randomly generated polynomials/F 2/degree 100,0.2986387333461905,0.296265179772381,0.30517845978,6.378443437934314e-3,2.39884555570616e-3,1.0042543792624741e-2 +randomly generated polynomials/F 59/degree 5,2.549960927379614e-4,2.524089376469672e-4,2.6034353240150966e-4,1.1943030256640144e-5,6.196432401599756e-6,2.2132566083225655e-5 +randomly generated polynomials/F 59/degree 10,1.0195986787858247e-3,1.0027265186176356e-3,1.0532132778051351e-3,7.807680985269726e-5,5.10341178446865e-5,1.0923190235892558e-4 +randomly generated polynomials/F 59/degree 50,0.24776341269619045,0.24608647037571427,0.2520043797490476,4.526839065654841e-3,1.097398220548699e-3,7.470924862014446e-3 +randomly generated polynomials/F 12379/degree 5,3.571358462734534e-4,3.531313575652858e-4,3.6340148538137627e-4,1.6112105435967873e-5,1.1670195424618204e-5,2.509261949488737e-5 +randomly generated polynomials/F 12379/degree 10,2.164182668672008e-3,2.1429633544627308e-3,2.1957912685782624e-3,9.011985687396417e-5,6.26750367654746e-5,1.2284037818596378e-4 +randomly generated polynomials/F 12379/degree 50,0.387784667669246,0.38358566521781745,0.3952198134416667,9.086582808032885e-3,5.5278787813081475e-3,1.4187111232189483e-2 +randomly generated polynomials/GF 2 5/degree 5,2.5209675798245026e-2,2.492659019377552e-2,2.5618894346518636e-2,7.51690747638736e-4,5.650336706235564e-4,9.384741446270037e-4 +randomly generated polynomials/GF 2 5/degree 10,8.418105123289388e-2,8.333828174155188e-2,8.639096103187721e-2,2.254634147362824e-3,1.0004929914127674e-3,3.641495099849744e-3 +randomly generated polynomials/GF 2 5/degree 25,0.8257292048773015,0.8161171942011111,0.8541149260299999,2.7362206188906286e-2,4.091054059132848e-3,4.525103946892865e-2 From 36f954df1e4f7c03e6aa596e0e2ead3f37ea9498 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 23:25:38 +0900 Subject: [PATCH 36/62] More efficient repeatedSquare without internal representation --- halg-core/package.yaml | 1 + halg-core/src/Algebra/Arithmetic.hs | 39 ++++++++++++++++------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/halg-core/package.yaml b/halg-core/package.yaml index 446e5fa3..3e16ab28 100644 --- a/halg-core/package.yaml +++ b/halg-core/package.yaml @@ -67,6 +67,7 @@ library: source-dirs: src dependencies: - template-haskell + - integer-logarithms ghc-options: ["-Wall", "-O2"] benchmarks: diff --git a/halg-core/src/Algebra/Arithmetic.hs b/halg-core/src/Algebra/Arithmetic.hs index dbe410e3..27c4f920 100644 --- a/halg-core/src/Algebra/Arithmetic.hs +++ b/halg-core/src/Algebra/Arithmetic.hs @@ -1,30 +1,33 @@ -{-# LANGUAGE NoImplicitPrelude, NoMonomorphismRestriction #-} +{-# LANGUAGE BangPatterns, NoImplicitPrelude, NoMonomorphismRestriction #-} module Algebra.Arithmetic (repeatedSquare, modPow, fermatTest, isPseudoPrime ) where -import AlgebraicPrelude hiding (div, mod) -import Control.Lens ((&), (+~), _1) -import Control.Monad.Random (MonadRandom, uniform) -import Data.List (elemIndex) -import Numeric.Decidable.Zero (isZero) -import Numeric.Domain.Euclidean () -import Prelude (div, mod) -import qualified Prelude as P +import AlgebraicPrelude hiding (div, mod) +import Control.Lens ((&), (+~), _1) +import Control.Monad.Random (MonadRandom, uniform) +import Data.Bits +import Data.List (elemIndex) +import Math.NumberTheory.Logarithms +import Numeric.Decidable.Zero (isZero) +import Numeric.Domain.Euclidean () +import Prelude (div, mod) +import qualified Prelude as P data PrimeResult = Composite | ProbablyPrime | Prime deriving (Read, Show, Eq, Ord) -- | Calculates @n@-th power efficiently, using repeated square method. -repeatedSquare :: Multiplicative r => r -> Natural -> r -repeatedSquare a n = - let bits = tail $ binRep n - in foldl (\b nk -> if nk == 1 then b * b * a else b * b) a bits - -binRep :: Natural -> [Natural] -binRep = flip go [] +repeatedSquare :: Unital r => r -> Natural -> r +repeatedSquare a n + | n == 0 = one + | otherwise = go (naturalLog2 n - 1) a where - go 0 = id - go k = go (k `div` 2) . ((k `mod` 2) :) + go !k !acc + | k < 0 = acc + | otherwise = go (k - 1) $ + if testBit n k + then acc*acc*a + else acc*acc -- | Fermat-test for pseudo-primeness. fermatTest :: MonadRandom m => Integer -> m PrimeResult From b53094f5410430937b514b7019105d34691fd139 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 23:52:35 +0900 Subject: [PATCH 37/62] Stop providing custom repeatedSquare --- halg-core/src/Algebra/Arithmetic.hs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/halg-core/src/Algebra/Arithmetic.hs b/halg-core/src/Algebra/Arithmetic.hs index 27c4f920..6baee293 100644 --- a/halg-core/src/Algebra/Arithmetic.hs +++ b/halg-core/src/Algebra/Arithmetic.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE BangPatterns, NoImplicitPrelude, NoMonomorphismRestriction #-} +{-# LANGUAGE NoImplicitPrelude, NoMonomorphismRestriction #-} module Algebra.Arithmetic (repeatedSquare, modPow, fermatTest, isPseudoPrime ) where @@ -18,16 +18,7 @@ data PrimeResult = Composite | ProbablyPrime | Prime -- | Calculates @n@-th power efficiently, using repeated square method. repeatedSquare :: Unital r => r -> Natural -> r -repeatedSquare a n - | n == 0 = one - | otherwise = go (naturalLog2 n - 1) a - where - go !k !acc - | k < 0 = acc - | otherwise = go (k - 1) $ - if testBit n k - then acc*acc*a - else acc*acc +repeatedSquare = pow -- | Fermat-test for pseudo-primeness. fermatTest :: MonadRandom m => Integer -> m PrimeResult From 4b9529c3037ef6c008c586586d5844078750973c Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 23:52:53 +0900 Subject: [PATCH 38/62] Import list refactoring --- halg-core/src/Algebra/Field/Prime.hs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 65025349..818315c2 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -23,12 +23,10 @@ import Algebra.Ring.Polynomial.Class (PrettyCoeff (..), ShowSCoeff (..)) import AlgebraicPrelude import Control.DeepSeq (NFData (..)) -import Control.Monad.Random (getRandomR, uniform) +import Control.Monad.Random (getRandomR) import Control.Monad.Random (runRand) import Control.Monad.Random (Random (..)) -import qualified Data.Coerce as C import Data.Kind (Constraint, Type) -import Data.Maybe (fromMaybe) import Data.Proxy (Proxy (..), asProxyTypeOf) import qualified Data.Ratio as R import Data.Reflection (Reifies (reflect), reifyNat) From 5b85fdb4c0ae1b281819c6c0a315926b62b37f07 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 11 Jul 2020 23:52:59 +0900 Subject: [PATCH 39/62] More inspection testing --- halg-core-test/opt-test/Inspection.hs | 33 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/halg-core-test/opt-test/Inspection.hs b/halg-core-test/opt-test/Inspection.hs index 10503b04..976fd1d6 100644 --- a/halg-core-test/opt-test/Inspection.hs +++ b/halg-core-test/opt-test/Inspection.hs @@ -41,6 +41,16 @@ f59AddManual :: Int -> Int -> Int f59AddManual = \l r -> (l + r) `mod` 59 +f59MulPrelude :: F 59 -> F 59 -> F 59 +f59MulPrelude = (P.*) + +f59MulAlgebra :: F 59 -> F 59 -> F 59 +f59MulAlgebra = (NA.*) + +f59MulManual :: Int -> Int -> Int +f59MulManual = \l r -> + (l * r) `mod` 59 + fLargeAddPrelude :: F LargeP -> F LargeP -> F LargeP fLargeAddPrelude = (P.+) @@ -71,9 +81,6 @@ f59RecipManual = \k -> let (_,_,r) = head $ euclid 59 k in r `rem` 59 -inspect $ coreOf 'f59RecipAlgebra -inspect $ coreOf 'f59RecipPrelude - f59ModPow :: WrapIntegral Int -> Natural -> WrapIntegral Int f59ModPow i n = modPow i 59 n @@ -122,6 +129,22 @@ main = hspec $ do $ checkInspection $(inspectTest $ 'f59AddAlgebra `doesNotUse` 'modInteger) it "has the same core as \\a b -> (a + b) `mod` 59" $ checkInspection $(inspectTest $ 'f59AddAlgebra ==- 'f59AddManual) + + describe "(Prelude.*)" $ do + it "has the same core representation as (NA.*) modulo casting" $ + checkInspection $(inspectTest $ 'f59MulPrelude ==- 'f59MulAlgebra) + describe "(NA.*)" $ do + it "doesn't contain type-classes" $ do + checkInspection $(inspectTest $ hasNoTypeClasses 'f59MulAlgebra) + it "doesn't contain type-natural comparison" + $ checkInspection $(inspectTest $ 'f59MulAlgebra `doesNotUse` 'SLT) + it "doesn't contain Integer type" $ + checkInspection $(inspectTest $ 'f59MulAlgebra `hasNoType` ''Integer) + it "doesn't contain modInteger operation" + $ checkInspection $(inspectTest $ 'f59MulAlgebra `doesNotUse` 'modInteger) + it "has the same core as \\a b -> (a * b) `mod` 59" + $ checkInspection $(inspectTest $ 'f59MulAlgebra ==- 'f59MulManual) + describe "productSum" $ do it "doesn't contain type-classes" $ checkInspection $(inspectTest $ hasNoTypeClasses 'f59ProductSum) @@ -148,8 +171,8 @@ main = hspec $ do $ checkInspection $(inspectTest $ 'f59PowAlgebra `doesNotUse` 'modInteger) describe ("NA.recip") $ do - it "doesn't contain type-classes" $ do - checkInspection $(inspectTest $ hasNoTypeClasses 'f59RecipAlgebra) + it "doesn't contain type-classes except IntegralDomain and UnitNormalForm" $ do + checkInspection $(inspectTest $ 'f59RecipAlgebra `hasNoTypeClassesExcept` [''IntegralDomain, ''UnitNormalForm]) it "doesn't contain type-natural comparison" $ checkInspection $(inspectTest $ 'f59RecipAlgebra `doesNotUse` 'SLT) it "doesn't contain Int type" $ From c135e1a1780344c525d889dbd37218d61c5810ff Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sun, 12 Jul 2020 00:52:06 +0900 Subject: [PATCH 40/62] Flag changes --- computational-algebra/package.yaml | 3 --- stack-prof.yaml | 5 ++--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/computational-algebra/package.yaml b/computational-algebra/package.yaml index f270eee4..325f2113 100644 --- a/computational-algebra/package.yaml +++ b/computational-algebra/package.yaml @@ -101,11 +101,8 @@ _profile-cond: &profile-cond else: buildable: false ghc-options: - - -caf-all - - -auto-all - -rtsopts - -eventlog - - -prof _examples: &examples algebraic: diff --git a/stack-prof.yaml b/stack-prof.yaml index 884d5b8e..bb003177 100644 --- a/stack-prof.yaml +++ b/stack-prof.yaml @@ -12,11 +12,10 @@ build: executable-profiling: true library-profiling: true -apply-ghc-options: everything rebuild-ghc-options: true ghc-options: - "$everything": -fno-prof-auto - "$locals": -fno-prof-auto + "$everything": -fno-prof-auto -fno-prof-cafs + "$locals": -fno-prof-auto -fno-prof-cafs packages: - 'computational-algebra' From a3a80f31855f0a224afe50ded8ab70746aeece5b Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sun, 12 Jul 2020 00:52:30 +0900 Subject: [PATCH 41/62] Corrects profiling flag --- halg-factor/package.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/halg-factor/package.yaml b/halg-factor/package.yaml index bd6cb4e5..337c338e 100644 --- a/halg-factor/package.yaml +++ b/halg-factor/package.yaml @@ -57,6 +57,14 @@ library: executables: factor-deg50-prof: + when: + - condition: flag(profile) + then: + buildable: true + ghc-options: + - -fno-prof-auto + else: + buildable: false source-dirs: app ghc-options: - -Wall From 296d4ed8f983f232a5642073014c58701e8f877b Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sun, 12 Jul 2020 00:52:42 +0900 Subject: [PATCH 42/62] More profiling cases --- halg-factor/app/factor-deg50-prof.hs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/halg-factor/app/factor-deg50-prof.hs b/halg-factor/app/factor-deg50-prof.hs index 2cae5bbd..fd43c457 100644 --- a/halg-factor/app/factor-deg50-prof.hs +++ b/halg-factor/app/factor-deg50-prof.hs @@ -29,6 +29,7 @@ f59_rand_deg50 :: Unipol (F 59) f59_rand_deg50 = randomPoly (-3071815209415553516) Proxy 100 + main :: IO () main = getArgs >>= \case ["2"] -> void $ evaluate $ withSeed 6147031469590640211 @@ -37,8 +38,12 @@ main = getArgs >>= \case $ factorise f59_rand_deg100 ["2", "100"] -> void $ evaluate $ withSeed 6147031469590640211 $ factorise f2_rand_deg100 + ["2", "ones"] -> void $ evaluate $ withSeed 6147031469590640211 + $ factorise f2_degOnes_deg100 ["59", "100"] -> void $ evaluate $ withSeed 7650165946084592722 $ factorise f59_rand_deg100 + ["59", "ones"] -> void $ evaluate $ withSeed 7650165946084592722 + $ factorise f59_degOnes_deg100 _ -> error "Arguments must be one of 2 or 59" f2_rand_deg100 :: Unipol (F 2) @@ -48,3 +53,23 @@ f2_rand_deg100 = f59_rand_deg100 :: Unipol (F 59) f59_rand_deg100 = randomPoly (-3354538193028255891) Proxy 100 + +f59_degOnes_deg100 :: Unipol (F 59) +f59_degOnes_deg100 = + product $ + map ((#x -) . injectCoeff) + [37,6,34,47,11,44,44,35,27,22,5 + ,13,45,32,4,11,51,20,45,4,5,0,34 + ,49,50,3,46,13,41,56,2,11,11,3,14 + ,3,58,55,18,27,4,8,44,28,28,37,7,9 + ,58,56,41,37,8,19,45,54,44,31,56 + ,57,43,37,2,7,5,38,54,15,44,22,8 + ,58,7,11,0,48,20,11,3,52,31 + ,34,37,23,56,12,3,23,42 + ,19,4,23,32,23,14,29,37,32,31,32] + +f2_degOnes_deg100 :: Unipol (F 2) +f2_degOnes_deg100 = + product $ + map ((#x -) . injectCoeff) + [0,0,1,0,0,1,1,1,0,1,0,0,0,1,0,0,1,1,0,1,1,0,1,0,1,0,1,1,1,1,1,1,0,0,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,0,1,0,0,1,0,1,1,0,1,1,1,1,1,1,1,0,0,1,0,1,1,1,1,1,1,1,0,1,1,0,0,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0] From 08bcf8903e7bf4a19ed2f6b4a52f98ff5b9d2cf5 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 18 Jul 2020 21:33:52 +0900 Subject: [PATCH 43/62] Instance unification --- halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs | 3 --- 1 file changed, 3 deletions(-) diff --git a/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs b/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs index 624b9cfa..f0dda830 100644 --- a/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs +++ b/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs @@ -82,9 +82,6 @@ regressions = ξ :: GF 2 5 ξ = primitive -instance IsPrimeChar n => Arbitrary (F n) where - arbitrary = QC.elements $ Fin.elements $ Proxy @(F n) - instance (IsPrimeChar p, KnownNat n, ConwayPolynomial p n) => Arbitrary (GF p n) where arbitrary = QC.elements $ Fin.elements $ Proxy @(GF p n) From c15aa60cb4998ca8dde74faf3bbe4c50c5ce9879 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 18 Jul 2020 22:15:50 +0900 Subject: [PATCH 44/62] Removes duplicates --- stack-804.yaml | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/stack-804.yaml b/stack-804.yaml index d910e440..6f961cc2 100644 --- a/stack-804.yaml +++ b/stack-804.yaml @@ -17,24 +17,23 @@ packages: - 'halg-polynomials' extra-deps: +- arithmoi-0.9.0.0 - control-monad-loop-0.1 - equational-reasoning-0.5.1.0 +- exact-pi-0.5.0.1 - ghc-typelits-presburger-0.3.0.0 -- singletons-presburger-0.3.0.0 -- sized-0.3.0.0 -- type-natural-0.8.1.0 -- arithmoi-0.9.0.0 -- unamb-0.2.7 -- parser-combinators-1.1.0 +- hspec-2.6.1 +- hspec-core-2.6.1 +- hspec-discover-2.6.1 +- inspection-testing-0.4.2.4 - megaparsec-7.0.5 -- arithmoi-0.9.0.0 -- exact-pi-0.5.0.1 -- semirings-0.5.3 +- parser-combinators-1.1.0 - QuickCheck-2.12.6.1 -- hspec-core-2.6.1 +- quickcheck-instances-0.3.19 - repa-3.4.1.4 - repa-algorithms-3.4.1.3 -- quickcheck-instances-0.3.19 -- hspec-2.6.1 -- hspec-discover-2.6.1 -- inspection-testing-0.4.2.4 +- semirings-0.5.3 +- singletons-presburger-0.3.0.0 +- sized-0.3.0.0 +- type-natural-0.8.1.0 +- unamb-0.2.7 From 0e902d95914706765ba77a6a7814cfb67f56abd5 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sat, 18 Jul 2020 22:17:02 +0900 Subject: [PATCH 45/62] 8.10 fix --- halg-core/src/Algebra/Field/Prime.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index bf181b68..5312e5b5 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -215,7 +215,7 @@ modNat :: IsPrimeChar (p :: k) => Integer -> F p modNat = modNat' Proxy {-# INLINE modNat #-} -modNat' :: forall proxy (p :: k). IsPrimeChar p => proxy (F p) -> Integer -> F p +modNat' :: forall proxy p. IsPrimeChar p => proxy (F p) -> Integer -> F p modNat' _ i = wrapF $ let p = charInfo (Proxy :: Proxy p) in unwrapIntegral $ fromInteger i `rem` fromInteger p From 075ef7e295498e42284b559962b3cb76b75a4d03 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 23 Jul 2020 17:40:27 +0900 Subject: [PATCH 46/62] Kind signature (I don't understand why this needed for GHC 8.10 --- halg-core/src/Algebra/Field/Prime.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 5312e5b5..5c88d7e2 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -54,7 +54,7 @@ type WORD_MAX_BOUND = $ sqrt $ fromIntegral $ maxBound @Int) type F' (p :: k) = F_Aux k p type family F_Aux (k :: Type) (p :: k) where - F_Aux Nat p = + F_Aux Nat (p :: Nat) = F_Nat_Aux (WORD_MAX_BOUND <=? p) F_Aux k p = Integer From 3bee94356e6299a86caf1881f37af95bef2fadb4 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 23 Jul 2020 17:53:12 +0900 Subject: [PATCH 47/62] StandaloneKindSignatures for F_Aux --- halg-core/src/Algebra/Field/Prime.hs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 5c88d7e2..6b9a6b52 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -1,4 +1,8 @@ -{-# LANGUAGE DataKinds, DerivingStrategies, FlexibleContexts #-} +#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 810 +{-# LANGUAGE StandaloneKindSignatures #-} +#endif + +{-# LANGUAGE CPP, DataKinds, DerivingStrategies, FlexibleContexts #-} {-# LANGUAGE FlexibleInstances, GADTs, GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase, MultiParamTypeClasses, MultiWayIf, PolyKinds #-} {-# LANGUAGE RankNTypes, ScopedTypeVariables, StandaloneDeriving #-} @@ -52,7 +56,16 @@ newtype F (p :: k) = F { runF :: F' p } type WORD_MAX_BOUND = $(litT $ numTyLit $ floor @Double $ sqrt $ fromIntegral $ maxBound @Int) + +#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 810 +type F' :: forall k. forall (p :: k) -> Type +#endif + type F' (p :: k) = F_Aux k p + +#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 810 +type F_Aux :: forall k (p :: k) -> Type +#endif type family F_Aux (k :: Type) (p :: k) where F_Aux Nat (p :: Nat) = F_Nat_Aux (WORD_MAX_BOUND <=? p) From edc1bc6a804f95662895a6c35b27115e3c2a1d80 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 23 Jul 2020 17:56:07 +0900 Subject: [PATCH 48/62] Bumps 8.8 resolver and switches default to 8.8 --- stack-808.yaml | 2 +- stack.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/stack-808.yaml b/stack-808.yaml index 4294d051..7f30510f 100644 --- a/stack-808.yaml +++ b/stack-808.yaml @@ -1,4 +1,4 @@ -resolver: lts-15.0 +resolver: lts-15.15 flags: {} packages: diff --git a/stack.yaml b/stack.yaml index 83496e60..c3579337 120000 --- a/stack.yaml +++ b/stack.yaml @@ -1 +1 @@ -stack-806.yaml \ No newline at end of file +stack-808.yaml \ No newline at end of file From 84fb07bf9a470b58dab374ec30ecbe842be6241e Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 23 Jul 2020 17:56:22 +0900 Subject: [PATCH 49/62] VSCode environment --- .vscode/settings.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 877e0599..5d877e59 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,7 @@ "**/.stack-work/": true, "heap-poly": true }, - "stylishHaskell.showConsoleOnError": false + "stylishHaskell.showConsoleOnError": false, + "haskell.formattingProvider": "none", + "editor.defaultFormatter": "vigoo.stylish-haskell" } \ No newline at end of file From 2838ebac6c497af450942513e08037e93bddb7b4 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 23 Jul 2020 18:16:31 +0900 Subject: [PATCH 50/62] Unbox instance for Small F_p --- halg-core/package.yaml | 2 ++ halg-core/src/Algebra/Field/Prime.hs | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/halg-core/package.yaml b/halg-core/package.yaml index 35314d47..6060522a 100644 --- a/halg-core/package.yaml +++ b/halg-core/package.yaml @@ -61,6 +61,8 @@ dependencies: - type-natural - unordered-containers - vector +- vector-th-unbox +- primitive - vector-instances library: diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 6b9a6b52..95fc576c 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -35,6 +35,7 @@ import Data.Kind (Constraint, Type) import Data.Proxy (Proxy (..), asProxyTypeOf) import qualified Data.Ratio as R import Data.Reflection (Reifies (reflect), reifyNat) +import Data.Vector.Unboxed.Deriving import Data.Singletons.Prelude import GHC.Read import GHC.TypeLits (KnownNat) @@ -482,3 +483,10 @@ modRat _ q = NA.fromInteger (numerator q) NA./ NA.fromInteger (denominator q) modRat' :: FiniteField k => Fraction Integer -> k modRat' = modRat Proxy {-# INLINE modRat' #-} + +derivingUnbox "Fp_small" + [t| forall p. (WORD_MAX_BOUND <=? p) ~ 'False + => F p -> Int + |] + [|runF|] + [|F|] From 618e178a4ad22da983de0b832c1654fcae0bbb06 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 23 Jul 2020 18:16:35 +0900 Subject: [PATCH 51/62] Format on save --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5d877e59..8e2aeb7f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,5 +7,6 @@ }, "stylishHaskell.showConsoleOnError": false, "haskell.formattingProvider": "none", - "editor.defaultFormatter": "vigoo.stylish-haskell" + "editor.defaultFormatter": "vigoo.stylish-haskell", + "editor.formatOnSave": true } \ No newline at end of file From 37421508be9dab58f76371d43ec24cdecdf259f2 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 23 Jul 2020 18:20:39 +0900 Subject: [PATCH 52/62] Updates image for CI 8.8 --- .gitlab-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 12e551db..48ebcd94 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,7 +37,7 @@ stages: <<: *cached-dirs .header-ghc-88: &header-ghc-88 - image: registry.gitlab.com/konn/computational-algebra/build/ghc-8.8:0.6.0.0-p3 + image: registry.gitlab.com/konn/computational-algebra/build/ghc-8.8:0.6.0.0-p4 variables: STACK_YAML: "stack-808.yaml" GHC: 808 @@ -119,7 +119,7 @@ test:ghc-8.10: deploy_documents: only: - master@konn/computational-algebra - image: registry.gitlab.com/konn/computational-algebra/build/ghc-8.8:0.6.0.0-p3 + image: registry.gitlab.com/konn/computational-algebra/build/ghc-8.8:0.6.0.0-p4 stage: deploy allow_failure: true dependencies: From 5dc036146d422ba134c45e68266c9c66549c8d72 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 23 Jul 2020 21:35:01 +0900 Subject: [PATCH 53/62] Workaround for REPL and IDE --- .../src/Algebra/Field/Galois/Conway.hs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/halg-galois-fields/src/Algebra/Field/Galois/Conway.hs b/halg-galois-fields/src/Algebra/Field/Galois/Conway.hs index c185af29..44f8e2c2 100644 --- a/halg-galois-fields/src/Algebra/Field/Galois/Conway.hs +++ b/halg-galois-fields/src/Algebra/Field/Galois/Conway.hs @@ -8,12 +8,21 @@ module Algebra.Field.Galois.Conway conwayFile) where import Algebra.Field.Galois.Internal import Algebra.Prelude.Core -import Control.Monad (liftM) -import Language.Haskell.TH (runIO) import Language.Haskell.TH (DecsQ) +import Language.Haskell.TH.Syntax +import System.Directory -do dat <- tail . init . lines <$> runIO (readFile "data/conway.txt") - concat <$> mapM (buildInstance . head . parseLine) dat +do + dir <- runIO getCurrentDirectory + conwayFile : _ <- runIO $ + filterM doesFileExist + [ dir "halg-galois-fields" "data" "conway.txt" + , "data" "conway.txt" + , "halg-galois-fields" "data" "conway.txt" + ] + addDependentFile conwayFile + dat <- tail . init . lines <$> runIO (readFile conwayFile) + concat <$> mapM (buildInstance . head . parseLine) dat -- | Macro to add Conway polynomials dictionary. addConwayPolynomials :: [(Integer, Integer, [Integer])] -> DecsQ From 8c20088bce15a276137a4136fb0b5f2cb210d9be Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Fri, 24 Jul 2020 01:27:26 +0900 Subject: [PATCH 54/62] Unboxed and Prim instances --- halg-core/package.yaml | 2 + halg-core/src/Algebra/Field/Prime.hs | 7 +- halg-core/src/Algebra/Instances.hs | 193 +++++++++++++++++++++++++-- 3 files changed, 187 insertions(+), 15 deletions(-) diff --git a/halg-core/package.yaml b/halg-core/package.yaml index 6060522a..8f1420f9 100644 --- a/halg-core/package.yaml +++ b/halg-core/package.yaml @@ -63,6 +63,8 @@ dependencies: - vector - vector-th-unbox - primitive +- vector-algorithms +- vector-builder - vector-instances library: diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 95fc576c..bb0380d8 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -1,7 +1,7 @@ #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 810 {-# LANGUAGE StandaloneKindSignatures #-} #endif - +{-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE CPP, DataKinds, DerivingStrategies, FlexibleContexts #-} {-# LANGUAGE FlexibleInstances, GADTs, GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase, MultiParamTypeClasses, MultiWayIf, PolyKinds #-} @@ -19,7 +19,7 @@ module Algebra.Field.Prime -- * Auxiliary interfaces HasPrimeField(..), -- ** Internals - wrapF, liftFUnary, liftBinF + wrapF, liftFUnary, liftBinF, WORD_MAX_BOUND ) where import Algebra.Arithmetic (modPow) import Algebra.Field.Finite @@ -45,6 +45,7 @@ import Language.Haskell.TH (litT, numTyLit) import Numeric.Algebra (char) import Numeric.Algebra (Natural) import qualified Numeric.Algebra as NA +import Data.Primitive.Types import Numeric.Semiring.ZeroProduct (ZeroProductSemiring) import qualified Prelude as P import Unsafe.Coerce (unsafeCoerce) @@ -490,3 +491,5 @@ derivingUnbox "Fp_small" |] [|runF|] [|F|] + +deriving newtype instance (WORD_MAX_BOUND <=? p) ~ 'False => Prim (F p) diff --git a/halg-core/src/Algebra/Instances.hs b/halg-core/src/Algebra/Instances.hs index 36cc3667..b62fdfba 100644 --- a/halg-core/src/Algebra/Instances.hs +++ b/halg-core/src/Algebra/Instances.hs @@ -1,21 +1,35 @@ -{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, GADTs #-} -{-# LANGUAGE MultiParamTypeClasses, TypeFamilies #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# LANGUAGE BangPatterns, DataKinds, FlexibleContexts, FlexibleInstances #-} +{-# LANGUAGE GADTs, MultiParamTypeClasses, ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications, TypeFamilies #-} +{-# OPTIONS_GHC -Wno-orphans #-} -- | This Library provides some *dangerous* instances for @Double@s and @Complex@. module Algebra.Instances () where import Algebra.Scalar import AlgebraicPrelude -import Control.DeepSeq (NFData (..)) -import Control.Monad.Random (Random (..), getRandom) -import Control.Monad.Random (getRandomR, runRand) -import Data.Complex (Complex (..)) -import Data.Convertible.Base (Convertible (..)) -import qualified Data.Ratio as P -import qualified Data.Vector as DV -import Data.Vector.Instances () -import qualified Numeric.Algebra as NA -import qualified Prelude as P +import Control.DeepSeq (NFData (..)) +import Control.Monad.Random (Random (..), getRandom) +import Control.Monad.Random (getRandomR, runRand) +import Control.Monad.ST.Strict (runST) +import qualified Data.Coerce as DC +import Data.Complex (Complex (..)) +import Data.Convertible.Base (Convertible (..)) +import Data.Functor.Identity +import Data.ListLike (ListLike) +import qualified Data.ListLike as LL +import Data.MonoTraversable +import qualified Data.Primitive.PrimArray as PA +import qualified Data.Ratio as P +import qualified Data.Sized.Builtin as SV +import qualified Data.Vector as DV +import qualified Data.Vector.Algorithms.Intro as AI +import Data.Vector.Instances () +import qualified Data.Vector.Primitive as PV +import qualified Numeric.Algebra as NA +import qualified Prelude as P +import Unsafe.Coerce (unsafeCoerce) +import qualified VectorBuilder.Builder as VB +import qualified VectorBuilder.Vector as VB instance Additive r => Additive (DV.Vector r) where (+) = DV.zipWith (+) @@ -171,3 +185,156 @@ instance (Random (Fraction Integer)) where ub = g * numerator b `quot` denominator b i <- getRandomR (lb, ub) return $ i % g + +type instance Element (PV.Vector a) = a +instance PV.Prim a => MonoFoldable (PV.Vector a) where + ofoldl' = PV.foldl' + ofoldMap = \f -> PV.foldl' (\a b -> a <> f b) mempty + ofoldr = PV.foldr' + ofoldr1Ex = PV.foldr1' + ofoldl1Ex' = PV.foldl1' + olength = PV.length + otoList = PV.toList + oall = PV.all + oany = PV.any + onull = PV.null + headEx = PV.head + lastEx = PV.last + oelem = PV.elem + onotElem = PV.notElem + +instance PV.Prim a => MonoFunctor (PV.Vector a) where + omap = PV.map + +instance PV.Prim a => MonoTraversable (PV.Vector a) where + otraverse = \f -> fmap PV.fromList . traverse f . PV.toList + +instance PV.Prim a => ListLike (PV.Vector a) a where + singleton = PV.singleton + null = PV.null + genericLength = fromIntegral . PV.length + head = PV.head + tail = PV.tail + cons = PV.cons + empty = PV.empty + snoc = PV.snoc + append = (<>) + last = PV.last + init = PV.init + length = PV.length + rigidMap = PV.map + reverse = PV.reverse + concat = VB.build . LL.foldMap VB.vector + rigidConcatMap = PV.concatMap + any = PV.any + all = PV.all + maximum = PV.maximum + minimum = PV.minimum + + replicate = PV.replicate + take = PV.take + drop = PV.drop + splitAt = PV.splitAt + takeWhile = PV.takeWhile + dropWhile = PV.dropWhile + span = PV.span + elem = PV.elem + notElem = PV.notElem + find = PV.find + filter = PV.filter + partition = PV.partition + index = DC.coerce $ PV.indexM @a @Identity + elemIndex = PV.elemIndex + elemIndices = fmap LL.fromListLike . PV.elemIndices + findIndex = PV.findIndex + findIndices = fmap LL.fromListLike . PV.findIndices + rigidMapM = PV.mapM + sort = PV.modify AI.sort + sortBy f = PV.modify (AI.sortBy f) + +instance PV.Prim a => LL.FoldableLL (PV.Vector a) a where + foldl = PV.foldl + foldl' = PV.foldl' + foldl1 = PV.foldl1 + foldr = PV.foldr + foldr' = PV.foldr' + foldr1 = PV.foldr1 + +instance PV.Prim a => LL.ListLike (PA.PrimArray a) a where + null = (== 0) . PA.sizeofPrimArray + singleton = PA.replicatePrimArray 1 + genericLength = fromIntegral . PA.sizeofPrimArray + head = (`PA.indexPrimArray` 0) + tail = \xs -> runST $ do + let !len = PA.sizeofPrimArray xs + mxs <- PA.newPrimArray (len - 1) + PA.copyPrimArray mxs 0 xs 0 (len - 1) + PA.unsafeFreezePrimArray mxs + cons = \x xs -> runST $ do + let !len = PA.sizeofPrimArray xs + mxxs <- PA.newPrimArray (1 + len) + PA.writePrimArray mxxs 0 x + PA.copyPrimArray + mxxs 0 xs 1 len + PA.unsafeFreezePrimArray mxxs + empty = runST $ do + PA.unsafeFreezePrimArray =<< PA.newPrimArray 0 + snoc = \ xs x -> runST $ do + let !len = PA.sizeofPrimArray xs + mxxs <- PA.newPrimArray (1 + len) + PA.writePrimArray mxxs len x + PA.copyPrimArray + mxxs 0 xs 0 len + PA.unsafeFreezePrimArray mxxs + append = (<>) + last = PA.indexPrimArray <$> id <*> pred . PA.sizeofPrimArray + init = \xs -> runST $ do + let !len = PA.sizeofPrimArray xs + mxs <- PA.newPrimArray (len - 1) + PA.copyPrimArray mxs 0 xs 0 (len - 1) + PA.unsafeFreezePrimArray mxs + length = PA.sizeofPrimArray + rigidMap = PA.mapPrimArray + + replicate = PA.replicatePrimArray + filter = PA.filterPrimArray + index = PA.indexPrimArray + rigidMapM = PA.traversePrimArray + toList = PA.primArrayToList + fromList = PA.primArrayFromList + +instance PV.Prim a => LL.FoldableLL (PA.PrimArray a) a where + foldl = PA.foldlPrimArray + foldr = PA.foldrPrimArray + foldl' = PA.foldlPrimArray' + foldr' = PA.foldrPrimArray' + +type instance Element (PA.PrimArray a) = a +instance PV.Prim a => MonoFoldable (PA.PrimArray a) where + ofoldMap f = PA.foldrPrimArray' (mappend . f) mempty + ofoldr = PA.foldrPrimArray' + ofoldl' = PA.foldlPrimArray' + ofoldl1Ex' = \f xs -> + PA.foldlPrimArray' f (LL.head xs) (LL.tail xs) + ofoldr1Ex = \f xs -> + PA.foldrPrimArray' f (LL.last xs) (LL.init xs) + otoList = PA.primArrayToList + olength = PA.sizeofPrimArray + onull = (== 0) . PA.sizeofPrimArray + otraverse_ = PA.traversePrimArray_ + ofoldlM = PA.foldlPrimArrayM' + headEx = (`PA.indexPrimArray` 0) + lastEx = PA.indexPrimArray <$> id <*> pred . PA.sizeofPrimArray + +instance PV.Prim a => MonoFunctor (PA.PrimArray a) where + omap = PA.mapPrimArray + +instance PV.Prim a => MonoTraversable (PA.PrimArray a) where + otraverse = PA.traversePrimArray + omapM = PA.traversePrimArray + +{-# RULES + "zipWithSame/PVector" [~1] + forall (f :: (PV.Prim a, PV.Prim b, PV.Prim c) => a -> b -> c). + SV.zipWithSame f = (unsafeCoerce .) . (. SV.unsized) . PV.zipWith f . SV.unsized + #-} From 288575cf2fdd1483960204419f2d4d2b2cc90683 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Fri, 24 Jul 2020 01:28:19 +0900 Subject: [PATCH 55/62] Galois Field opt-test --- .gitlab-ci.yml | 3 +- .../opt-test/halg-gf-opt-test.hs | 53 +++ halg-galois-fields/package.yaml | 39 +- .../src/Algebra/Field/Galois.hs | 376 +++++++++++++----- hie.yaml | 3 + 5 files changed, 374 insertions(+), 100 deletions(-) create mode 100644 halg-galois-fields/opt-test/halg-gf-opt-test.hs diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 48ebcd94..7fb69165 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -66,7 +66,7 @@ before_script: - echo "$STACK_YAML" - stack setup - stack build --no-terminal --test --no-run-tests --coverage - - stack build --no-terminal --work-dir=.stack-no-coverage --flag halg-core-test:opt-test halg-core-test:exe:halg-core-opt-test + - stack build --no-terminal --work-dir=.stack-no-coverage --flag halg-core-test:opt-test --flag halg-galois-fields:opt-test halg-core-test:exe:halg-core-opt-test halg-galois-fields:text:halg-gf-opt-test .test-script: &test-script stage: test @@ -74,6 +74,7 @@ before_script: - stack setup - stack --no-terminal test --no-rerun-tests --coverage - stack exec --work-dir=.stack-no-coverage -- halg-core-opt-test + - stack exec --work-dir=.stack-no-coverage -- halg-gf-opt-test build:ghc-8.4: <<: *header-ghc-84 diff --git a/halg-galois-fields/opt-test/halg-gf-opt-test.hs b/halg-galois-fields/opt-test/halg-gf-opt-test.hs new file mode 100644 index 00000000..9033959f --- /dev/null +++ b/halg-galois-fields/opt-test/halg-gf-opt-test.hs @@ -0,0 +1,53 @@ +{-# OPTIONS_GHC -fno-hpc -O2 #-} +{-# OPTIONS_GHC -dsuppress-idinfo -dsuppress-coercions + -dsuppress-type-applications + -dsuppress-module-prefixes -dsuppress-type-signatures + -dsuppress-uniques + #-} +{-# LANGUAGE TemplateHaskell #-} +module Main where +import Algebra.Field.Galois +import Algebra.Field.Prime +import Algebra.Prelude.Core +import qualified Data.ListLike as LL +import qualified Data.Sized.Builtin as SV +import qualified Data.Vector as V +import qualified Data.Vector.Primitive as P +import Numeric.Algebra as NA +import Test.Hspec +import Test.Inspection + +add_gf_2_8 :: GF 2 8 -> GF 2 8 -> GF 2 8 +add_gf_2_8 = (NA.+) + +add_gf_2_8_Manual + :: SV.Sized P.Vector 8 (F 2) + -> SV.Sized P.Vector 8 (F 2) + -> SV.Sized P.Vector 8 (F 2) +add_gf_2_8_Manual = SV.zipWithSame (NA.+) + +inspect $ coreOf 'add_gf_2_8 + +checkInspection + :: Result -> Expectation +checkInspection Success{} = pure () +checkInspection (Failure msg) = + fail msg + +main :: IO () +main = hspec $ do + describe "GF 2 8" $ do + describe "(NA.+)" $ do + it "doesn't contain boxed Vector" $ + checkInspection + $(inspectTest $ 'add_gf_2_8 `hasNoType` ''V.Vector) + it "doesn't contain type class dictionary" $ + checkInspection + $(inspectTest $ + 'add_gf_2_8 + `hasNoTypeClassesExcept` + [''LL.ListLike] + ) + -- it "is almost equivalent to P.zipWith (+)" $ + -- checkInspection + -- $(inspectTest $ 'add_gf_2_8 ==- 'add_gf_2_8_Manual) diff --git a/halg-galois-fields/package.yaml b/halg-galois-fields/package.yaml index 69e24ab1..a020b4af 100644 --- a/halg-galois-fields/package.yaml +++ b/halg-galois-fields/package.yaml @@ -43,8 +43,13 @@ dependencies: - algebraic-prelude - algebra -data-files: -- data/* +data-dir: data + +flags: + opt-test: + description: "Whether to build optimisation test" + manual: true + default: false library: source-dirs: src @@ -58,7 +63,11 @@ library: - singletons - sized - template-haskell + - mono-traversable + - ListLike - vector + - primitive + - directory other-modules: - Algebra.Field.Galois.Conway - Algebra.Field.Galois.Internal @@ -67,4 +76,28 @@ library: executables: {} -tests: {} +tests: + halg-gf-opt-test: + when: + - condition: flag(opt-test) + then: + buildable: true + else: + buildable: false + source-dirs: opt-test + main: halg-gf-opt-test.hs + ghc-options: + - -Wall + - -O2 + - -fno-hpc + dependencies: + - halg-core + - halg-polynomials + - halg-galois-fields + - inspection-testing + - hspec + - vector + - primitive + - sized + - ListLike + diff --git a/halg-galois-fields/src/Algebra/Field/Galois.hs b/halg-galois-fields/src/Algebra/Field/Galois.hs index 51cde527..011faf73 100644 --- a/halg-galois-fields/src/Algebra/Field/Galois.hs +++ b/halg-galois-fields/src/Algebra/Field/Galois.hs @@ -1,10 +1,16 @@ -{-# LANGUAGE DataKinds, DerivingStrategies, FlexibleContexts #-} +#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 810 +{-# LANGUAGE StandaloneKindSignatures #-} +#endif +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE CPP, DataKinds, DerivingStrategies, FlexibleContexts #-} {-# LANGUAGE FlexibleInstances, GADTs, GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses, NoMonomorphismRestriction #-} {-# LANGUAGE ParallelListComp, PolyKinds, QuasiQuotes, RankNTypes #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ScopedTypeVariables, StandaloneDeriving, TypeApplications #-} {-# LANGUAGE TypeFamilies, TypeOperators, UndecidableInstances #-} {-# LANGUAGE UndecidableSuperClasses #-} +{-# OPTIONS_GHC -Wno-orphans #-} module Algebra.Field.Galois ( GF'(), IsGF', modPoly, modVec, withIrreducible, linearRepGF, linearRepGF', @@ -15,38 +21,70 @@ module Algebra.Field.Galois ) where import Algebra.Field.Galois.Conway import Algebra.Field.Prime +import Algebra.Instances () import Algebra.Internal import Algebra.Prelude.Core hiding (varX) import Algebra.Ring.Polynomial.Univariate import Control.DeepSeq -import Control.Lens (imap) -import Control.Monad (replicateM) -import Control.Monad.Loops (iterateUntil) -import Control.Monad.Random (MonadRandom, getRandom, runRand) -import Control.Monad.Random (Random (..), getRandomR) -import qualified Data.Foldable as F -import Data.Kind (Type) -import qualified Data.Ratio as Rat -import Data.Reflection (Reifies (..), reify) -import Data.Singletons.Prelude.Enum (SEnum (..)) -import Data.Singletons.TypeLits (withKnownNat) -import qualified Data.Sized.Builtin as SV -import qualified Data.Traversable as T -import qualified Data.Vector as V -import qualified GHC.TypeLits as TL -import qualified Numeric.Algebra as NA -import Numeric.Domain.Euclidean (Euclidean) -import Numeric.Domain.GCD (GCDDomain, gcd) -import Numeric.Semiring.ZeroProduct (ZeroProductSemiring) -import qualified Prelude as P +import Control.Lens (imap) +import Control.Monad.Loops (iterateUntil) +import Control.Monad.Random (MonadRandom, getRandom, runRand) +import Control.Monad.Random (Random (..), getRandomR) +import Data.Kind (Type) +import qualified Data.Ratio as Rat +import Data.Reflection (Reifies (..), reify) +import qualified Data.Sized.Builtin as SV +import qualified Data.Sized as Sized +import qualified Data.Vector as V +import qualified GHC.TypeLits as TL +import qualified Numeric.Algebra as NA +import qualified Prelude as P +import qualified Data.Vector.Primitive as Prim +import Data.Singletons.TH (sCases) +import Data.MonoTraversable (MonoTraversable, otraverse, Element, MonoFoldable(oall)) +import qualified Data.Vector.Generic as G +import qualified Data.ListLike as LL +import Unsafe.Coerce (unsafeCoerce) +import qualified Data.Coerce as DC + +#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 810 +type GFSized :: forall k. forall (p :: k) -> Type -> Type +#endif +type GFSized (p :: k) = Sized.Sized (GFSized' k p) + +#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 810 +type GFSized' :: forall k (p :: k) -> Nat -> Type -> Nat +#endif +type family GFSized' k (p :: k) where + GFSized' Nat p = GFSized_Aux (WORD_MAX_BOUND <=? p) + GFSized' k p = V.Vector + +type family GFSized_Aux a where + GFSized_Aux 'True = V.Vector + GFSized_Aux 'False = Prim.Vector -- | Galois field of order @p^n@. -- @f@ stands for the irreducible polynomial over @F_p@ of degree @n@. -newtype GF' p (n :: TL.Nat) (f :: Type) = GF' { runGF' :: Sized n (F p) } +newtype GF' p (n :: TL.Nat) (f :: Type) = GF' { runGF' :: GFSized p n (F p) } + deriving newtype instance - NFData (F p) => NFData (GF' p n f) -deriving instance IsPrimeChar p => Eq (GF' p n f) + NFData (F (p :: Type)) => NFData (GF' p n f) + +instance + (SingI (WORD_MAX_BOUND <=? p), NFData (F p)) => NFData (GF' p n f) + where + rnf = + $(sCases ''Bool [|sing :: Sing (WORD_MAX_BOUND <=? p)|] + [|rnf . runGF'|]) + + +instance (IsPrimeChar (p :: Nat), SingI (WORD_MAX_BOUND <=? p)) + => Eq (GF' p n f) where + (==) = + $(sCases ''Bool [|sing :: Sing (WORD_MAX_BOUND <=? p)|] + [|(==) `on` runGF'|]) +deriving instance IsPrimeChar (p :: Type) => Eq (GF' p n f) -- | Galois Field of order @p^n@. This uses conway polynomials -- as canonical minimal polynomial and it should be known at @@ -54,29 +92,49 @@ deriving instance IsPrimeChar p => Eq (GF' p n f) -- instances should be defined to use field operations). type GF (p :: TL.Nat) n = GF' p n (Conway p n) -modPoly :: forall p n f. (KnownNat n, IsPrimeChar p) => Unipol (F p) -> GF' p n f +modPoly :: forall k (p :: k) n f. + ( KnownNat n, IsPrimeChar p, + G.Vector (GFSized' k p) (F p), + LL.ListLike (GFSized' k p (F p)) (F p) + ) + => Unipol (F p) -> GF' p n f modPoly = GF' . polyToVec -modVec :: Sized n (F p) -> GF' p n f +modVec :: SV.Sized (GFSized' k p) n (F p) -> GF' p n f modVec = GF' -instance (IsPrimeChar p, Show (F p)) => Show (GF' p n f) where - showsPrec d (GF' (v :< vs)) = - if F.all isZero vs + +instance (IsGF' p n f, Show (F p)) + => Show (GF' p n f) where + showsPrec d (GF' (v SV.:< vs)) = + if oall isZero vs then showsPrec d v else showChar '<' . showString (showPolynomialWith (singleton "ξ") 0 $ vecToPoly $ v :< vs) . showChar '>' showsPrec _ _ = showString "0" -instance (IsPrimeChar p, Show (F p)) => PrettyCoeff (GF' p n f) +instance (IsGF' p n f) => PrettyCoeff (GF' p n f) varX :: CoeffRing r => Unipol r varX = var [od|0|] -vecToPoly :: (CoeffRing r) - => Sized n r -> Unipol r -vecToPoly v = sum $ imap (\i c -> injectCoeff c * varX^fromIntegral i) $ F.toList v - -polyToVec :: forall n r. (CoeffRing r, KnownNat n) => Unipol r -> Sized n r +vecToPoly :: (CoeffRing r, G.Vector v r) + => Sized.Sized v n r -> Unipol r +vecToPoly v = sum $ imap (\i c -> injectCoeff c * varX^fromIntegral i) + $ G.toList $ SV.unsized v + +{-# SPECIALISE INLINE polyToVec + :: forall n (p :: Nat). (KnownNat n, IsPrimeChar p) + => Unipol (F p) -> SV.Sized V.Vector n (F p) + #-} +{-# SPECIALISE INLINE polyToVec + :: forall n (p :: Nat). + ( KnownNat n, IsPrimeChar p, Prim.Prim (F p) + ) + => Unipol (F p) -> SV.Sized Prim.Vector n (F p) + #-} +polyToVec :: forall n r v. + (CoeffRing r, KnownNat n, G.Vector v r, LL.ListLike (v r) r) + => Unipol r -> SV.Sized v n r polyToVec f = case zeroOrSucc (sing :: SNat n) of IsZero -> SV.empty @@ -86,97 +144,175 @@ polyToVec f = | i <- [0..fromIntegral (fromSing (sing :: SNat n)) P.- 1] ] -instance IsPrimeChar p => Additive (GF' p n f) where - GF' v + GF' u = GF' $ SV.zipWithSame (+) v u - -instance (IsPrimeChar p, KnownNat n) => Monoidal (GF' p n f) where +mapSV + :: forall f n a b. + (LL.ListLike (f a) a, LL.ListLike (f b) b) + => (a -> b) -> SV.Sized f n a -> SV.Sized f n b +{-# INLINE [1] mapSV #-} +mapSV = SV.map + +{-# SPECIALISE mapSV + :: (F p -> F p) -> Sized n (F p) -> Sized n (F p) #-} +{-# SPECIALISE mapSV + :: Prim.Prim (F p) + => (F p -> F p) -> SV.Sized Prim.Vector n (F p) -> SV.Sized Prim.Vector n (F p) + #-} +{-# SPECIALISE mapSV + :: (F 2 -> F 2) -> SV.Sized Prim.Vector n (F 2) -> SV.Sized Prim.Vector n (F 2) + #-} +{-# SPECIALISE mapSV + :: (F 3 -> F 3) -> SV.Sized Prim.Vector n (F 3) -> SV.Sized Prim.Vector n (F 3) + #-} + +zipWithSameSV + :: forall f a b c n. + ( LL.ListLike (f a) a, LL.ListLike (f b) b + , LL.ListLike (f c) c + ) + => (a -> b -> c) -> SV.Sized f n a -> SV.Sized f n b -> SV.Sized f n c +{-# INLINE [2] zipWithSameSV #-} +zipWithSameSV = SV.zipWithSame + +zipWithFpPrim + :: forall p n. Prim.Prim (F p) => + (F p -> F p -> F p) + -> SV.Sized Prim.Vector n (F p) + -> SV.Sized Prim.Vector n (F p) + -> SV.Sized Prim.Vector n (F p) +zipWithFpPrim = unsafeCoerce $ Prim.zipWith @(F p) @(F p) @(F p) + +zipWithFpBoxed + :: forall p n. + (F p -> F p -> F p) + -> SV.Sized V.Vector n (F p) + -> SV.Sized V.Vector n (F p) + -> SV.Sized V.Vector n (F p) +zipWithFpBoxed = unsafeCoerce $ V.zipWith @(F p) @(F p) @(F p) +{-# RULES +"zipWith/Fp/Boxed" [~2] + zipWithSameSV = zipWithFpBoxed + +"zipWith/Fp/Prim" [~2] + forall (f :: Prim.Prim (F p) => F p -> F p -> F p). + zipWithSameSV f = zipWithFpPrim f + +"zipWith/Fp/Prim/F 2" [~2] + zipWithSameSV = zipWithFpPrim @2 + +"zipWith/Fp/Prim/F 3" [~2] + zipWithSameSV = zipWithFpPrim @3 + #-} + +{-# SPECIALISE zipWithSame + :: (F p -> F p -> F p) + -> Sized n (F p) -> Sized n (F p) + -> Sized n (F p) + #-} +{-# SPECIALISE zipWithSame + :: (F 2 -> F 2 -> F 2) + -> SV.Sized Prim.Vector n (F 2) + -> SV.Sized Prim.Vector n (F 2) + -> SV.Sized Prim.Vector n (F 2) + #-} +{-# SPECIALISE zipWithSame + :: (F 3 -> F 3 -> F 3) + -> SV.Sized Prim.Vector n (F 3) + -> SV.Sized Prim.Vector n (F 3) + -> SV.Sized Prim.Vector n (F 3) + #-} + +instance IsGF' p n f => Additive (GF' p n f) where + (+) = DC.coerce $ zipWithSameSV @(GFSized' _ p) @(F p) @(F p) @(F p) @n (+) + {-# INLINE (+) #-} + +instance (IsGF' p n f) => Monoidal (GF' p n f) where zero = GF' $ SV.replicate' zero -instance IsPrimeChar p => LeftModule Natural (GF' p n f) where - n .* GF' v = GF' $ SV.map (n .*) v +instance (IsGF' p n f) => LeftModule Natural (GF' p n f) where + n .* GF' v = GF' $ mapSV (n .*) v -instance IsPrimeChar p => RightModule Natural (GF' p n f) where - GF' v *. n = GF' $ SV.map (*. n) v +instance (IsGF' p n f) => RightModule Natural (GF' p n f) where + GF' v *. n = GF' $ mapSV (*. n) v -instance IsPrimeChar p => LeftModule Integer (GF' p n f) where - n .* GF' v = GF' $ SV.map (n .*) v +instance (IsGF' p n f) => LeftModule Integer (GF' p n f) where + n .* GF' v = GF' $ mapSV (n .*) v -instance IsPrimeChar p => RightModule Integer (GF' p n f) where - GF' v *. n = GF' $ SV.map (*. n) v +instance (IsGF' p n f) => RightModule Integer (GF' p n f) where + GF' v *. n = GF' $ mapSV (*. n) v -instance (KnownNat n, IsPrimeChar p) => Group (GF' p n f) where - negate (GF' v) = GF' $ SV.map negate v - GF' u - GF' v = GF' $ SV.zipWithSame (-) u v +instance (IsGF' p n f) => Group (GF' p n f) where + negate (GF' v) = GF' $ mapSV negate v + GF' u - GF' v = GF' $ zipWithSameSV (-) u v -instance (IsPrimeChar p) => Abelian (GF' p n f) +instance (IsGF' p n f) => Abelian (GF' p n f) -instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) +instance (IsGF' p n f) => Multiplicative (GF' p n f) where GF' u * GF' v = let t = (vecToPoly u * vecToPoly v) `rem` reflect (Proxy :: Proxy f) in GF' $ polyToVec t -instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Unital (GF' p n f) where +instance (IsGF' p n f) => Unital (GF' p n f) where one = case zeroOrSucc (sing :: SNat n) of IsZero -> GF' NilL IsSucc k -> withKnownNat k $ GF' $ one :< SV.replicate' zero -instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Semiring (GF' p n f) +instance (IsGF' p n f) => Semiring (GF' p n f) -instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Rig (GF' p n f) where +instance (IsGF' p n f) => Rig (GF' p n f) where fromNatural n = case zeroOrSucc (sing :: SNat n) of IsZero -> GF' SV.empty IsSucc k -> withKnownNat k $ GF' $ fromNatural n :< SV.replicate' zero -instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Commutative (GF' p n f) +instance (IsGF' p n f) => Commutative (GF' p n f) -instance (KnownNat n, Reifies f (Unipol (F p)), IsPrimeChar p) => Ring (GF' p n f) where +instance (IsGF' p n f) => Ring (GF' p n f) where fromInteger n = case zeroOrSucc (sing :: SNat n) of IsZero -> GF' NilL IsSucc k -> withKnownNat k $ GF' $ fromInteger n :< SV.replicate' zero -instance (KnownNat n, IsPrimeChar p) => DecidableZero (GF' p n f) where - isZero (GF' sv) = F.all isZero sv +instance (IsGF' p n f) => DecidableZero (GF' p n f) where + isZero (GF' sv) = oall isZero sv -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => DecidableUnits (GF' p n f) where - isUnit (GF' sv) = not $ F.all isZero sv +instance (IsGF' p n f) => DecidableUnits (GF' p n f) where + isUnit (GF' sv) = not $ oall isZero sv recipUnit a | isZero a = Nothing | otherwise = Just $ recip a -instance (IsPrimeChar p, Reifies f (Unipol (F p)), KnownNat n) +instance (IsGF' p n f) => Characteristic (GF' p n f) where char _ = char (Proxy :: Proxy (F p)) -instance (IsPrimeChar p, Reifies f (Unipol (F p)), KnownNat n) +instance (IsGF' p n f) => Division (GF' p n f) where recip f = let p = reflect (Proxy :: Proxy f) (_,_,r) = P.head $ euclid p $ vecToPoly $ runGF' f in GF' $ polyToVec $ r `rem` p -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => DecidableAssociates (GF' p n f) where isAssociate p n = (isZero p && isZero n) || (not (isZero p) && not (isZero n)) -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => ZeroProductSemiring (GF' p n f) -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => UnitNormalForm (GF' p n f) -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => IntegralDomain (GF' p n f) -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => GCDDomain (GF' p n f) -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => UFD (GF' p n f) -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => PID (GF' p n f) -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => Euclidean (GF' p n f) -instance (IsPrimeChar p, Reifies f (Unipol (F p)), KnownNat n) => P.Num (GF' p n f) where +instance (IsGF' p n f) => P.Num (GF' p n f) where (+) = (NA.+) (-) = (NA.-) negate = NA.negate @@ -185,7 +321,7 @@ instance (IsPrimeChar p, Reifies f (Unipol (F p)), KnownNat n) => P.Num (GF' p n abs = error "not defined" signum = error "not defined" -instance (IsPrimeChar p, Reifies f (Unipol (F p)), KnownNat n) => P.Fractional (GF' p n f) where +instance (IsGF' p n f) => P.Fractional (GF' p n f) where fromRational u = fromInteger (Rat.numerator u) / fromInteger (Rat.denominator u) (/) = (/) recip = recip @@ -199,35 +335,57 @@ generateIrreducible p n = let f = varX^n + sum [ injectCoeff c * (varX^i) | c <- cs | i <- [0..n P.- 1]] return f -withIrreducible :: forall p a. IsPrimeChar p - => Unipol (F p) - -> (forall f (n :: Nat). (Reifies f (Unipol (F p))) => Proxy (GF' p n f) -> a) - -> a +withIrreducible + :: forall p a. + ( IsPrimeChar (p :: k), + G.Vector (GFSized' k p) (F p), + MonoFoldable (GFSized' k p (F p)), + Element (GFSized' k p (F p)) ~ F p, + MonoTraversable (GFSized' k p (F p)), + LL.ListLike (GFSized' k p (F p)) (F p) + ) + => Unipol (F p) + -> (forall f (n :: Nat). (IsGF' p n f) => Proxy (GF' p n f) -> a) + -> a withIrreducible r f = case toSing (fromIntegral $ totalDegree' r) of SomeSing sn -> withKnownNat sn $ - reify r (f. proxyGF' (Proxy :: Proxy (F n)) sn) + reify r (f . proxyGF' (Proxy :: Proxy (F p)) sn) reifyGF' - :: MonadRandom m => Natural -> Natural - -> (forall (p :: TL.Nat) (f :: Type) (n :: TL.Nat) . (IsPrimeChar p, Reifies f (Unipol (F p))) + :: MonadRandom m + => Natural -> Natural + -> (forall (p :: TL.Nat) (f :: Type) (n :: TL.Nat) . (IsGF' p n f) => Proxy (GF' p n f) -> a) -> m a -reifyGF' p n f = reifyPrimeField (P.toInteger p) $ \pxy -> do +reifyGF' p n f = reifyPrimeField (P.toInteger p) $ \(pxy :: Proxy (F p)) -> do + let sp = sing :: SNat p mpol <- generateIrreducible pxy n - case toSing (fromIntegral p) of - SomeSing sp -> return $ withKnownNat sp $ withIrreducible mpol f - -linearRepGF :: IsPrimeChar p => GF' p n f -> V.Vector (F p) -linearRepGF = SV.unsized . runGF' - -linearRepGF' :: IsPrimeChar p => GF' p n f -> V.Vector Integer + case toSing (fromIntegral n) of + SomeSing (sn :: SNat n) -> + let cond :: Sing (WORD_MAX_BOUND <=? p) + cond = unsafeCoerce ((sing :: Sing WORD_MAX_BOUND) %<= sp) + in case cond of + STrue -> withKnownNat sp + $ withKnownNat sn + $ return $ withIrreducible mpol f + SFalse -> withKnownNat sp + $ withKnownNat sn + $ return $ withIrreducible mpol f + +linearRepGF :: (IsGF' p n f) => GF' p n f -> V.Vector (F p) +linearRepGF = G.convert . SV.unsized . runGF' + +linearRepGFRaw :: (IsGF' (p :: k) n f) => GF' p n f -> GFSized' k p (F p) +linearRepGFRaw = G.convert . SV.unsized . runGF' + +linearRepGF' :: (IsGF' p n f) => GF' p n f -> V.Vector Integer linearRepGF' = V.map naturalRepr . linearRepGF withGF' :: MonadRandom m => Natural -> Natural - -> (forall (p :: TL.Nat) f (n :: TL.Nat) . (IsPrimeChar p, Reifies f (Unipol (F p))) + -> (forall (p :: TL.Nat) f (n :: TL.Nat) . (IsGF' p n f) => GF' p n f) -> m (V.Vector Integer) withGF' p n f = reifyGF' p n $ V.map naturalRepr . linearRepGF . asProxyTypeOf f @@ -236,16 +394,33 @@ proxyGF' :: Proxy (F p) -> SNat n -> Proxy f -> Proxy (GF' p n f) proxyGF' _ _ Proxy = Proxy -- | Type-constraint synonym to work with Galois field. -class (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => IsGF' p n f -instance (KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p))) => IsGF' p n f +class + ( KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p)), + G.Vector (GFSized' k p) (F p), + LL.ListLike (GFSized' k p (F p)) (F p), + MonoTraversable (GFSized' k p (F p)), + MonoFoldable (GFSized' k p (F p)), + Element (GFSized' k p (F p)) ~ F p + ) + => IsGF' (p :: k) n f +instance + ( KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p)), + G.Vector (GFSized' k p) (F p), + LL.ListLike (GFSized' k p (F p)) (F p), + MonoFoldable (GFSized' k p (F p)), + MonoTraversable (GFSized' k p (F p)), + Element (GFSized' k p (F p)) ~ F p + ) + => IsGF' p n f instance (KnownNat n, IsGF' p n f) => FiniteField (GF' p n f) where power _ = fromIntegral $ fromSing (sing :: SNat n) elements _ = let sn = sing :: SNat n - in P.map GF' $ T.sequence $ - SV.replicate sn $ elements Proxy + in P.map (GF' . SV.unsafeToSized') $ otraverse (const $ elements Proxy) + $ SV.unsized + $ SV.replicate sn (0 :: F p) primitive' :: forall p n f. (IsGF' p n f, (n >= 1) ~ 'True) => GF' p n f primitive' = withKnownNat (sSucc (sing :: SNat n)) $ GF' $ polyToVec $ var [od|0|] @@ -260,7 +435,16 @@ conway = conwayPolynomial instance IsGF' p n f => Random (GF' p n f) where random = runRand $ - GF' <$> sequence (SV.replicate' getRandom) + GF' . SV.unsafeToSized' + <$> otraverse (const $ getRandom) (SV.unsized $ SV.replicate (sing :: SNat n) 0) randomR (GF' ls, GF' rs) = runRand $ - GF' <$> sequence (SV.zipWithSame (curry getRandomR) ls rs) - + GF' . hoistSized <$> sequence + (zipWithSameSV (curry getRandomR) + (hoistSized @V.Vector ls) + (hoistSized @V.Vector rs)) + +hoistSized + :: forall g f n a. (G.Vector f a, G.Vector g a, KnownNat n, LL.ListLike (g a) a) + => SV.Sized f n a -> SV.Sized g n a +{-# INLINE hoistSized #-} +hoistSized = SV.unsafeToSized' . G.convert . SV.unsized \ No newline at end of file diff --git a/hie.yaml b/hie.yaml index 12aebc49..643a1a46 100644 --- a/hie.yaml +++ b/hie.yaml @@ -37,6 +37,9 @@ cradle: - path: "halg-galois-fields/src" component: "halg-galois-fields:lib" + - path: "halg-galois-fields/opt-test" + component: "halg-galois-fields:test:halg-gf-opt-test" + - path: "algebraic-prelude/src" component: "algebraic-prelude:lib" From 31785dc0d072510fb75fd1fb48ec90fa196e589c Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 3 Sep 2020 20:14:28 +0900 Subject: [PATCH 56/62] Switched from `ListLike` to `subcategories` --- .../Algebra/Ring/Polynomial/Monomial/Test.hs | 2 +- halg-core/package.yaml | 2 +- halg-core/src/Algebra/Instances.hs | 153 +++--------------- halg-core/src/Algebra/Internal.hs | 14 +- halg-core/src/Algebra/Ring/Ideal.hs | 4 +- .../src/Algebra/Ring/Polynomial/Class.hs | 12 +- .../src/Algebra/Ring/Polynomial/Monomial.hs | 10 +- .../opt-test/halg-gf-opt-test.hs | 22 +-- halg-galois-fields/package.yaml | 4 +- .../src/Algebra/Field/Galois.hs | 87 +++++----- .../src/Algebra/Ring/Polynomial/Quotient.hs | 2 +- stack-808.yaml | 5 + 12 files changed, 83 insertions(+), 234 deletions(-) diff --git a/halg-core-test/src/Algebra/Ring/Polynomial/Monomial/Test.hs b/halg-core-test/src/Algebra/Ring/Polynomial/Monomial/Test.hs index 5256a527..b989b1a5 100644 --- a/halg-core-test/src/Algebra/Ring/Polynomial/Monomial/Test.hs +++ b/halg-core-test/src/Algebra/Ring/Polynomial/Monomial/Test.hs @@ -29,7 +29,7 @@ instance (Monad m, Serial m (Monomial n)) => Serial m (OrderedMonomial ord n) wh series = newtypeCons OrderedMonomial arbitraryMonomialOfSum :: SNat n -> Int -> Gen (Monomial n) -arbitraryMonomialOfSum n k = +arbitraryMonomialOfSum n k = withKnownNat n $ case zeroOrSucc n of IsZero | k == 0 -> QC.elements [SV.empty] | otherwise -> error "Impossible" diff --git a/halg-core/package.yaml b/halg-core/package.yaml index 8f1420f9..56e53ca3 100644 --- a/halg-core/package.yaml +++ b/halg-core/package.yaml @@ -37,7 +37,6 @@ default-extensions: - UndecidableInstances dependencies: -- ListLike - MonadRandom - algebra - algebraic-prelude @@ -58,6 +57,7 @@ dependencies: - reflection - singletons - sized +- subcategories - type-natural - unordered-containers - vector diff --git a/halg-core/src/Algebra/Instances.hs b/halg-core/src/Algebra/Instances.hs index b62fdfba..917283bf 100644 --- a/halg-core/src/Algebra/Instances.hs +++ b/halg-core/src/Algebra/Instances.hs @@ -1,35 +1,26 @@ -{-# LANGUAGE BangPatterns, DataKinds, FlexibleContexts, FlexibleInstances #-} -{-# LANGUAGE GADTs, MultiParamTypeClasses, ScopedTypeVariables #-} -{-# LANGUAGE TypeApplications, TypeFamilies #-} +{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, GADTs #-} +{-# LANGUAGE MultiParamTypeClasses, ScopedTypeVariables, TypeApplications #-} +{-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -Wno-orphans #-} -- | This Library provides some *dangerous* instances for @Double@s and @Complex@. module Algebra.Instances () where import Algebra.Scalar import AlgebraicPrelude -import Control.DeepSeq (NFData (..)) -import Control.Monad.Random (Random (..), getRandom) -import Control.Monad.Random (getRandomR, runRand) -import Control.Monad.ST.Strict (runST) -import qualified Data.Coerce as DC -import Data.Complex (Complex (..)) -import Data.Convertible.Base (Convertible (..)) -import Data.Functor.Identity -import Data.ListLike (ListLike) -import qualified Data.ListLike as LL +import Control.DeepSeq (NFData (..)) +import Control.Monad.Random (Random (..), getRandom) +import Control.Monad.Random (getRandomR, runRand) +import Control.Subcategory +import Data.Complex (Complex (..)) +import Data.Convertible.Base (Convertible (..)) import Data.MonoTraversable -import qualified Data.Primitive.PrimArray as PA -import qualified Data.Ratio as P -import qualified Data.Sized.Builtin as SV -import qualified Data.Vector as DV -import qualified Data.Vector.Algorithms.Intro as AI -import Data.Vector.Instances () -import qualified Data.Vector.Primitive as PV -import qualified Numeric.Algebra as NA -import qualified Prelude as P -import Unsafe.Coerce (unsafeCoerce) -import qualified VectorBuilder.Builder as VB -import qualified VectorBuilder.Vector as VB +import qualified Data.Primitive.PrimArray as PA +import qualified Data.Ratio as P +import qualified Data.Vector as DV +import Data.Vector.Instances () +import qualified Data.Vector.Primitive as PV +import qualified Numeric.Algebra as NA +import qualified Prelude as P instance Additive r => Additive (DV.Vector r) where (+) = DV.zipWith (+) @@ -209,115 +200,13 @@ instance PV.Prim a => MonoFunctor (PV.Vector a) where instance PV.Prim a => MonoTraversable (PV.Vector a) where otraverse = \f -> fmap PV.fromList . traverse f . PV.toList -instance PV.Prim a => ListLike (PV.Vector a) a where - singleton = PV.singleton - null = PV.null - genericLength = fromIntegral . PV.length - head = PV.head - tail = PV.tail - cons = PV.cons - empty = PV.empty - snoc = PV.snoc - append = (<>) - last = PV.last - init = PV.init - length = PV.length - rigidMap = PV.map - reverse = PV.reverse - concat = VB.build . LL.foldMap VB.vector - rigidConcatMap = PV.concatMap - any = PV.any - all = PV.all - maximum = PV.maximum - minimum = PV.minimum - - replicate = PV.replicate - take = PV.take - drop = PV.drop - splitAt = PV.splitAt - takeWhile = PV.takeWhile - dropWhile = PV.dropWhile - span = PV.span - elem = PV.elem - notElem = PV.notElem - find = PV.find - filter = PV.filter - partition = PV.partition - index = DC.coerce $ PV.indexM @a @Identity - elemIndex = PV.elemIndex - elemIndices = fmap LL.fromListLike . PV.elemIndices - findIndex = PV.findIndex - findIndices = fmap LL.fromListLike . PV.findIndices - rigidMapM = PV.mapM - sort = PV.modify AI.sort - sortBy f = PV.modify (AI.sortBy f) - -instance PV.Prim a => LL.FoldableLL (PV.Vector a) a where - foldl = PV.foldl - foldl' = PV.foldl' - foldl1 = PV.foldl1 - foldr = PV.foldr - foldr' = PV.foldr' - foldr1 = PV.foldr1 - -instance PV.Prim a => LL.ListLike (PA.PrimArray a) a where - null = (== 0) . PA.sizeofPrimArray - singleton = PA.replicatePrimArray 1 - genericLength = fromIntegral . PA.sizeofPrimArray - head = (`PA.indexPrimArray` 0) - tail = \xs -> runST $ do - let !len = PA.sizeofPrimArray xs - mxs <- PA.newPrimArray (len - 1) - PA.copyPrimArray mxs 0 xs 0 (len - 1) - PA.unsafeFreezePrimArray mxs - cons = \x xs -> runST $ do - let !len = PA.sizeofPrimArray xs - mxxs <- PA.newPrimArray (1 + len) - PA.writePrimArray mxxs 0 x - PA.copyPrimArray - mxxs 0 xs 1 len - PA.unsafeFreezePrimArray mxxs - empty = runST $ do - PA.unsafeFreezePrimArray =<< PA.newPrimArray 0 - snoc = \ xs x -> runST $ do - let !len = PA.sizeofPrimArray xs - mxxs <- PA.newPrimArray (1 + len) - PA.writePrimArray mxxs len x - PA.copyPrimArray - mxxs 0 xs 0 len - PA.unsafeFreezePrimArray mxxs - append = (<>) - last = PA.indexPrimArray <$> id <*> pred . PA.sizeofPrimArray - init = \xs -> runST $ do - let !len = PA.sizeofPrimArray xs - mxs <- PA.newPrimArray (len - 1) - PA.copyPrimArray mxs 0 xs 0 (len - 1) - PA.unsafeFreezePrimArray mxs - length = PA.sizeofPrimArray - rigidMap = PA.mapPrimArray - - replicate = PA.replicatePrimArray - filter = PA.filterPrimArray - index = PA.indexPrimArray - rigidMapM = PA.traversePrimArray - toList = PA.primArrayToList - fromList = PA.primArrayFromList - -instance PV.Prim a => LL.FoldableLL (PA.PrimArray a) a where - foldl = PA.foldlPrimArray - foldr = PA.foldrPrimArray - foldl' = PA.foldlPrimArray' - foldr' = PA.foldrPrimArray' - type instance Element (PA.PrimArray a) = a instance PV.Prim a => MonoFoldable (PA.PrimArray a) where ofoldMap f = PA.foldrPrimArray' (mappend . f) mempty ofoldr = PA.foldrPrimArray' ofoldl' = PA.foldlPrimArray' - ofoldl1Ex' = \f xs -> - PA.foldlPrimArray' f (LL.head xs) (LL.tail xs) - ofoldr1Ex = \f xs -> - PA.foldrPrimArray' f (LL.last xs) (LL.init xs) + ofoldl1Ex' = \f xs -> PA.foldlPrimArray' f (chead xs) (ctail xs) + ofoldr1Ex = cfoldr1 otoList = PA.primArrayToList olength = PA.sizeofPrimArray onull = (== 0) . PA.sizeofPrimArray @@ -332,9 +221,3 @@ instance PV.Prim a => MonoFunctor (PA.PrimArray a) where instance PV.Prim a => MonoTraversable (PA.PrimArray a) where otraverse = PA.traversePrimArray omapM = PA.traversePrimArray - -{-# RULES - "zipWithSame/PVector" [~1] - forall (f :: (PV.Prim a, PV.Prim b, PV.Prim c) => a -> b -> c). - SV.zipWithSame f = (unsafeCoerce .) . (. SV.unsized) . PV.zipWith f . SV.unsized - #-} diff --git a/halg-core/src/Algebra/Internal.hs b/halg-core/src/Algebra/Internal.hs index c6befed2..f0cc870f 100644 --- a/halg-core/src/Algebra/Internal.hs +++ b/halg-core/src/Algebra/Internal.hs @@ -18,14 +18,9 @@ import AlgebraicPrelude import Control.Lens ((%~), _Unwrapping) import qualified Data.Foldable as F import Data.Kind (Type) -import Data.ListLike (ListLike) import Data.Proxy import qualified Data.Sequence as Seq -import Data.Singletons.Prelude as Algebra.Internal (PNum (..), - POrd (..), - SNum (..), - SOrd (..), - SingI (..), +import Data.Singletons.Prelude as Algebra.Internal (SingI (..), SingKind (..), SomeSing (..), withSingI) @@ -35,10 +30,11 @@ import Data.Singletons.Prelude as Algebra.Internal (SBool (SFalse, STrue), Sing) import Data.Singletons.Prelude as Algebra.Internal (Sing (SFalse, STrue)) #endif +import Control.Subcategory (CFoldable) +import Control.Subcategory.Functor (Dom) import Data.Singletons.Prelude.Enum as Algebra.Internal (PEnum (..), SEnum (..)) -import Data.Singletons.TypeLits as Algebra.Internal (KnownNat, - withKnownNat) +import Data.Singletons.TypeLits as Algebra.Internal (withKnownNat) import Data.Sized.Builtin as Algebra.Internal (pattern (:<), pattern (:>), pattern NilL, @@ -82,7 +78,7 @@ coerceLength eql = _Unwrapping Flipped.Flipped %~ coerce eql type SNat (n :: Nat) = Sing n -sizedLength :: ListLike (f a) a => S.Sized f n a -> Sing n +sizedLength :: (CFoldable f, Dom f a) => S.Sized f n a -> Sing n sizedLength = S.sLength padVecs :: forall a n m. (Unbox a) => a -> USized n a -> USized m a diff --git a/halg-core/src/Algebra/Ring/Ideal.hs b/halg-core/src/Algebra/Ring/Ideal.hs index 55262cf0..5245fc78 100644 --- a/halg-core/src/Algebra/Ring/Ideal.hs +++ b/halg-core/src/Algebra/Ring/Ideal.hs @@ -8,7 +8,7 @@ module Algebra.Ring.Ideal ( Ideal(..), addToIdeal, toIdeal, appendIdeal , principalIdeal, isEmptyIdeal , someSizedIdeal ) where -import Algebra.Internal (Nat) +import Algebra.Internal () import AlgebraicPrelude import Control.DeepSeq @@ -54,6 +54,6 @@ mapIdeal :: (r -> r') -> Ideal r -> Ideal r' mapIdeal fun (Ideal xs) = Ideal $ fmap fun xs {-# INLINE [1] mapIdeal #-} -someSizedIdeal :: Ideal r -> S.SomeSized Vector Nat r +someSizedIdeal :: Ideal r -> S.SomeSized Vector r someSizedIdeal (Ideal xs) = S.toSomeSized $ V.fromList $ F.toList xs diff --git a/halg-core/src/Algebra/Ring/Polynomial/Class.hs b/halg-core/src/Algebra/Ring/Polynomial/Class.hs index 92ba20c4..c5269cb0 100644 --- a/halg-core/src/Algebra/Ring/Polynomial/Class.hs +++ b/halg-core/src/Algebra/Ring/Polynomial/Class.hs @@ -29,35 +29,25 @@ import Algebra.Normed import Algebra.Ring.Polynomial.Monomial import Algebra.Scalar import AlgebraicPrelude -import Control.Arrow ((***)) import Control.Lens (Iso', folded, ifoldMap, iso, ix, maximumOf, (%~), _Wrapped) -import Data.Foldable (foldr, maximum) import qualified Data.Foldable as F import qualified Data.HashSet as HS import Data.Int import Data.Kind (Type) import qualified Data.List as L import qualified Data.Map.Strict as M -import Data.Maybe (catMaybes, fromJust, - fromMaybe) +import Data.Maybe (fromJust) import Data.Monoid (First (..)) import Data.MonoTraversable import qualified Data.Ratio as R import qualified Data.Set as S -import Data.Singletons.Prelude (SingKind (..)) import qualified Data.Sized.Builtin as V import Data.Vector.Instances () import Data.Word -import GHC.TypeLits (KnownNat, Nat) import qualified Numeric.Algebra.Complex as NA -import Numeric.Decidable.Zero (DecidableZero (..)) -import Numeric.Domain.Euclidean (Euclidean, quot) -import Numeric.Domain.GCD (gcd) -import Numeric.Field.Fraction (Fraction) import qualified Numeric.Field.Fraction as NA -import Numeric.Natural (Natural) import qualified Numeric.Ring.Class as NA import qualified Prelude as P diff --git a/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs b/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs index 09075911..9fd8bb42 100644 --- a/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs +++ b/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs @@ -34,21 +34,15 @@ import qualified Data.Coerce as DC import Data.Constraint ((:=>) (..), Dict (..)) import qualified Data.Constraint as C import Data.Constraint.Forall (Forall, inst) -import Data.Hashable (Hashable (..)) import Data.Kind (Type) -import Data.Maybe (catMaybes) -import Data.Monoid (Dual (..), Sum (..), (<>)) +import Data.Monoid (Dual (..), Sum (..)) import Data.MonoTraversable (MonoFoldable (..), oand, ofoldMap, ofoldl', ofoldlUnwrap, osum) -import Data.Ord (comparing) import qualified Data.Semigroup as Semi -import Data.Singletons.Prelude (SList, Sing) -import Data.Singletons.Prelude (SingKind (..)) +import Data.Singletons.Prelude (SList) import Data.Singletons.Prelude.List (Length, Replicate, sReplicate) -import Data.Singletons.TypeLits (withKnownNat) import qualified Data.Sized.Builtin as V -import Data.Type.Natural.Class (IsPeano (..), PeanoOrder (..)) import qualified Data.Vector.Generic as G import qualified Data.Vector.Generic.Mutable as M import Data.Vector.Instances () diff --git a/halg-galois-fields/opt-test/halg-gf-opt-test.hs b/halg-galois-fields/opt-test/halg-gf-opt-test.hs index 9033959f..ed775ae3 100644 --- a/halg-galois-fields/opt-test/halg-gf-opt-test.hs +++ b/halg-galois-fields/opt-test/halg-gf-opt-test.hs @@ -9,8 +9,6 @@ module Main where import Algebra.Field.Galois import Algebra.Field.Prime import Algebra.Prelude.Core -import qualified Data.ListLike as LL -import qualified Data.Sized.Builtin as SV import qualified Data.Vector as V import qualified Data.Vector.Primitive as P import Numeric.Algebra as NA @@ -21,12 +19,10 @@ add_gf_2_8 :: GF 2 8 -> GF 2 8 -> GF 2 8 add_gf_2_8 = (NA.+) add_gf_2_8_Manual - :: SV.Sized P.Vector 8 (F 2) - -> SV.Sized P.Vector 8 (F 2) - -> SV.Sized P.Vector 8 (F 2) -add_gf_2_8_Manual = SV.zipWithSame (NA.+) - -inspect $ coreOf 'add_gf_2_8 + :: P.Vector (F 2) + -> P.Vector (F 2) + -> P.Vector (F 2) +add_gf_2_8_Manual = P.zipWith (NA.+) checkInspection :: Result -> Expectation @@ -44,10 +40,8 @@ main = hspec $ do it "doesn't contain type class dictionary" $ checkInspection $(inspectTest $ - 'add_gf_2_8 - `hasNoTypeClassesExcept` - [''LL.ListLike] + hasNoTypeClasses 'add_gf_2_8 ) - -- it "is almost equivalent to P.zipWith (+)" $ - -- checkInspection - -- $(inspectTest $ 'add_gf_2_8 ==- 'add_gf_2_8_Manual) + it "is almost equivalent to zipWith (+)" $ + checkInspection + $(inspectTest $ 'add_gf_2_8 ==- 'add_gf_2_8_Manual) diff --git a/halg-galois-fields/package.yaml b/halg-galois-fields/package.yaml index a020b4af..03825c5e 100644 --- a/halg-galois-fields/package.yaml +++ b/halg-galois-fields/package.yaml @@ -64,9 +64,9 @@ library: - sized - template-haskell - mono-traversable - - ListLike - vector - primitive + - subcategories - directory other-modules: - Algebra.Field.Galois.Conway @@ -99,5 +99,5 @@ tests: - vector - primitive - sized - - ListLike + - subcategories diff --git a/halg-galois-fields/src/Algebra/Field/Galois.hs b/halg-galois-fields/src/Algebra/Field/Galois.hs index 011faf73..9f9f2450 100644 --- a/halg-galois-fields/src/Algebra/Field/Galois.hs +++ b/halg-galois-fields/src/Algebra/Field/Galois.hs @@ -35,18 +35,20 @@ import Data.Kind (Type) import qualified Data.Ratio as Rat import Data.Reflection (Reifies (..), reify) import qualified Data.Sized.Builtin as SV -import qualified Data.Sized as Sized +import qualified Data.Sized.Builtin as Sized import qualified Data.Vector as V import qualified GHC.TypeLits as TL import qualified Numeric.Algebra as NA import qualified Prelude as P +import Control.Subcategory (CZip, Dom) import qualified Data.Vector.Primitive as Prim import Data.Singletons.TH (sCases) -import Data.MonoTraversable (MonoTraversable, otraverse, Element, MonoFoldable(oall)) import qualified Data.Vector.Generic as G -import qualified Data.ListLike as LL import Unsafe.Coerce (unsafeCoerce) import qualified Data.Coerce as DC +import Control.Subcategory.Foldable (CFreeMonoid) +import Control.Subcategory.Foldable (CFoldable(call)) +import Control.Subcategory (CTraversable(ctraverse)) #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 810 type GFSized :: forall k. forall (p :: k) -> Type -> Type @@ -95,7 +97,8 @@ type GF (p :: TL.Nat) n = GF' p n (Conway p n) modPoly :: forall k (p :: k) n f. ( KnownNat n, IsPrimeChar p, G.Vector (GFSized' k p) (F p), - LL.ListLike (GFSized' k p (F p)) (F p) + CFreeMonoid (GFSized' k p), + Dom (GFSized' k p) (F p) ) => Unipol (F p) -> GF' p n f modPoly = GF' . polyToVec @@ -107,7 +110,7 @@ modVec = GF' instance (IsGF' p n f, Show (F p)) => Show (GF' p n f) where showsPrec d (GF' (v SV.:< vs)) = - if oall isZero vs + if call isZero vs then showsPrec d v else showChar '<' . showString (showPolynomialWith (singleton "ξ") 0 $ vecToPoly $ v :< vs) . showChar '>' showsPrec _ _ = showString "0" @@ -133,7 +136,7 @@ vecToPoly v = sum $ imap (\i c -> injectCoeff c * varX^fromIntegral i) => Unipol (F p) -> SV.Sized Prim.Vector n (F p) #-} polyToVec :: forall n r v. - (CoeffRing r, KnownNat n, G.Vector v r, LL.ListLike (v r) r) + (CoeffRing r, KnownNat n, G.Vector v r, CFreeMonoid v, Dom v r) => Unipol r -> SV.Sized v n r polyToVec f = case zeroOrSucc (sing :: SNat n) of @@ -146,7 +149,7 @@ polyToVec f = mapSV :: forall f n a b. - (LL.ListLike (f a) a, LL.ListLike (f b) b) + (CFreeMonoid f, Dom f a, Dom f b) => (a -> b) -> SV.Sized f n a -> SV.Sized f n b {-# INLINE [1] mapSV #-} mapSV = SV.map @@ -166,8 +169,7 @@ mapSV = SV.map zipWithSameSV :: forall f a b c n. - ( LL.ListLike (f a) a, LL.ListLike (f b) b - , LL.ListLike (f c) c + ( CZip f, CFreeMonoid f, Dom f a, Dom f b, Dom f c ) => (a -> b -> c) -> SV.Sized f n a -> SV.Sized f n b -> SV.Sized f n c {-# INLINE [2] zipWithSameSV #-} @@ -203,24 +205,6 @@ zipWithFpBoxed = unsafeCoerce $ V.zipWith @(F p) @(F p) @(F p) zipWithSameSV = zipWithFpPrim @3 #-} -{-# SPECIALISE zipWithSame - :: (F p -> F p -> F p) - -> Sized n (F p) -> Sized n (F p) - -> Sized n (F p) - #-} -{-# SPECIALISE zipWithSame - :: (F 2 -> F 2 -> F 2) - -> SV.Sized Prim.Vector n (F 2) - -> SV.Sized Prim.Vector n (F 2) - -> SV.Sized Prim.Vector n (F 2) - #-} -{-# SPECIALISE zipWithSame - :: (F 3 -> F 3 -> F 3) - -> SV.Sized Prim.Vector n (F 3) - -> SV.Sized Prim.Vector n (F 3) - -> SV.Sized Prim.Vector n (F 3) - #-} - instance IsGF' p n f => Additive (GF' p n f) where (+) = DC.coerce $ zipWithSameSV @(GFSized' _ p) @(F p) @(F p) @(F p) @n (+) {-# INLINE (+) #-} @@ -275,10 +259,10 @@ instance (IsGF' p n f) => Ring (GF' p n f) where IsSucc k -> withKnownNat k $ GF' $ fromInteger n :< SV.replicate' zero instance (IsGF' p n f) => DecidableZero (GF' p n f) where - isZero (GF' sv) = oall isZero sv + isZero (GF' sv) = call isZero sv instance (IsGF' p n f) => DecidableUnits (GF' p n f) where - isUnit (GF' sv) = not $ oall isZero sv + isUnit (GF' sv) = not $ call isZero sv recipUnit a | isZero a = Nothing | otherwise = Just $ recip a @@ -339,10 +323,11 @@ withIrreducible :: forall p a. ( IsPrimeChar (p :: k), G.Vector (GFSized' k p) (F p), - MonoFoldable (GFSized' k p (F p)), - Element (GFSized' k p (F p)) ~ F p, - MonoTraversable (GFSized' k p (F p)), - LL.ListLike (GFSized' k p (F p)) (F p) + CFreeMonoid (GFSized' k p), + CTraversable (GFSized' k p), + Monoid (GFSized' k p (F p)), + CZip (GFSized' k p), + Dom (GFSized' k p) (F p) ) => Unipol (F p) -> (forall f (n :: Nat). (IsGF' p n f) => Proxy (GF' p n f) -> a) @@ -377,9 +362,6 @@ reifyGF' p n f = reifyPrimeField (P.toInteger p) $ \(pxy :: Proxy (F p)) -> do linearRepGF :: (IsGF' p n f) => GF' p n f -> V.Vector (F p) linearRepGF = G.convert . SV.unsized . runGF' -linearRepGFRaw :: (IsGF' (p :: k) n f) => GF' p n f -> GFSized' k p (F p) -linearRepGFRaw = G.convert . SV.unsized . runGF' - linearRepGF' :: (IsGF' p n f) => GF' p n f -> V.Vector Integer linearRepGF' = V.map naturalRepr . linearRepGF @@ -397,28 +379,30 @@ proxyGF' _ _ Proxy = Proxy class ( KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p)), G.Vector (GFSized' k p) (F p), - LL.ListLike (GFSized' k p (F p)) (F p), - MonoTraversable (GFSized' k p (F p)), - MonoFoldable (GFSized' k p (F p)), - Element (GFSized' k p (F p)) ~ F p + CTraversable (GFSized' k p), + CFreeMonoid (GFSized' k p), + Monoid (GFSized' k p (F p)), + CZip (GFSized' k p), + Dom (GFSized' k p) (F p) ) => IsGF' (p :: k) n f instance ( KnownNat n, IsPrimeChar p, Reifies f (Unipol (F p)), G.Vector (GFSized' k p) (F p), - LL.ListLike (GFSized' k p (F p)) (F p), - MonoFoldable (GFSized' k p (F p)), - MonoTraversable (GFSized' k p (F p)), - Element (GFSized' k p (F p)) ~ F p + CTraversable (GFSized' k p), + CZip (GFSized' k p), + CFreeMonoid (GFSized' k p), + Dom (GFSized' k p) (F p), + Monoid (GFSized' k p (F p)) ) - => IsGF' p n f + => IsGF' (p :: k) n f instance (KnownNat n, IsGF' p n f) => FiniteField (GF' p n f) where power _ = fromIntegral $ fromSing (sing :: SNat n) elements _ = let sn = sing :: SNat n - in P.map (GF' . SV.unsafeToSized') $ otraverse (const $ elements Proxy) + in P.map (GF' . SV.unsafeToSized') $ ctraverse (const $ elements Proxy) $ SV.unsized $ SV.replicate sn (0 :: F p) @@ -435,8 +419,8 @@ conway = conwayPolynomial instance IsGF' p n f => Random (GF' p n f) where random = runRand $ - GF' . SV.unsafeToSized' - <$> otraverse (const $ getRandom) (SV.unsized $ SV.replicate (sing :: SNat n) 0) + GF' . hoistSized + <$> ctraverse (const getRandom) (SV.replicate @V.Vector(sing :: SNat n) (0 :: Int)) randomR (GF' ls, GF' rs) = runRand $ GF' . hoistSized <$> sequence (zipWithSameSV (curry getRandomR) @@ -444,7 +428,10 @@ instance IsGF' p n f => Random (GF' p n f) where (hoistSized @V.Vector rs)) hoistSized - :: forall g f n a. (G.Vector f a, G.Vector g a, KnownNat n, LL.ListLike (g a) a) + :: forall g f n a. + ( G.Vector f a, G.Vector g a, KnownNat n, + Dom f a, Dom g a + ) => SV.Sized f n a -> SV.Sized g n a {-# INLINE hoistSized #-} -hoistSized = SV.unsafeToSized' . G.convert . SV.unsized \ No newline at end of file +hoistSized = SV.unsafeToSized' . G.convert . SV.unsized diff --git a/halg-polynomials/src/Algebra/Ring/Polynomial/Quotient.hs b/halg-polynomials/src/Algebra/Ring/Polynomial/Quotient.hs index cbba30c2..eac97ca4 100644 --- a/halg-polynomials/src/Algebra/Ring/Polynomial/Quotient.hs +++ b/halg-polynomials/src/Algebra/Ring/Polynomial/Quotient.hs @@ -252,7 +252,7 @@ stdMonoms basis = do -> Maybe [OrderedMonomial Grevlex 1] #-} -diag :: Unbox a => a -> a -> SNat n -> [USized n a] +diag :: (Unbox a) => a -> a -> SNat n -> [USized n a] diag d z n = [ generate n (\j -> if i == j then d else z) | i <- enumOrdinal n ] diff --git a/stack-808.yaml b/stack-808.yaml index 7f30510f..b2d9b599 100644 --- a/stack-808.yaml +++ b/stack-808.yaml @@ -21,3 +21,8 @@ extra-deps: - unamb-0.2.7 - control-monad-loop-0.1 - repa-3.4.1.4 +- git: https://github.com/konn/sized.git + commit: 57e36fb31222dbcdcd0bfc9303d2f07cf2f96b88 +- git: https://github.com/konn/subcategories.git + commit: 79c68f79ed77d24e35e5f7a4d580f9a8f5d0b71a + From b0aa4083ed83ffed1ed2d8c076838acf5961e72b Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 3 Sep 2020 21:21:52 +0900 Subject: [PATCH 57/62] Drops a support for GHC <= 8.4 --- .gitlab-ci.yml | 20 --------------- computational-algebra/package.yaml | 2 +- halg-algebraic/package.yaml | 2 +- halg-algorithms/package.yaml | 2 +- halg-bridge-singular/package.yaml | 2 +- halg-core-test/package.yaml | 2 +- halg-core/package.yaml | 2 +- halg-factor/package.yaml | 2 +- halg-galois-fields/package.yaml | 2 +- halg-heaps/package.yaml | 2 +- halg-matrices/package.yaml | 2 +- halg-polyn-parser/package.yaml | 2 +- halg-polynomials/package.yaml | 2 +- stack-804.yaml | 39 ------------------------------ 14 files changed, 12 insertions(+), 71 deletions(-) delete mode 100644 stack-804.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7fb69165..584b7339 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,15 +18,6 @@ stages: - '.apt/' - '.hspec-failures' -.header-ghc-84: &header-ghc-84 - image: registry.gitlab.com/konn/computational-algebra/build/ghc-8.4:0.6.0.0-p4 - variables: - STACK_YAML: "stack-804.yaml" - GHC: 804 - cache: - key: "${CI_COMMIT_REF_SLUG}-ghc-8.4" - <<: *cached-dirs - .header-ghc-86: &header-ghc-86 image: registry.gitlab.com/konn/computational-algebra/build/ghc-8.6:0.6.0.0-p3 variables: @@ -76,10 +67,6 @@ before_script: - stack exec --work-dir=.stack-no-coverage -- halg-core-opt-test - stack exec --work-dir=.stack-no-coverage -- halg-gf-opt-test -build:ghc-8.4: - <<: *header-ghc-84 - <<: *build-script - build:ghc-8.6: <<: *header-ghc-86 <<: *build-script @@ -92,13 +79,6 @@ build:ghc-8.10: <<: *header-ghc-810 <<: *build-script -test:ghc-8.4: - dependencies: - - build:ghc-8.4 - <<: *header-ghc-84 - <<: *test-script - coverage: '/^\s*(\d+\s*%)\s*top-level declarations used/' - test:ghc-8.6: dependencies: - build:ghc-8.6 diff --git a/computational-algebra/package.yaml b/computational-algebra/package.yaml index b7b59516..24dbabbf 100644 --- a/computational-algebra/package.yaml +++ b/computational-algebra/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package # synopsis: Short description of your package diff --git a/halg-algebraic/package.yaml b/halg-algebraic/package.yaml index f5eea8be..ca4593ca 100644 --- a/halg-algebraic/package.yaml +++ b/halg-algebraic/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: Algebraic reals, part of halg computational algebra suite. diff --git a/halg-algorithms/package.yaml b/halg-algorithms/package.yaml index fa27f131..bd8e961a 100644 --- a/halg-algorithms/package.yaml +++ b/halg-algorithms/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: Algorithms related to Gröbner basis, part of halg computational algebra suite. diff --git a/halg-bridge-singular/package.yaml b/halg-bridge-singular/package.yaml index 21a51231..0bda1034 100644 --- a/halg-bridge-singular/package.yaml +++ b/halg-bridge-singular/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: Bridge interface between Singular and halg computational algebra suite. diff --git a/halg-core-test/package.yaml b/halg-core-test/package.yaml index 416f9632..aa058d99 100644 --- a/halg-core-test/package.yaml +++ b/halg-core-test/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package # synopsis: Short description of your package diff --git a/halg-core/package.yaml b/halg-core/package.yaml index 56e53ca3..d3f54742 100644 --- a/halg-core/package.yaml +++ b/halg-core/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: Core types and functions of halg computational algebra suite. diff --git a/halg-factor/package.yaml b/halg-factor/package.yaml index c0a314ec..ef1d695b 100644 --- a/halg-factor/package.yaml +++ b/halg-factor/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: Polynomial factorisation algorithms, part of halg computational algebra suite. diff --git a/halg-galois-fields/package.yaml b/halg-galois-fields/package.yaml index 03825c5e..10211aa4 100644 --- a/halg-galois-fields/package.yaml +++ b/halg-galois-fields/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: General Galois fields, part of halg computational algebra suite. diff --git a/halg-heaps/package.yaml b/halg-heaps/package.yaml index 711d64dd..7c7c6f60 100644 --- a/halg-heaps/package.yaml +++ b/halg-heaps/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: Various heap structures diff --git a/halg-matrices/package.yaml b/halg-matrices/package.yaml index db4e5442..58f85c2c 100644 --- a/halg-matrices/package.yaml +++ b/halg-matrices/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: Abstraction layer ror various matrix libraries, part of halg computational algebra suite. diff --git a/halg-polyn-parser/package.yaml b/halg-polyn-parser/package.yaml index e701ef1e..665c6bd0 100644 --- a/halg-polyn-parser/package.yaml +++ b/halg-polyn-parser/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: Polynomial parsers, part of halg computational algebra suite. diff --git a/halg-polynomials/package.yaml b/halg-polynomials/package.yaml index d9b725f6..1813a4d2 100644 --- a/halg-polynomials/package.yaml +++ b/halg-polynomials/package.yaml @@ -11,7 +11,7 @@ extra-source-files: - ChangeLog.md tested-with: | - GHC == 8.4.3, GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 + GHC == 8.6.5, GHC == 8.8.2, GHC == 8.10.1 # Metadata used when publishing your package synopsis: | diff --git a/stack-804.yaml b/stack-804.yaml deleted file mode 100644 index 6f961cc2..00000000 --- a/stack-804.yaml +++ /dev/null @@ -1,39 +0,0 @@ -resolver: lts-12.2 - -flags: {} -packages: -- 'computational-algebra' -- 'algebraic-prelude' -- 'halg-algebraic' -- 'halg-algorithms' -- 'halg-bridge-singular' -- 'halg-core' -- 'halg-core-test' -- 'halg-factor' -- 'halg-galois-fields' -- 'halg-heaps' -- 'halg-matrices' -- 'halg-polyn-parser' -- 'halg-polynomials' - -extra-deps: -- arithmoi-0.9.0.0 -- control-monad-loop-0.1 -- equational-reasoning-0.5.1.0 -- exact-pi-0.5.0.1 -- ghc-typelits-presburger-0.3.0.0 -- hspec-2.6.1 -- hspec-core-2.6.1 -- hspec-discover-2.6.1 -- inspection-testing-0.4.2.4 -- megaparsec-7.0.5 -- parser-combinators-1.1.0 -- QuickCheck-2.12.6.1 -- quickcheck-instances-0.3.19 -- repa-3.4.1.4 -- repa-algorithms-3.4.1.3 -- semirings-0.5.3 -- singletons-presburger-0.3.0.0 -- sized-0.3.0.0 -- type-natural-0.8.1.0 -- unamb-0.2.7 From ac3f40bf4a59d2d16edc07d86c0aea7521063ef3 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 3 Sep 2020 21:22:03 +0900 Subject: [PATCH 58/62] Adds missing extra-deps --- stack-806.yaml | 6 +++++- stack-810.yaml | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/stack-806.yaml b/stack-806.yaml index 25c45d19..b66455ef 100644 --- a/stack-806.yaml +++ b/stack-806.yaml @@ -22,6 +22,10 @@ extra-deps: - singletons-presburger-0.3.0.1 - type-natural-0.8.3.1 - algebra-4.3.1@rev:2 -- sized-0.4.0.0 - unamb-0.2.7 - control-monad-loop-0.1 +- git: https://github.com/konn/sized.git + commit: 57e36fb31222dbcdcd0bfc9303d2f07cf2f96b88 +- git: https://github.com/konn/subcategories.git + commit: 79c68f79ed77d24e35e5f7a4d580f9a8f5d0b71a + diff --git a/stack-810.yaml b/stack-810.yaml index 23321e98..8606e7b2 100644 --- a/stack-810.yaml +++ b/stack-810.yaml @@ -21,3 +21,7 @@ extra-deps: - control-monad-loop-0.1 - repa-3.4.1.4 - unamb-0.2.7 +- git: https://github.com/konn/sized.git + commit: 57e36fb31222dbcdcd0bfc9303d2f07cf2f96b88 +- git: https://github.com/konn/subcategories.git + commit: 79c68f79ed77d24e35e5f7a4d580f9a8f5d0b71a From 72e2f54ee0b2d3a6744954bee5629ba28ecd5c31 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 3 Sep 2020 21:24:21 +0900 Subject: [PATCH 59/62] corrects duplicated key --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 584b7339..e99ef775 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -36,7 +36,7 @@ stages: key: "${CI_COMMIT_REF_SLUG}-ghc-8.8" <<: *cached-dirs -.header-ghc-88: &header-ghc-810 +.header-ghc-810: &header-ghc-810 image: registry.gitlab.com/konn/computational-algebra/build/ghc-8.10:0.6.0.0 variables: STACK_YAML: "stack-810.yaml" From 2f699cf46eb8de287758e07ef383e1f7325e323e Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Thu, 3 Sep 2020 21:27:57 +0900 Subject: [PATCH 60/62] Defines isGF constraint --- halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs | 2 +- halg-galois-fields/src/Algebra/Field/Galois.hs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs b/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs index f0dda830..d7c6e1ad 100644 --- a/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs +++ b/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs @@ -82,7 +82,7 @@ regressions = ξ :: GF 2 5 ξ = primitive -instance (IsPrimeChar p, KnownNat n, ConwayPolynomial p n) +instance (IsGF p n, KnownNat n, ConwayPolynomial p n) => Arbitrary (GF p n) where arbitrary = QC.elements $ Fin.elements $ Proxy @(GF p n) diff --git a/halg-galois-fields/src/Algebra/Field/Galois.hs b/halg-galois-fields/src/Algebra/Field/Galois.hs index 9f9f2450..e9c32ab1 100644 --- a/halg-galois-fields/src/Algebra/Field/Galois.hs +++ b/halg-galois-fields/src/Algebra/Field/Galois.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE ConstraintKinds #-} #if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 810 {-# LANGUAGE StandaloneKindSignatures #-} #endif @@ -12,7 +13,7 @@ {-# LANGUAGE UndecidableSuperClasses #-} {-# OPTIONS_GHC -Wno-orphans #-} module Algebra.Field.Galois - ( GF'(), IsGF', modPoly, modVec, + ( GF'(), IsGF', IsGF, modPoly, modVec, withIrreducible, linearRepGF, linearRepGF', reifyGF', generateIrreducible, withGF', GF, ConwayPolynomial(..), @@ -106,6 +107,8 @@ modPoly = GF' . polyToVec modVec :: SV.Sized (GFSized' k p) n (F p) -> GF' p n f modVec = GF' +class IsGF' p n (Conway p n) => IsGF p n +instance IsGF' p n (Conway p n) => IsGF p n instance (IsGF' p n f, Show (F p)) => Show (GF' p n f) where From ae8f51c61bc1c65f7d446480cadcd6b4cd814a6e Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sun, 6 Sep 2020 12:24:41 +0900 Subject: [PATCH 61/62] Updates `sized` hash --- stack-806.yaml | 2 +- stack-808.yaml | 2 +- stack-810.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stack-806.yaml b/stack-806.yaml index b66455ef..fc109b39 100644 --- a/stack-806.yaml +++ b/stack-806.yaml @@ -25,7 +25,7 @@ extra-deps: - unamb-0.2.7 - control-monad-loop-0.1 - git: https://github.com/konn/sized.git - commit: 57e36fb31222dbcdcd0bfc9303d2f07cf2f96b88 + commit: 76a441ea6a19ad6fadb9c4a683730781f07c17a2 - git: https://github.com/konn/subcategories.git commit: 79c68f79ed77d24e35e5f7a4d580f9a8f5d0b71a diff --git a/stack-808.yaml b/stack-808.yaml index b2d9b599..c467b26a 100644 --- a/stack-808.yaml +++ b/stack-808.yaml @@ -22,7 +22,7 @@ extra-deps: - control-monad-loop-0.1 - repa-3.4.1.4 - git: https://github.com/konn/sized.git - commit: 57e36fb31222dbcdcd0bfc9303d2f07cf2f96b88 + commit: 76a441ea6a19ad6fadb9c4a683730781f07c17a2 - git: https://github.com/konn/subcategories.git commit: 79c68f79ed77d24e35e5f7a4d580f9a8f5d0b71a diff --git a/stack-810.yaml b/stack-810.yaml index 8606e7b2..367c940b 100644 --- a/stack-810.yaml +++ b/stack-810.yaml @@ -22,6 +22,6 @@ extra-deps: - repa-3.4.1.4 - unamb-0.2.7 - git: https://github.com/konn/sized.git - commit: 57e36fb31222dbcdcd0bfc9303d2f07cf2f96b88 + commit: 76a441ea6a19ad6fadb9c4a683730781f07c17a2 - git: https://github.com/konn/subcategories.git commit: 79c68f79ed77d24e35e5f7a4d580f9a8f5d0b71a From 172cb8bed662189b24d83a7af864674031cd2b24 Mon Sep 17 00:00:00 2001 From: Hiromi ISHII Date: Sun, 6 Sep 2020 12:54:24 +0900 Subject: [PATCH 62/62] Corrects target name --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e99ef775..f261018a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -57,7 +57,7 @@ before_script: - echo "$STACK_YAML" - stack setup - stack build --no-terminal --test --no-run-tests --coverage - - stack build --no-terminal --work-dir=.stack-no-coverage --flag halg-core-test:opt-test --flag halg-galois-fields:opt-test halg-core-test:exe:halg-core-opt-test halg-galois-fields:text:halg-gf-opt-test + - stack build --no-terminal --work-dir=.stack-no-coverage --flag halg-core-test:opt-test --flag halg-galois-fields:opt-test halg-core-test:exe:halg-core-opt-test halg-galois-fields:test:halg-gf-opt-test .test-script: &test-script stage: test