lol-0.0.1.0: src/Crypto/Lol/Cyclotomic/Tensor/RepaTensor/Gauss.hs
{-# LANGUAGE ConstraintKinds, FlexibleContexts, NoImplicitPrelude,
RebindableSyntax, ScopedTypeVariables #-}
-- | (Continuous) Gaussian sampling for Repa arrays
module Crypto.Lol.Cyclotomic.Tensor.RepaTensor.Gauss
( tGaussianDec' ) where
import Crypto.Lol.Cyclotomic.Tensor.RepaTensor.RTCommon
import Crypto.Lol.GaussRandom
import Crypto.Lol.LatticePrelude
import Control.Monad.Random
-- | A function tagged by the cyclotomic index which,
-- given a (scaled) variance, outputs a Gaussian-distributed
-- vector in the decoding basis
tGaussianDec' :: forall m v r rnd .
(Fact m, OrdFloat r, Random r, Unbox r, Elt r,
ToRational v, MonadRandom rnd)
=> v -> rnd (Arr m r)
tGaussianDec' =
let pm = Proxy::Proxy m
m = proxy valueFact pm
n = proxy totientFact pm
rad = proxy radicalFact pm
in \v -> do -- rnd monad
x <- realGaussians (v * fromIntegral (m `div` rad)) n
let arr = Arr $ fromUnboxed (Z:.n) x
return $ fD arr
-- | The fully tensored D transformation
fD :: (Fact m, Transcendental r, Unbox r, Elt r) => Arr m r -> Arr m r
fD = eval $ fTensor $ ppTensor pD
-- | The D transformation for a prime
pD :: forall p r . (NatC p, Transcendental r, Unbox r, Elt r)
=> Tagged p (Trans r)
pD = let pval = proxy valueNatC (Proxy::Proxy p)
in tag $
if pval==2
then Id 1
else trans (pval-1) $ mulMat $ force $
fromFunction (Z :. pval-1 :. pval-1)
(\(Z:.i:.j) ->
-- mtx is sqrt(2)*[ cos(2pi*i*(j+1)/p) | sin(same) ]
-- (signs of columns doesn't matter for our purposes.)
let theta = 2 * pi * fromIntegral (i*(j+1)) /
fromIntegral pval
in sqrt 2 * if j < pval `div` 2
then cos theta else sin theta)