packages feed

arithmoi-0.12.1.0: test-suite/Math/NumberTheory/Primes/FactorisationTests.hs

-- |
-- Module:      Math.NumberTheory.Primes.FactorisationTests
-- Copyright:   (c) 2017 Andrew Lelechenko
-- Licence:     MIT
-- Maintainer:  Andrew Lelechenko <andrew.lelechenko@gmail.com>
--
-- Tests for Math.NumberTheory.Primes.Factorisation
--

{-# OPTIONS_GHC -fno-warn-type-defaults #-}

module Math.NumberTheory.Primes.FactorisationTests
  ( testSuite
  ) where

import Test.Tasty
import Test.Tasty.HUnit

import Control.Arrow
import Control.Monad (zipWithM_)
import Data.List (nub, sort)
import Data.Maybe

import Math.NumberTheory.Primes
import Math.NumberTheory.TestUtils

specialCases :: [(Integer, [(Integer, Word)])]
specialCases =
  [ (35,[(5,1),(7,1)])
  , (75,[(3,1),(5,2)])
  , (65521^2,[(65521,2)])
  , (65537^2,[(65537,2)])
  , (2147483647, [(2147483647, 1)])
  , (4294967291, [(4294967291, 1)])
  , (19000000000000000001, [(19000000000000000001, 1)])
  , (3 * 5^2 * 7^21, [(3,1), (5,2), (7, 21)])
  , (9223372036854775783, [(9223372036854775783, 1)])
  , (18446744073709551557, [(18446744073709551557, 1)])
  , (4181339589500970917,[(15034813,1),(278110515209,1)])
  , (4181339589500970918,[(2,1),(3,2),(7,1),(2595773,1),(12784336241,1)])
  , (2227144715990344929,[(3,1),(317,1),(17381911,1),(134731889,1)])
  , (10489674846272137811130167281,[(1312601,1),(9555017,1),(836368815445393,1)])
  , (10489674846272137811130167282,[(2,1),(17,1),(577,1),(3863,1),(179347163,1),(771770327021,1)])
  , (10489674846272137811130167283,[(3,1),(7,1),(4634410717,1),(107782489838601619,1)])
  , (10489674846272137811130167287,[(4122913189601,1),(2544238591472087,1)])
  , (6293073306208101456461600748,[(2,2),(3,1),(1613,1),(69973339,1),(4646378436563447,1)])
  , (6293073306208101456461600749,[(7,1),(103,1),(4726591,1),(1846628365511484259,1)])
  , (6293073306208101456461600750,[(2,1),(5,3),(239,1),(34422804769,1),(3059698456333,1)])
  , (6293073306208101456461600751,[(3,1),(13523,1),(1032679,1),(150211485989006401,1)])
  , (6293073306208101456461600753,[(19391,1),(372473053129,1),(871300023127,1)])
  , (6293073306208101456461600754,[(2,1),(3,2),(11,1),(13,1),(71,1),(2311,1),(22859,1),(7798621,1),(83583569,1)])
  , (11999991291828813663324577057,[(14381453,1),(10088205181,1),(82711187849,1)])
  , (11999991291828813663324577062,[(2,1),(3,1),(7,1),(3769,1),(634819511,1),(119413997449529,1)])
  , (16757651897802863152387219654541878160,[(2,4),(5,1),(12323,1),(1424513,1),(6205871923,1),(1922815011093901,1)])
  , (16757651897802863152387219654541878162,[(2,1),(29,1),(78173,1),(401529283,1),(1995634649,1),(4612433663779,1)])
  , (16757651897802863152387219654541878163,[(11,1),(31,1),(112160981904206269,1),(438144115295608147,1)])
  -- , (16757651897802863152387219654541878166,[(2,1),(23,1),(277,1),(505353699591289,1),(2602436338718275457,1)])
  , ((10 ^ 80 - 1) `div` 9, [(11,1),(17,1),(41,1),(73,1),(101,1),(137,1),(271,1),(3541,1),(9091,1),(27961,1),
                             (1676321,1),(5070721,1),(5882353,1),(5964848081,1),(19721061166646717498359681,1)])
  , (623506907396924300595652906937, [(300137,1),(825131,2),(1746779,2)])
  , (626472835738582668418814215862, [(2,1),(150211,1),(11746151,2),(122939,2)])
  , (638396704483535474833679624037, [(3,1),(11,2),(100519,1),(104281,2),(1268419,2)])
  ]

lazyCases :: [(Integer, [(Integer, Word)])]
lazyCases =
  [ ( 14145130711
    * 10000000000000000000000000000000000000121
    * 100000000000000000000000000000000000000000000000447
    , [(14145130711, 1)]
    )
  ]

shortenNumber :: Integer -> String
shortenNumber n
  | l <= 10 = xs
  | otherwise = take 5 xs ++ "..." ++ drop (l - 5) xs
  where
    xs = show n
    l = length xs

factoriseProperty1 :: Assertion
factoriseProperty1 = assertEqual "0" [] (factorise (1 :: Int))

factoriseProperty2 :: Positive Integer -> Bool
factoriseProperty2 (Positive n) = factorise n == factorise (negate n)

factoriseProperty3 :: Positive Integer -> Bool
factoriseProperty3 (Positive n) = all (isJust . isPrime . unPrime . fst) (factorise n)

factoriseProperty4 :: Positive Integer -> Bool
factoriseProperty4 (Positive n) = sort bases == nub (sort bases)
  where
    bases = map fst $ factorise n

factoriseProperty5 :: Positive Integer -> Bool
factoriseProperty5 (Positive n) = product (map (\(p, k) -> unPrime p ^ k) (factorise n)) == n

factoriseProperty6 :: (Integer, [(Integer, Word)]) -> Assertion
factoriseProperty6 (n, fs) = assertEqual (show n) (sort fs) (sort $ map (first unPrime) $ factorise n)

factoriseProperty7 :: (Integer, [(Integer, Word)]) -> Assertion
factoriseProperty7 (n, fs) = zipWithM_ (assertEqual (show n)) fs (map (first unPrime) $ factorise n)

testSuite :: TestTree
testSuite = testGroup "Factorisation"
  [ testGroup "factorise" $
    [ testCase          "0"                              factoriseProperty1
    , testSmallAndQuick "negate"                         factoriseProperty2
    , testSmallAndQuick "bases are prime"                factoriseProperty3
    , testSmallAndQuick "bases are distinct"             factoriseProperty4
    , testSmallAndQuick "factorback"                     factoriseProperty5
    ] ++
    map (\x -> testCase ("special case " ++ shortenNumber (fst x)) (factoriseProperty6 x)) specialCases
    ++
    map (\x -> testCase ("laziness " ++ shortenNumber (fst x)) (factoriseProperty7 x)) lazyCases
  ]