{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RebindableSyntax #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Crypto.Lol.Types.Numeric
( module Crypto.Lol.Types.Numeric
, module NumericPrelude
, Int64
) where
import Control.DeepSeq
import Control.Monad.Random
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.Matrix hiding (one, zero)
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
type Matrix a = MathObj.Matrix.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
instance (NFData r) => NFData (Matrix r) where
rnf = rnf . rows
{-# SPECIALISE [1] (^) ::
Integer -> Integer -> Integer,
Integer -> Int -> Integer,
Int -> Int -> Int,
Int64 -> Int64 -> Int64
#-}
(^) :: 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
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)
=> i
-> i
-> (i,i)
divModCent = flip (\b ->
let shift = b `div` 2
in \a -> let (q,r) = (a+shift) `divMod` b
in (q,r-shift))