-- | -- Module: Math.NumberTheory.Moduli.Cbrt -- Copyright: (c) 2020 Federico Bongiorno -- Licence: MIT -- Maintainer: Federico Bongiorno -- -- Test for Math.NumberTheory.Moduli.Cbrt -- module Math.NumberTheory.Moduli.CbrtTests ( testSuite ) where import Math.NumberTheory.Moduli.Cbrt import Math.NumberTheory.Quadratic.EisensteinIntegers import Math.NumberTheory.Primes import qualified Data.Euclidean as A import Data.List (genericReplicate) import Test.Tasty import Math.NumberTheory.TestUtils -- Checks multiplicative property of numerators. In details, -- @cubicSymbol1 alpha1 alpha2 beta@ checks that -- @(cubicSymbol alpha1 beta) <> (cubicSymbol alpha2 beta) == (cubicSymbol alpha1*alpha2 beta)@ cubicSymbol1 :: EisensteinInteger -> EisensteinInteger -> EisensteinInteger -> Bool cubicSymbol1 alpha1 alpha2 beta = isBadDenominator beta || cubicSymbolNumerator alpha1 alpha2 beta cubicSymbolNumerator :: EisensteinInteger -> EisensteinInteger -> EisensteinInteger -> Bool cubicSymbolNumerator alpha1 alpha2 beta = (symbol1 <> symbol2) == symbolProduct where symbol1 = cubicSymbol alpha1 beta symbol2 = cubicSymbol alpha2 beta symbolProduct = cubicSymbol alphaProduct beta alphaProduct = alpha1 * alpha2 -- Checks multiplicative property of denominators. In details, -- @cubicSymbol2 alpha beta1 beta2@ checks that -- @(cubicSymbol alpha beta1) <> (cubicSymbol alpha beta2) == (cubicSymbol alpha beta1*beta2)@ cubicSymbol2 :: EisensteinInteger -> EisensteinInteger -> EisensteinInteger -> Bool cubicSymbol2 alpha beta1 beta2 = isBadDenominator beta1 || isBadDenominator beta2 || cubicSymbolDenominator alpha beta1 beta2 cubicSymbolDenominator :: EisensteinInteger -> EisensteinInteger -> EisensteinInteger -> Bool cubicSymbolDenominator alpha beta1 beta2 = (symbol1 <> symbol2) == symbolProduct where symbol1 = cubicSymbol alpha beta1 symbol2 = cubicSymbol alpha beta2 symbolProduct = cubicSymbol alpha betaProduct betaProduct = beta1 * beta2 -- Checks that `cubicSymbol` agrees with the computational definition -- -- when the denominator is prime. cubicSymbol3 :: EisensteinInteger -> Prime EisensteinInteger -> Bool cubicSymbol3 alpha prime = isBadDenominator beta || cubicSymbol alpha beta == cubicSymbolPrime alpha beta where beta = unPrime prime cubicSymbolPrime :: EisensteinInteger -> EisensteinInteger -> CubicSymbol cubicSymbolPrime alpha beta = findCubicSymbol residue beta where residue = foldr f 1 listOfAlphas f x y = (x * y) `A.rem` beta listOfAlphas = genericReplicate alphaExponent alpha -- Exponent is defined to be 1/3*(@betaNorm@ - 1). alphaExponent = betaNorm `div` 3 betaNorm = norm beta isBadDenominator :: EisensteinInteger -> Bool isBadDenominator x = modularNorm == 0 where modularNorm = norm x `mod` 3 -- This complication is necessary because it may happen that the residue field -- of @beta@ has characteristic two. In this case 1=-1 and the Euclidean algorithm -- can return both. Therefore it is not enough to pattern match for the values -- which give a well defined @cubicSymbol@. findCubicSymbol :: EisensteinInteger -> EisensteinInteger -> CubicSymbol findCubicSymbol residue beta | residue `A.rem` beta == 0 = Zero | (residue - ω) `A.rem` beta == 0 = Omega | (residue + 1 + ω) `A.rem` beta == 0 = OmegaSquare | (residue - 1) `A.rem` beta == 0 = One | otherwise = error "Math.NumberTheory.Moduli.Cbrt: invalid EisensteinInteger." testSuite :: TestTree testSuite = testGroup "CubicSymbol" [ testSmallAndQuick "multiplicative property of numerators" cubicSymbol1 , testSmallAndQuick "multiplicative property of denominators" cubicSymbol2 , testSmallAndQuick "cubic residue with prime denominator" cubicSymbol3 ]