module Math.NumberTheory.Pell.Test.Solve ( Problem (..) , prop_solves , naive ) where import Control.Monad (liftM2) import Math.NumberTheory.Pell (solve) import Math.NumberTheory.Powers.Squares (isSquare, integerSquareRoot) import Test.QuickCheck data Problem = Problem Integer Integer deriving (Show, Eq) isProperD :: Integral a => a -> Bool isProperD n = (n > 0) && not (isSquare n) genD :: Gen Integer genD = scale (* 2) $ suchThat arbitrary isProperD shrinkD :: Integer -> [Integer] shrinkD d = filter isProperD $ shrink d genN :: Gen Integer genN = scale (* 2) $ sized genN' where genN' 0 = elements [-1, 1] genN' 1 = elements [-4, 4] genN' _ = do x <- suchThat arbitrary (> 0) let y = integerSquareRoot x elements [-y, y] shrinkN :: Integer -> [Integer] shrinkN n = filter (/= 0) $ shrink n instance Arbitrary Problem where arbitrary = liftM2 Problem genD genN shrink (Problem d n) = [Problem d' n | d' <- shrinkD d] ++ [Problem d n' | n' <- shrinkN n] naive :: Integer -> Integer -> Integer -> [(Integer, Integer)] naive maxY d n = [(integerSquareRoot $ n + d * y * y, y) | y <- [0..maxY], isSquare $ n + d * y * y] prop_solves :: Integer -> Problem -> Property prop_solves limit (Problem d n) = classify (n == 1) "n == 1" $ classify (n == (-1)) "n == -1" $ classify (n == 4) "n == 4" $ classify (n == (-4)) "n == -4" $ classify (abs n `notElem` [1, 4]) "|n| /= 1, 4" $ classify (n * n < d) "n^2 < d" $ classify (n * n > d) "n^2 > d" $ classify (d <= 100) "d <= 100" $ classify (d > 100) "d > 100" $ takeWhile ((<= limit) . snd) (solve d n) === naive limit d n