content: {-|
  Module      : Crypto.Lol.Types.Unsafe.RRq
  Description : An implementation of modular arithmetic over the reals.
  Copyright   : (c) Eric Crockett, 2011-2017
                    Chris Peikert, 2011-2017
  License     : GPL-3
  Maintainer  : ecrockett0@gmail.com
  Stability   : experimental
  Portability : POSIX
  
    \( \def\Z{\mathbb{Z}} \)
    \( \def\R{\mathbb{R}} \)
  
  An implementation of the additive quotient group \(\R/(q\Z)\).
  This module is "unsafe" because it exports the 'RRq' constructor.
  This module should only be used to make tensor-specific instances for 'RRq'.
  The safe way to use this type is to import "Crypto.Lol.Types".
  -}
  
  {-# LANGUAGE ConstraintKinds            #-}
  {-# LANGUAGE FlexibleContexts           #-}
  {-# LANGUAGE FlexibleInstances          #-}
  {-# LANGUAGE GeneralizedNewtypeDeriving #-}
  {-# LANGUAGE MultiParamTypeClasses      #-}
  {-# LANGUAGE PolyKinds                  #-}
  {-# LANGUAGE RebindableSyntax           #-}
  {-# LANGUAGE ScopedTypeVariables        #-}
  {-# LANGUAGE TypeApplications           #-}
  {-# LANGUAGE TypeFamilies               #-}
  {-# LANGUAGE UndecidableInstances       #-}
  
  module Crypto.Lol.Types.Unsafe.RRq
  ( RRq(..)
  ) where
  
  import Algebra.Additive     as Additive (C)
  import Algebra.ZeroTestable as ZeroTestable (C)
  
  import Control.DeepSeq
  import System.Random
  
  import Crypto.Lol.Prelude
  import Crypto.Lol.Reflects
  import Crypto.Lol.Types.Unsafe.ZqBasic hiding (ZqB)
  
  -- invariant: 0 <= x < 1, scaled
  -- | The additive group \( \R/(q\Z) \) of reals modulo 'q', using
  -- underlying floating-point type 'r'.
  newtype RRq q r = RRq r
      deriving (Eq, ZeroTestable.C, Show, NFData)
  
  instance RealField r => Additive.C (RRq q r) where
    {-# INLINABLE zero #-}
    zero = RRq zero
  
    {-# INLINABLE (+) #-}
    (RRq x) + (RRq y) = RRq $ fraction $ x + y
  
    {-# INLINABLE negate #-}
    negate (RRq x) = RRq $ fraction $ negate x
  
  reduce' :: forall q r . (Reflects q r, RealField r) => r -> RRq q r
  reduce' r = RRq $ fraction $ r / value @q -- scale down
  
  instance (Reflects q r, RealField r) => Reduce r (RRq q r) where
    reduce = reduce'
  
  type instance LiftOf (RRq q r) = r
  
  instance (Reflects q r, Field r, Reduce r (RRq q r))
    => Lift' (RRq q r) where
    lift (RRq r) = (r-0.5) * value @q
  
  instance (Additive (RRq q r), Additive (RRq p r))
    => Rescale (RRq q r) (RRq p r) where
    rescale (RRq r) = RRq r
  
  instance Random (RRq q Double) where
    random g = let (r,g') = random g in (RRq r, g')
    randomR = error "randomR is nonsensical for RRq"
  
  instance (ToInteger z, RealField r, Reflects q z, Reflects q r)
    => Subgroup (ZqBasic q z) (RRq q r) where
    fromSubgroup = reduce' . fromIntegral . lift
  