packages feed

linear-massiv-0.1.0.0: bench/Bench/Solve.hs

{-# LANGUAGE AllowAmbiguousTypes #-}

module Bench.Solve (solveBenchmarks) where

import Criterion.Main
import qualified Data.Massiv.Array as M
import GHC.TypeNats (KnownNat)

import Numeric.LinearAlgebra.Massiv.Types
import Numeric.LinearAlgebra.Massiv.Internal
import Numeric.LinearAlgebra.Massiv.Solve.LU (lu, luSolve)
import Numeric.LinearAlgebra.Massiv.Solve.Cholesky (cholesky, choleskySolve)

-- Diagonally dominant matrix for LU
mkMatP :: forall n. KnownNat n => Matrix n n M.P Double
mkMatP = makeMatrix @n @n @M.P $ \i j ->
  fromIntegral (i * 7 + j * 3 + 1) / 100.0 + if i == j then fromIntegral (dimVal @n) else 0

-- SPD matrix: A = B^T B + nI
mkSPDP :: forall n. KnownNat n => Matrix n n M.P Double
mkSPDP =
  let nn = dimVal @n
      b = makeMatrix @n @n @M.P $ \i j -> fromIntegral (i * nn + j + 1) / fromIntegral (nn * nn)
  in makeMatrix @n @n @M.P $ \i j ->
    foldl' (\acc k -> acc + (b ! (i, k)) * (b ! (j, k))) (if i == j then 1 else 0) [0..nn-1]

mkVecP :: forall n. KnownNat n => Vector n M.P Double
mkVecP = makeVector @n @M.P $ \i -> fromIntegral (i + 1)

solveBenchmarks :: [Benchmark]
solveBenchmarks =
  [ bgroup "lu"
    [ bench "10x10/P"  $ nf lu (mkMatP @10)
    , bench "50x50/P"  $ nf lu (mkMatP @50)
    , bench "100x100/P" $ nf lu (mkMatP @100)
    ]
  , bgroup "luSolve"
    [ bench "10x10/P"  $ nf (uncurry luSolve) (mkMatP @10, mkVecP @10)
    , bench "50x50/P"  $ nf (uncurry luSolve) (mkMatP @50, mkVecP @50)
    , bench "100x100/P" $ nf (uncurry luSolve) (mkMatP @100, mkVecP @100)
    ]
  , bgroup "cholesky"
    [ bench "10x10/P"  $ nf cholesky (mkSPDP @10)
    , bench "50x50/P"  $ nf cholesky (mkSPDP @50)
    , bench "100x100/P" $ nf cholesky (mkSPDP @100)
    ]
  , bgroup "choleskySolve"
    [ bench "10x10/P"  $ nf (uncurry choleskySolve) (mkSPDP @10, mkVecP @10)
    , bench "50x50/P"  $ nf (uncurry choleskySolve) (mkSPDP @50, mkVecP @50)
    , bench "100x100/P" $ nf (uncurry choleskySolve) (mkSPDP @100, mkVecP @100)
    ]
  ]