module Crypto.Lol.Types.Numeric
( module Crypto.Lol.Types.Numeric
, module NumericPrelude
, Int64
) where
import Control.DeepSeq
import Control.Monad.Random
import Algebra.IntegralDomain (divUp)
import NumericPrelude hiding (abs, max, min, (^))
import qualified NumericPrelude.Numeric (abs)
import qualified Prelude (max, min)
import qualified Algebra.Absolute (C)
import qualified Algebra.Additive (C)
import qualified Algebra.Algebraic (C)
import qualified Algebra.Field (C)
import qualified Algebra.IntegralDomain (C)
import qualified Algebra.Module (C)
import qualified Algebra.PrincipalIdealDomain (C)
import qualified Algebra.RealField (C)
import qualified Algebra.RealIntegral (C)
import qualified Algebra.RealRing (C)
import qualified Algebra.RealTranscendental (C)
import qualified Algebra.Ring (C)
import qualified Algebra.ToInteger (C)
import qualified Algebra.ToRational (C, realToField)
import qualified Algebra.Transcendental (C)
import qualified Algebra.ZeroTestable (C)
import MathObj.Polynomial
import Data.Int (Int64)
max :: Ord a => a -> a -> a
max = Prelude.max
min :: Ord a => a -> a -> a
min = Prelude.min
abs :: Absolute a => a -> a
abs = NumericPrelude.Numeric.abs
realToField :: (Field b, ToRational a) => a -> b
realToField = Algebra.ToRational.realToField
type ZeroTestable a = (Algebra.ZeroTestable.C a)
type Additive a = (Algebra.Additive.C a)
type Ring a = (Algebra.Ring.C a)
type Module a v = (Algebra.Module.C a v)
type IntegralDomain a = (Algebra.IntegralDomain.C a)
type ToRational a = (Algebra.ToRational.C a)
type Field a = (Algebra.Field.C a)
type RealRing a = (Algebra.RealRing.C a)
type RealField a = (Algebra.RealField.C a)
type Algebraic a = (Algebra.Algebraic.C a)
type Transcendental a = (Algebra.Transcendental.C a)
type RealTranscendental a = (Algebra.RealTranscendental.C a)
type OrdFloat a = (Ord a, Transcendental a)
type ToInteger a = (Algebra.ToInteger.C a)
type Absolute a = (Algebra.Absolute.C a)
type RealIntegral a = (Algebra.RealIntegral.C a)
type PID a = (Algebra.PrincipalIdealDomain.C a)
type Polynomial a = MathObj.Polynomial.T a
instance Algebra.IntegralDomain.C Double where
_ `div` 0 = error "cannot divide Double by 0\n"
a `div` b = a / b
_ `mod` _ = 0
instance (NFData r) => NFData (Polynomial r) where
rnf = rnf . coeffs
(^) :: forall a i . (Ring a, ToInteger i) => a -> i -> a
x0 ^ y0 | y0 < 0 = error "Negative exponent"
| y0 == 0 = 1
| otherwise = f x0 y0
where
f :: a -> i -> a
f x y | even y = f (x * x) (y `quot` 2)
| y == 1 = x
| otherwise = g (x * x) ((y 1) `quot` 2) x
g :: a -> i -> a -> a
g x y z | even y = g (x * x) (y `quot` 2) z
| y == 1 = x * z
| otherwise = g (x * x) ((y 1) `quot` 2) (x * z)
modinv :: (PID i, Eq i) => i -> i -> Maybe i
modinv a q = let (d, (_, inv)) = extendedGCD q a
in if d == one
then Just $ inv `mod` q
else Nothing
decomp :: (IntegralDomain z, Ord z) => [z] -> z -> [z]
decomp [] v = [v]
decomp (b:bs) v = let (q,r) = v `divModCent` b
in r : decomp bs q
logCeil :: (ToInteger i) => i -> i -> Int
logCeil _ 1 = 0
logCeil b x = 1 + logCeil b (x `divUp` b)
roundMult :: (RealField r, ToInteger i) => i -> r -> i
roundMult 1 r = round r
roundMult i r = let r' = r / fromIntegral i in i * round r'
roundScalarCentered :: (RealField r, Random r, ToInteger i,
MonadRandom mon)
=> i -> r -> mon i
roundScalarCentered p x =
let x' = x / fromIntegral p
mod1 = x' floor x'
in do prob <- getRandomR (zero, one)
return $ p * if prob < mod1
then ceiling x'
else floor x'
divModCent :: (IntegralDomain i, Ord i) => i -> i -> (i,i)
divModCent a b = let (q,r) = a `divMod` b
in if 2*r < b
then (q,r)
else (q+1,rb)