packages feed

fpnla-examples-0.1: src/FPNLA/Operations/BLAS/Strategies/GEMM/MonadPar/StrassenPar.hs

{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables   #-}

module FPNLA.Operations.BLAS.Strategies.GEMM.MonadPar.StrassenPar () where

import           Control.DeepSeq                            (NFData)
import           Control.Monad.Par                          as MP (parMap,
                                                                   runPar)
import           FPNLA.Matrix                               (cantCols_m,
                                                             cantRows_m,
                                                             fromBlocks_m,
                                                             fromBlocks_m,
                                                             generate_m,
                                                             toBlocks_m,
                                                             zipWith_m)
import           FPNLA.Operations.BLAS                      (GEMM (gemm))
import           FPNLA.Operations.BLAS.Strategies.DataTypes (StrassenPar_MP,
                                                             getStrassenLimit)
import           FPNLA.Operations.Parameters                (Elt, ResM, TransType (NoTrans),
                                                             blasResultM,
                                                             getResultDataM,
                                                             transTrans_m)

instance (NFData (m e), Elt e, GEMM s m v e) => GEMM (StrassenPar_MP s) m v e where
    gemm (ctx, sctx) pmA pmB alpha beta mC =
        blasResultM $ strassen mA mB alpha beta mC
        where

            callGemm mA mB alpha beta mC = getResultDataM (gemm sctx (NoTrans mA) (NoTrans mB) alpha beta mC :: ResM s v m e)

            mA = transTrans_m pmA
            mB = transTrans_m pmB

            strassenLimit = getStrassenLimit ctx

            strassen :: m e -> m e -> e -> e -> m e -> m e
            strassen mA mB alpha beta mC =
                if cantRows_m mA <= strassenLimit
                then callGemm mA mB alpha beta mC
                else quadJoin . toC . toM $ (quadPartition mA, quadPartition mB, quadPartition mC)

            quadPartition :: m e -> (m e, m e, m e, m e)
            quadPartition m =
                let
                blocks = toBlocks_m (div (cantRows_m m) 2) (div (cantCols_m m) 2) m in
                (head (head blocks), head blocks !! 1, head (blocks !! 1), blocks !! 1 !! 1)

            fillWithZeros :: m e -> m e
            fillWithZeros m = generate_m (cantRows_m m) (cantCols_m m) (\_ _ -> 0)

            toM :: ((m e, m e, m e, m e), (m e, m e, m e, m e), (m e, m e, m e, m e)) -> (m e, m e, m e, m e, m e, m e, m e)
            toM ((a11, a12, a21, a22), (b11, b12, b21, b22), (c11, c12, c21, c22)) =
                (\[a, b, c, d, e, f, g] -> (a, b, c, d, e, f, g)) . runPar . MP.parMap id $
                    [strassen (zipWith_m (+) a11 a22) (zipWith_m (+) b11 b22) alpha 0 (fillWithZeros c11),
                    strassen (zipWith_m (+) a21 a22) b11 alpha 0 (fillWithZeros c11),
                    strassen a11 (zipWith_m (-) b12 b22) alpha beta c12,
                    strassen a22 (zipWith_m (-) b21 b11) alpha beta c21,
                    strassen (zipWith_m (+) a11 a12) b22 alpha 0 (fillWithZeros c11),
                    strassen (zipWith_m (-) a21 a11) (zipWith_m (+) b11 b12) alpha beta (zipWith_m (-) c22 c12),
                    strassen (zipWith_m (-) a12 a22) (zipWith_m (+) b21 b22) alpha beta (zipWith_m (-) c11 c21)]

            toC :: (m e, m e, m e, m e, m e, m e, m e) -> (m e, m e, m e, m e)
            toC (m1, m2, m3, m4, m5, m6, m7) =
                (\[a, b, c, d] -> (a, b, c, d)) . runPar . MP.parMap id $
                    [zipWith_m (+) m1 . zipWith_m (+) m4 . zipWith_m (-) m7 $ m5,
                    zipWith_m (+) m3 m5,
                    zipWith_m (+) m2 m4,
                    zipWith_m (+) m1 . zipWith_m (+) m3 . zipWith_m (-) m6 $ m2]

            quadJoin :: (m e, m e, m e, m e) -> m e
            quadJoin (c11, c12, c21, c22) =
                fromBlocks_m [
                    [c11, c12],
                    [c21, c22]]