diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 45a30c1f..f261018a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,20 +11,13 @@ stages: .cached_dirs: &cached-dirs paths: - '.stack-work/' + - '.stack-no-coverage/' - '.stack-root/' - '*/.stack-work' + - '*/.stack-no-coverage' - '.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: @@ -35,7 +28,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 @@ -43,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" @@ -64,16 +57,15 @@ 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:test:halg-gf-opt-test .test-script: &test-script stage: test script: - stack setup - stack --no-terminal test --no-rerun-tests --coverage - -build:ghc-8.4: - <<: *header-ghc-84 - <<: *build-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.6: <<: *header-ghc-86 @@ -87,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 @@ -115,7 +100,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: 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/.vscode/settings.json b/.vscode/settings.json index fe582f39..8e2aeb7f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,9 @@ "**/.stack-prof/": true, "**/.stack-work/": true, "heap-poly": true - } + }, + "stylishHaskell.showConsoleOnError": false, + "haskell.formattingProvider": "none", + "editor.defaultFormatter": "vigoo.stylish-haskell", + "editor.formatOnSave": true } \ No newline at end of file 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/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/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 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 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 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) + diff --git a/computational-algebra/package.yaml b/computational-algebra/package.yaml index 278edd79..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 @@ -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 @@ -105,12 +101,8 @@ _profile-cond: &profile-cond else: buildable: false ghc-options: - - -caf-all - - -auto-all - -rtsopts - -eventlog - - -prof - - -fprof-auto-exported _examples: &examples algebraic: 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-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 diff --git a/halg-core-test/opt-test/Inspection.hs b/halg-core-test/opt-test/Inspection.hs new file mode 100644 index 00000000..976fd1d6 --- /dev/null +++ b/halg-core-test/opt-test/Inspection.hs @@ -0,0 +1,204 @@ +{-# 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 Inspection (main) where +import Algebra.Arithmetic (modPow) +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 + +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.+) + +fLargeAddAlgebra :: F LargeP -> F LargeP -> F LargeP +fLargeAddAlgebra = (NA.+) + +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.^) + +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 + +f59ModPow :: WrapIntegral Int -> Natural -> WrapIntegral Int +f59ModPow i n = modPow i 59 n + +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 + ) + +main :: IO () +main = hspec $ 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 "(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) + 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 ("NA.recip") $ do + 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" $ + 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" + $ 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 Int 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) diff --git a/halg-core-test/package.yaml b/halg-core-test/package.yaml index 72fae372..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 @@ -34,6 +34,63 @@ 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: + 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 >= 2.12 + - arithmoi >= 0.9 + - hspec + - template-haskell diff --git a/halg-core-test/src/Algebra/Field/Prime/Test.hs b/halg-core-test/src/Algebra/Field/Prime/Test.hs index 44ca2907..c081c0a0 100644 --- a/halg-core-test/src/Algebra/Field/Prime/Test.hs +++ b/halg-core-test/src/Algebra/Field/Prime/Test.hs @@ -4,14 +4,15 @@ 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 Test.QuickCheck (Arbitrary (..)) +import Algebra.Field.Prime (F, IsPrimeChar, charInfo, modNat) +import Data.Proxy +import Prelude (Maybe (..), Monad, fromIntegral, (-), (<$>)) +import Test.QuickCheck (Arbitrary (..), resize) import Test.SmallCheck.Series (Serial (..)) -instance Reifies p Integer => Arbitrary (F p) where - arbitrary = arbitraryFiniteField (Nothing :: Maybe (F p)) +instance IsPrimeChar p => Arbitrary (F p) where + arbitrary = modNat <$> + resize (fromIntegral (charInfo (Proxy :: Proxy p)) - 1) arbitrary -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-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-test/test/Algebra/Field/PrimeSpec.hs b/halg-core-test/test/Algebra/Field/PrimeSpec.hs new file mode 100644 index 00000000..abcc975e --- /dev/null +++ b/halg-core-test/test/Algebra/Field/PrimeSpec.hs @@ -0,0 +1,78 @@ +{-# LANGUAGE DataKinds, DerivingStrategies, GADTs #-} +{-# 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 + -dsuppress-uniques + #-} +module Algebra.Field.PrimeSpec where +import Algebra.Field.Finite.Test () +import Algebra.Field.Prime +import Algebra.Field.Prime.Test () +import AlgebraicPrelude +import Data.Proxy (Proxy (..)) +import GHC.TypeLits (Nat) +import Language.Haskell.TH +import Math.NumberTheory.Primes +import Test.Hspec +import Test.Hspec.QuickCheck +import Test.QuickCheck hiding (elements) +import qualified Test.QuickCheck as QC + +bigEnoughPrime :: Prime Integer +bigEnoughPrime = precPrime $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int + +type LargeP = $(litT $ numTyLit $ unPrime + $ nextPrime $ floor @Double + $ sqrt $ fromIntegral $ maxBound @Int) + +spec :: Spec +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 + +newtype SmallPrime = SmallPrime { runSmallPrime :: Integer } + deriving newtype (Show) + +instance Arbitrary SmallPrime where + arbitrary = SmallPrime . unPrime + <$> 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 10 [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 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/package.yaml b/halg-core/package.yaml index 4371e6de..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. @@ -37,7 +37,6 @@ default-extensions: - UndecidableInstances dependencies: -- ListLike - MonadRandom - algebra - algebraic-prelude @@ -50,6 +49,7 @@ dependencies: - equational-reasoning - ghc-typelits-knownnat - ghc-typelits-presburger >= 0.2.0.5 +- singletons-presburger - hashable - intern - lens @@ -57,13 +57,21 @@ dependencies: - reflection - singletons - sized +- subcategories - type-natural - unordered-containers - vector +- vector-th-unbox +- primitive +- vector-algorithms +- vector-builder - vector-instances 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..6baee293 100644 --- a/halg-core/src/Algebra/Arithmetic.hs +++ b/halg-core/src/Algebra/Arithmetic.hs @@ -2,29 +2,23 @@ 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 [] - where - go 0 = id - go k = go (k `div` 2) . ((k `mod` 2) :) +repeatedSquare :: Unital r => r -> Natural -> r +repeatedSquare = pow -- | Fermat-test for pseudo-primeness. fermatTest :: MonadRandom m => Integer -> m PrimeResult diff --git a/halg-core/src/Algebra/Field/Prime.hs b/halg-core/src/Algebra/Field/Prime.hs index 1817e876..bb0380d8 100644 --- a/halg-core/src/Algebra/Field/Prime.hs +++ b/halg-core/src/Algebra/Field/Prime.hs @@ -1,14 +1,26 @@ -{-# LANGUAGE DerivingStrategies, GeneralizedNewtypeDeriving #-} -{-# LANGUAGE StandaloneDeriving #-} +#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 #-} +{-# LANGUAGE RankNTypes, ScopedTypeVariables, StandaloneDeriving #-} +{-# LANGUAGE TemplateHaskell, TypeApplications, TypeFamilies #-} +{-# LANGUAGE TypeOperators, UndecidableInstances, UndecidableSuperClasses #-} +{-# OPTIONS_GHC -Wno-orphans #-} +{-# 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, charInfo, + naturalRepr, reifyPrimeField, withPrimeField, + modNat, modNat', modRat, modRat', + FiniteField(..), order, + -- * Auxiliary interfaces + HasPrimeField(..), + -- ** Internals + wrapF, liftFUnary, liftBinF, WORD_MAX_BOUND + ) where import Algebra.Arithmetic (modPow) import Algebra.Field.Finite import Algebra.Normed @@ -19,217 +31,447 @@ import Control.DeepSeq (NFData (..)) import Control.Monad.Random (getRandomR) import Control.Monad.Random (runRand) import Control.Monad.Random (Random (..)) -import qualified Data.Coerce as C -import Data.Maybe (fromMaybe) +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) +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 Data.Primitive.Types 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. -newtype F (p :: k) = F { runF :: Integer } - deriving (NFData, Hashable) +newtype F (p :: k) = F { runF :: F' p } + -- deriving (NFData) --- | Caution: just for use with Map or Sets; --- no guarantee for the compatibility with --- field structure and normal forms! -deriving newtype instance Ord (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 -instance Reifies p Integer => Read (F p) where +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) + 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 #-} SingI (WORD_MAX_BOUND <=? p) => NFData (F p) where + {-# INLINE rnf #-} + rnf = case sing :: Sing (WORD_MAX_BOUND <=? 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 +{-# SPECIALISE INLINE + charInfo :: ((WORD_MAX_BOUND <=? p) ~ 'False, KnownNat 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 +{-# 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 +{-# 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)) + +unwrapBinF + :: IsPrimeChar p + => (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 + :: IsPrimeChar p + => (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 + 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 :: Sing (WORD_MAX_BOUND <=? p) of + STrue -> F $ f i + SFalse -> F $ f i + {-# INLINE unwrapF #-} + unwrapF f = \(F i :: F p) -> + case sing :: Sing (WORD_MAX_BOUND <=? p) of + STrue -> f i + SFalse -> f i + {-# INLINE wrapF_ #-} + wrapF_ s = + (case sing :: Sing (WORD_MAX_BOUND <=? p) of + STrue -> F s + 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 + liftFUnary_ f = \(F p) -> F $ f p + wrapF_ = F + unwrapF f = \(F p) -> f 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 {-# INLINE modNat #-} -modNat' :: forall proxy p. Reifies p Integer => proxy (F p) -> Integer -> F p -modNat' _ i = - let p = reflect (Proxy :: Proxy p) - in F (i `rem` 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 {-# INLINE modNat' #-} -reifyPrimeField :: Integer -> (forall p. KnownNat p => 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 +reifyPrimeField + :: Integer + -> (forall p. IsPrimeChar (p :: Nat) => Proxy (F p) -> a) -> a +reifyPrimeField p f = reifyNat p $ \(_ :: Proxy p) -> + withSingI (unsafeCoerce $ + (sing :: Sing WORD_MAX_BOUND) + %<= (sing :: Sing p) :: Sing (WORD_MAX_BOUND <=? p)) + $ f $ Proxy @(F p) -naturalRepr :: F p -> Integer -naturalRepr = runF +withPrimeField :: Integer -> (forall p. IsPrimeChar (p :: Nat) => F p) -> Integer +withPrimeField p f = reifyPrimeField p $ unwrapF toInteger . asProxyTypeOf f -proxyF :: Proxy (a :: k) -> Proxy (F a) -proxyF Proxy = Proxy +naturalRepr :: IsPrimeChar p => F p -> Integer +naturalRepr = unwrapF toInteger -instance Eq (F p) where - F n == F m = n == m +instance IsPrimeChar p => Eq (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => Eq (F p) #-} + (==) = 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 + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => P.Num (F p) #-} 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 - 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 + {-# 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 #-} +pows = flip $ \n -> unwrapF $ \a -> + wrapF_ $ fromIntegral $ + modPow + (WrapIntegral a) + (WrapIntegral $ fromInteger $ charInfo $ Proxy @p) n + +instance IsPrimeChar p => NA.Additive (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => Additive (F p) #-} + (+) = plus {-# 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 + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => Multiplicative (F p) #-} + (*) = mulP {-# INLINE (*) #-} - pow1p n p = pows n (p P.+ 1) + pow1p n = pows n . succ {-# INLINE pow1p #-} -instance Reifies p Integer => NA.Monoidal (F p) where - zero = F 0 +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 (F k) = modNat $ P.fromIntegral n * k + sinnum n = liftFUnary $ \k -> P.fromIntegral n P.* k {-# INLINE sinnum #-} + sumWith f = foldl' (\a b -> a + f b) zero + {-# INLINE sumWith #-} -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 + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => LeftModule Natural (F p) #-} + (.*) 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 + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => RightModule Natural (F p) #-} + (*.) = 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 + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => LeftModule Integer (F p) #-} + (.*) 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 + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => RightModule Integer (F p) #-} + (*.) = 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 + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => Group (F p) #-} + (-) = minus {-# INLINE (-) #-} - negate (F a) = modNat $ negate a + negate = negP {-# INLINE negate #-} -instance Reifies p Integer => NA.Abelian (F p) + subtract = flip minus + {-# INLINE subtract #-} + + times n = liftFUnary (fromIntegral n P.*) + {-# INLINE times #-} -instance Reifies p Integer => NA.Semiring (F p) +instance IsPrimeChar p => NA.Abelian (F p) -instance Reifies p Integer => NA.Rig (F p) where +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 Reifies p Integer => NA.Ring (F p) where +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 Reifies p Integer => NA.DecidableZero (F p) where - isZero (F p) = p == 0 +instance IsPrimeChar p => NA.DecidableZero (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => DecidableZero (F p) #-} + isZero = unwrapF (== 0) -instance Reifies p Integer => NA.Unital (F p) where - one = F 1 +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 #-} + productWith f = foldl' (\a b -> a * f b) one + {-# INLINE productWith #-} -instance Reifies p Integer => DecidableUnits (F p) where - isUnit (F n) = n /= 0 +instance IsPrimeChar p => DecidableUnits (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => DecidableUnits (F p) #-} + 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 = \k -> + if k == 0 + then Nothing + else Just $ recip k {-# INLINE recipUnit #-} -instance (Reifies p Integer) => DecidableAssociates (F p) where +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 #-} -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 Reifies p Integer => Division (F p) where - recip = fromMaybe (error "recip: not unit") . recipUnit +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 IsPrimeChar p => Division (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => Division (F p) #-} + 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 (/) #-} + (\\) = flip (/) + {-# INLINE (\\) #-} (^) = pows {-# INLINE (^) #-} -instance Reifies p Integer => P.Fractional (F p) where - (/) = C.coerce ((P./) :: WrapAlgebra (F p) -> WrapAlgebra (F p) -> WrapAlgebra (F p)) +instance IsPrimeChar p => P.Fractional (F p) where + {-# SPECIALISE instance (IsPrimeChar p, (WORD_MAX_BOUND <=? p) ~ 'False) + => P.Fractional (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 Reifies p Integer => NA.Commutative (F p) +instance IsPrimeChar p => NA.Commutative (F p) -instance Reifies p Integer => NA.Characteristic (F p) where - char _ = fromIntegral $ reflect (Proxy :: Proxy p) +instance IsPrimeChar p => NA.Characteristic (F p) where + char _ = fromIntegral $ charInfo (Proxy :: Proxy p) {-# INLINE char #-} +instance IsPrimeChar p => Show (F p) where + showsPrec d = unwrapF $ showsPrec d -instance Reifies (p :: k) Integer => Show (F p) where - showsPrec d n@(F p) = showsPrec d (p `rem` reflect n) +instance IsPrimeChar p => PrettyCoeff (F p) where + showsCoeff d = unwrapF $ \p -> + if | p == 0 -> Vanished + | p == 1 -> OneCoeff + | otherwise -> Positive $ showsPrec d p + {-# INLINE showsCoeff #-} -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 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 $ modNat <$> - getRandomR (0 :: Integer, reflect (Proxy :: Proxy p) - 1) + getRandomR (0 :: Integer, charInfo (Proxy :: Proxy p) - 1) {-# INLINE random #-} randomR (a, b) = runRand $ modNat <$> getRandomR (naturalRepr a, naturalRepr b) @@ -242,3 +484,12 @@ 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|] + +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..917283bf 100644 --- a/halg-core/src/Algebra/Instances.hs +++ b/halg-core/src/Algebra/Instances.hs @@ -1,21 +1,26 @@ -{-# LANGUAGE DataKinds, FlexibleContexts, FlexibleInstances, GADTs #-} -{-# LANGUAGE MultiParamTypeClasses, TypeFamilies #-} -{-# OPTIONS_GHC -fno-warn-orphans #-} +{-# 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 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.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.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 (+) @@ -171,3 +176,48 @@ 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 + +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 (chead xs) (ctail xs) + ofoldr1Ex = cfoldr1 + 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 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 ac439231..9fd8bb42 100644 --- a/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs +++ b/halg-core/src/Algebra/Ring/Polynomial/Monomial.hs @@ -28,28 +28,21 @@ 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) -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-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/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] diff --git a/halg-factor/package.yaml b/halg-factor/package.yaml index 8c20df18..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. @@ -59,6 +59,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 diff --git a/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs b/halg-factor/test/Algebra/Ring/Polynomial/FactoriseSpec.hs index 0c5c3f27..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 (KnownNat 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/opt-test/halg-gf-opt-test.hs b/halg-galois-fields/opt-test/halg-gf-opt-test.hs new file mode 100644 index 00000000..ed775ae3 --- /dev/null +++ b/halg-galois-fields/opt-test/halg-gf-opt-test.hs @@ -0,0 +1,47 @@ +{-# 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.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 + :: P.Vector (F 2) + -> P.Vector (F 2) + -> P.Vector (F 2) +add_gf_2_8_Manual = P.zipWith (NA.+) + +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 $ + hasNoTypeClasses 'add_gf_2_8 + ) + 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 69e24ab1..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. @@ -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 - vector + - primitive + - subcategories + - 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 + - subcategories + diff --git a/halg-galois-fields/src/Algebra/Field/Galois.hs b/halg-galois-fields/src/Algebra/Field/Galois.hs index 70ad8939..e9c32ab1 100644 --- a/halg-galois-fields/src/Algebra/Field/Galois.hs +++ b/halg-galois-fields/src/Algebra/Field/Galois.hs @@ -1,48 +1,93 @@ -{-# LANGUAGE DataKinds, DerivingStrategies, FlexibleContexts #-} +{-# LANGUAGE ConstraintKinds #-} +#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 #-} -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 #-} +{-# OPTIONS_GHC -Wno-orphans #-} +module Algebra.Field.Galois + ( GF'(), IsGF', 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.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.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 qualified Data.Vector.Generic as G +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 +#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) } - deriving newtype (NFData) -deriving instance Reifies p Integer => Eq (GF' p n f) +newtype GF' p (n :: TL.Nat) (f :: Type) = GF' { runGF' :: GFSized p n (F p) } + +deriving newtype instance + 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 @@ -50,29 +95,52 @@ 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 k (p :: k) n f. + ( KnownNat n, IsPrimeChar p, + G.Vector (GFSized' k p) (F p), + CFreeMonoid (GFSized' k p), + Dom (GFSized' k 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 (Reifies p Integer, Show (F p)) => Show (GF' p n f) where - showsPrec d (GF' (v :< vs)) = - if F.all isZero vs +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 + showsPrec d (GF' (v SV.:< vs)) = + if call 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 (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, CFreeMonoid v, Dom v r) + => Unipol r -> SV.Sized v n r polyToVec f = case zeroOrSucc (sing :: SNat n) of IsZero -> SV.empty @@ -82,97 +150,156 @@ polyToVec f = | i <- [0..fromIntegral (fromSing (sing :: SNat n)) P.- 1] ] -instance Reifies p Integer => 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 +mapSV + :: forall f n a 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 + +{-# 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. + ( 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 #-} +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 + #-} + +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 Reifies p Integer => 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 Reifies p Integer => 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 Reifies p Integer => 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 Reifies p Integer => 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, Reifies p Integer) => 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 (Reifies p Integer) => Abelian (GF' p n f) +instance (IsGF' p n f) => Abelian (GF' p n f) -instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) +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)), Reifies p Integer) => 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)), Reifies p Integer) => Semiring (GF' p n f) +instance (IsGF' p n f) => Semiring (GF' p n f) -instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => 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)), Reifies p Integer) => Commutative (GF' p n f) +instance (IsGF' p n f) => Commutative (GF' p n f) -instance (KnownNat n, Reifies f (Unipol (F p)), Reifies p Integer) => 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, Reifies p Integer) => 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) = call isZero sv -instance (KnownNat n, Reifies p Integer, 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 $ call isZero sv recipUnit a | isZero a = Nothing | otherwise = Just $ recip a -instance (Reifies p Integer, 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 (Reifies p Integer, 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, Reifies p Integer, 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, Reifies p Integer, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => ZeroProductSemiring (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => UnitNormalForm (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => IntegralDomain (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => GCDDomain (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => UFD (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => PID (GF' p n f) -instance (KnownNat n, Reifies p Integer, Reifies f (Unipol (F p))) +instance (IsGF' p n f) => Euclidean (GF' p n f) -instance (Reifies p Integer, 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 @@ -181,7 +308,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 (IsGF' p n f) => P.Fractional (GF' p n f) where fromRational u = fromInteger (Rat.numerator u) / fromInteger (Rat.denominator u) (/) = (/) recip = recip @@ -195,34 +322,55 @@ 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 - => 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), + 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) + -> a withIrreducible r f = case toSing (fromIntegral $ totalDegree' r) of SomeSing sn -> 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' p n f = reifyPrimeField (P.toInteger p) $ \pxy -> do + reify r (f . proxyGF' (Proxy :: Proxy (F p)) sn) + +reifyGF' + :: 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 :: 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 :: GF' p n f -> V.Vector (F p) -linearRepGF = SV.unsized . runGF' - -linearRepGF' :: 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' + +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) . (Reifies p Integer, 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 @@ -231,18 +379,35 @@ 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)), + G.Vector (GFSized' k 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), + 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 :: k) 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 _ = let sn = sing :: SNat n - in P.map GF' $ T.sequence $ - SV.replicate sn $ elements Proxy + in P.map (GF' . SV.unsafeToSized') $ ctraverse (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|] @@ -257,7 +422,19 @@ conway = conwayPolynomial instance IsGF' p n f => Random (GF' p n f) where random = runRand $ - GF' <$> sequence (SV.replicate' getRandom) + GF' . hoistSized + <$> ctraverse (const getRandom) (SV.replicate @V.Vector(sing :: SNat n) (0 :: Int)) 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, + 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 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 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/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/hie.yaml b/hie.yaml index fbbd42fc..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" @@ -45,6 +48,10 @@ cradle: - path: "halg-core/src" 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-core/bench/prime-field-simple-bench.hs" component: "halg-core:bench:prime-field-simple-bench" 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 deleted file mode 100644 index ac2a6e59..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: -- control-monad-loop-0.1 -- equational-reasoning-0.5.1.0 -- ghc-typelits-presburger-0.3.0.0 -- singletons-presburger-0.3.0.0 -- sized-0.3.0.0 -- type-natural-0.8.1.0 -- unamb-0.2.7 -- parser-combinators-1.1.0 -- megaparsec-7.0.5 -- arithmoi-0.9.0.0 -- exact-pi-0.5.0.1 -- semirings-0.5.3 -- 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 -- inspection-testing-0.4.2.4 \ No newline at end of file diff --git a/stack-806.yaml b/stack-806.yaml index 25c45d19..fc109b39 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: 76a441ea6a19ad6fadb9c4a683730781f07c17a2 +- git: https://github.com/konn/subcategories.git + commit: 79c68f79ed77d24e35e5f7a4d580f9a8f5d0b71a + diff --git a/stack-808.yaml b/stack-808.yaml index fa3ab6f6..c467b26a 100644 --- a/stack-808.yaml +++ b/stack-808.yaml @@ -1,4 +1,4 @@ -resolver: lts-15.0 +resolver: lts-15.15 flags: {} packages: @@ -20,4 +20,9 @@ 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/sized.git + commit: 76a441ea6a19ad6fadb9c4a683730781f07c17a2 +- git: https://github.com/konn/subcategories.git + commit: 79c68f79ed77d24e35e5f7a4d580f9a8f5d0b71a + diff --git a/stack-810.yaml b/stack-810.yaml index 23321e98..367c940b 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: 76a441ea6a19ad6fadb9c4a683730781f07c17a2 +- git: https://github.com/konn/subcategories.git + commit: 79c68f79ed77d24e35e5f7a4d580f9a8f5d0b71a diff --git a/stack-prof.yaml b/stack-prof.yaml index cdb0206d..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": -fprof-auto + "$everything": -fno-prof-auto -fno-prof-cafs + "$locals": -fno-prof-auto -fno-prof-cafs packages: - 'computational-algebra' 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