{-| Module : Crypto.Lol.Benchmarks.TensorBenches Description : Benchmarks for the 'Tensor' interface. Copyright : (c) Eric Crockett, 2011-2017 Chris Peikert, 2011-2017 License : GPL-3 Maintainer : ecrockett0@email.com Stability : experimental Portability : POSIX Benchmarks for the 'Tensor' interface. In a perfect world, these benchmarks would have the same performance as the 'Cyc' benchmarks. In practice, GHC gets in the way at higher levels of the library, resulting in worse performance for 'Cyc' in some cases. -} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE PartialTypeSignatures #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# OPTIONS_GHC -fno-warn-partial-type-signatures #-} module Crypto.Lol.Benchmarks.TensorBenches (tensorBenches1, tensorBenches2) where import Control.Applicative import Control.Monad.Random hiding (lift) import Crypto.Lol.Cyclotomic.Tensor import Crypto.Lol.Prelude import Crypto.Lol.Types import Crypto.Lol.Types.IFunctor import Crypto.Lol.Utils.Benchmarks (Benchmark, bgroup, mkBench, mkBenchIO) import Crypto.Random -- must come after imports {-# ANN module "HLint: ignore Use camelCase" #-} -- | Benchmarks for single-index 'Tensor' operations. -- There must be a CRT basis for \(O_m\) over @r@. -- These cover the same functions as @cycBenches1@, but may have different -- performance due to how GHC interacts with Lol. {-# INLINABLE tensorBenches1 #-} tensorBenches1 :: forall (t :: Factored -> * -> *) (m :: Factored) (r :: *) gen . (Fact m, _) => Proxy '(t,m,r) -> Proxy gen -> Benchmark tensorBenches1 ptmr pgen = let z = zero :: t m r errorBench = mkBenchIO "error" (bench_errRounded ptmr pgen 0.1) benches = ($ z) <$> [ mkBench "zipWith (*)" (bench_mul z), mkBench "crt" bench_crt, mkBench "crtInv" bench_crtInv, mkBench "decToPow" bench_decToPow, mkBench "powToDec" bench_powToDec, mkBench "*g Pow" bench_mulGPow, mkBench "*g Dec" bench_mulGDec, mkBench "*g CRT" bench_mulGCRT, mkBench "divG Pow" bench_divGPow, mkBench "divG Dec" bench_divGDec, mkBench "divG CRT" bench_divGCRT, mkBench "lift" bench_lift] in bgroup "Tensor" (benches ++ [errorBench]) -- | Benchmarks for inter-ring 'Tensor' operations. -- There must be a CRT basis for \(O_{m'}\) over @r@. -- These cover the same functions as @cycBenches1@, but may have different -- performance due to how GHC interacts with Lol. {-# INLINABLE tensorBenches2 #-} tensorBenches2 :: forall (t :: Factored -> * -> *) (m :: Factored) (m' :: Factored) (r :: *) . _ => Proxy '(t,m,m',r) -> Benchmark tensorBenches2 ptmmr = let z = zero :: t m r z' = zero :: t m' r benches = [ mkBench "twacePow" (bench_twacePow ptmmr) z', mkBench "twaceDec" (bench_twacePow ptmmr) z', -- yes, twacePow is correct here. It's the same function! mkBench "twaceCRT" (bench_twaceCRT ptmmr) z', mkBench "embedPow" (bench_embedPow ptmmr) z, mkBench "embedCRT" (bench_embedCRT ptmmr) z] in bgroup "Tensor" benches {-# INLINABLE bench_mul #-} -- no CRT conversion, just coefficient-wise multiplication bench_mul :: _ => t m r -> t m r -> t m r bench_mul = zipWithI (*) {-# INLINABLE bench_crt #-} -- convert input from Pow basis to CRT basis bench_crt :: _ => t m r -> t m r bench_crt = fromJust' "TensorBenches.bench_crt" crt {-# INLINABLE bench_crtInv #-} -- convert input from CRT basis to Pow basis bench_crtInv :: _ => t m r -> t m r bench_crtInv = fromJust' "TensorBenches.bench_crtInv" crtInv {-# INLINABLE bench_decToPow #-} -- convert input from Dec basis to Pow basis bench_decToPow :: _ => t m r -> t m r bench_decToPow = decToPow {-# INLINABLE bench_powToDec #-} -- convert input from Dec basis to Pow basis bench_powToDec :: _ => t m r -> t m r bench_powToDec = powToDec {-# INLINABLE bench_lift #-} bench_lift :: _ => t m r -> t m r' bench_lift = fmapI lift {-# INLINABLE bench_mulGPow #-} -- multiply by g when input is in Pow basis bench_mulGPow :: _ => t m r -> t m r bench_mulGPow = mulGPow {-# INLINABLE bench_mulGDec #-} -- multiply by g when input is in Dec basis bench_mulGDec :: _ => t m r -> t m r bench_mulGDec = mulGDec {-# INLINABLE bench_mulGCRT #-} -- multiply by g when input is in CRT basis bench_mulGCRT :: _ => t m r -> t m r bench_mulGCRT = fromJust' "TensorBenches.bench_mulGCRT" mulGCRT {-# INLINABLE bench_divGPow #-} -- divide by g when input is in Pow basis bench_divGPow :: _ => t m r -> Maybe (t m r) bench_divGPow = divGPow . mulGPow {-# INLINABLE bench_divGDec #-} -- divide by g when input is in Dec basis bench_divGDec :: _ => t m r -> Maybe (t m r) bench_divGDec = divGDec . mulGDec {-# INLINABLE bench_divGCRT #-} -- divide by g when input is in CRT basis bench_divGCRT :: _ => t m r -> t m r bench_divGCRT = fromJust' "TensorBenches.bench_divGCRT" divGCRT {-# INLINABLE bench_errRounded #-} -- generate a rounded error term bench_errRounded :: forall t m r gen . (Fact m, CryptoRandomGen gen, TensorPowDec t r, _) => Proxy '(t,m,r) -> Proxy gen -> Double -> IO (t m (LiftOf r)) bench_errRounded _ _ v = evalRand (fmapI (roundMult one) <$> (tweakedGaussianDec v :: Rand (CryptoRand gen) (t m Double)) :: Rand (CryptoRand gen) (t m (LiftOf r))) <$> newGenIO {-# INLINABLE bench_twacePow #-} bench_twacePow :: forall t m m' r . _ => Proxy '(t,m,m',r) -> t m' r -> t m r bench_twacePow _ = twacePowDec {-# INLINABLE bench_twaceCRT #-} bench_twaceCRT :: forall t m m' r . _ => Proxy '(t,m,m',r) -> t m' r -> t m r bench_twaceCRT _ = fromJust' "TensorBenches.bench_twaceCRT" twaceCRT {-# INLINABLE bench_embedPow #-} bench_embedPow :: forall t m m' r . _ => Proxy '(t,m,m',r) -> t m r -> t m' r bench_embedPow _ = embedPow {-# INLINABLE bench_embedCRT #-} bench_embedCRT :: forall t m m' r . _ => Proxy '(t,m,m',r) -> t m r -> t m' r bench_embedCRT _ = fromJust' "TensorBenches.bench_embedCRT" embedCRT