{-# LANGUAGE CPP #-}
module Proarrow.Category.Instance.TensorNetwork.Blas (Gemm, gemmDouble, gemmFloat, gemmComplexDouble) where
import Data.Complex (Complex (..))
import Data.Kind (Type)
import Data.Vector.Storable qualified as SV
import Prelude (Bool, Double, Float, Int, Maybe (..))
#ifdef BLAS
import Data.Vector.Storable.Mutable qualified as MSV
import Foreign.C.Types (CInt (..))
import Foreign.Marshal.Utils (with)
import Foreign.Ptr (Ptr)
import Foreign.Storable (Storable)
import System.IO.Unsafe (unsafeDupablePerformIO)
import Prelude (IO, fromIntegral, ($), (*))
#endif
type Gemm :: Type -> Type
type Gemm e = Bool -> Bool -> Int -> Int -> Int -> SV.Vector e -> SV.Vector e -> SV.Vector e
gemmDouble :: Maybe (Gemm Double)
gemmFloat :: Maybe (Gemm Float)
gemmComplexDouble :: Maybe (Gemm (Complex Double))
#ifdef BLAS
type CblasGemm :: Type -> Type -> Type
type CblasGemm e s =
CInt -> CInt -> CInt -> CInt -> CInt -> CInt -> s -> Ptr e -> CInt -> Ptr e -> CInt -> s -> Ptr e -> CInt -> IO ()
foreign import ccall safe "cblas_dgemm" cblas_dgemm :: CblasGemm Double Double
foreign import ccall safe "cblas_sgemm" cblas_sgemm :: CblasGemm Float Float
foreign import ccall safe "cblas_zgemm" cblas_zgemm :: CblasGemm (Complex Double) (Ptr (Complex Double))
gemmWith :: (Storable e) => CblasGemm e s -> ((s -> s -> IO ()) -> IO ()) -> Gemm e
gemmWith routine scalars ta tb m n k a b = unsafeDupablePerformIO $ do
c <- MSV.unsafeNew (m * n)
scalars \one zero ->
SV.unsafeWith a \pa -> SV.unsafeWith b \pb -> MSV.unsafeWith c \pc ->
routine rowMajor (trans ta) (trans tb) (cint m) (cint n) (cint k) one pa (lead ta k m) pb (lead tb n k) zero pc (cint n)
SV.unsafeFreeze c
where
rowMajor = 101
trans t = if t then 112 else 111
cint = fromIntegral
lead t notTransposed transposed = cint (if t then transposed else notTransposed)
gemmDouble = Just (gemmWith cblas_dgemm \k -> k 1 0)
gemmFloat = Just (gemmWith cblas_sgemm \k -> k 1 0)
gemmComplexDouble = Just (gemmWith cblas_zgemm \k -> with (1 :+ 0) \one -> with (0 :+ 0) \zero -> k one zero)
#else
gemmDouble :: Maybe (Gemm Double)
gemmDouble = Maybe (Gemm Double)
forall a. Maybe a
Nothing
gemmFloat :: Maybe (Gemm Float)
gemmFloat = Maybe (Gemm Float)
forall a. Maybe a
Nothing
gemmComplexDouble :: Maybe (Gemm (Complex Double))
gemmComplexDouble = Maybe (Gemm (Complex Double))
forall a. Maybe a
Nothing
#endif