{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Numeric.LAPACK.Matrix.Symmetric.Basic (
Symmetric,
gramian, gramianTransposed,
congruenceDiagonal, congruenceDiagonalTransposed,
congruence, congruenceTransposed,
scaledAnticommutator, scaledAnticommutatorTransposed,
) where
import qualified Numeric.LAPACK.Matrix.Private as Matrix
import qualified Numeric.LAPACK.Matrix.Basic as Basic
import qualified Numeric.LAPACK.Matrix.Shape.Private as MatrixShape
import qualified Numeric.LAPACK.Matrix.Extent.Private as Extent
import qualified Numeric.LAPACK.Split as Split
import Numeric.LAPACK.Matrix.Triangular.Private (pack, recheck)
import Numeric.LAPACK.Matrix.Shape.Private
(Order(RowMajor,ColumnMajor), NonUnit(NonUnit))
import Numeric.LAPACK.Matrix.Modifier
(Transposition(NonTransposed, Transposed))
import Numeric.LAPACK.Matrix.Private (Full)
import Numeric.LAPACK.Vector (Vector)
import Numeric.LAPACK.Scalar (zero, one)
import Numeric.LAPACK.Shape.Private (Unchecked(Unchecked))
import qualified Numeric.BLAS.FFI.Generic as BlasGen
import qualified Numeric.Netlib.Utility as Call
import qualified Numeric.Netlib.Class as Class
import qualified Data.Array.Comfort.Storable.Unchecked as Array
import qualified Data.Array.Comfort.Shape as Shape
import Data.Array.Comfort.Storable.Unchecked (Array(Array))
import Foreign.ForeignPtr (ForeignPtr, withForeignPtr)
import Foreign.Ptr (Ptr)
import Control.Monad.Trans.Cont (ContT(ContT), evalContT)
import Control.Monad.IO.Class (liftIO)
type Symmetric sh = Array (MatrixShape.FlexSymmetric NonUnit sh)
gramian ::
(Shape.C height, Shape.C width, Class.Floating a) =>
Matrix.General height width a -> Symmetric width a
gramian (Array (MatrixShape.Full order extent) a) =
Array.unsafeCreate (symmetricShape order $ Extent.width extent) $
\bPtr -> gramianIO order a bPtr $ gramianParameters order extent
gramianParameters ::
(Extent.C horiz, Extent.C vert, Shape.C height, Shape.C width) =>
Order ->
Extent.Extent vert horiz height width ->
((Int, Int), (Char, Char, Int))
gramianParameters order extent =
let (height, width) = Extent.dimensions extent
n = Shape.size width
k = Shape.size height
in ((n,k),
case order of
ColumnMajor -> ('U', 'T', k)
RowMajor -> ('L', 'N', n))
gramianTransposed ::
(Shape.C height, Shape.C width, Class.Floating a) =>
Matrix.General height width a -> Symmetric height a
gramianTransposed (Array (MatrixShape.Full order extent) a) =
Array.unsafeCreate (symmetricShape order $ Extent.height extent) $
\bPtr -> gramianIO order a bPtr $ gramianTransposedParameters order extent
gramianTransposedParameters ::
(Extent.C horiz, Extent.C vert, Shape.C height, Shape.C width) =>
Order ->
Extent.Extent vert horiz height width ->
((Int, Int), (Char, Char, Int))
gramianTransposedParameters order extent =
let (height, width) = Extent.dimensions extent
n = Shape.size height
k = Shape.size width
in ((n,k),
case order of
ColumnMajor -> ('U', 'N', n)
RowMajor -> ('L', 'T', k))
gramianIO ::
(Class.Floating a) =>
Order ->
ForeignPtr a -> Ptr a ->
((Int, Int), (Char, Char, Int)) -> IO ()
gramianIO order a bPtr ((n,k), (uplo,trans,lda)) =
evalContT $ do
uploPtr <- Call.char uplo
transPtr <- Call.char trans
nPtr <- Call.cint n
kPtr <- Call.cint k
alphaPtr <- Call.number one
aPtr <- ContT $ withForeignPtr a
ldaPtr <- Call.leadingDim lda
betaPtr <- Call.number zero
cPtr <- Call.allocaArray (n*n)
ldcPtr <- Call.leadingDim n
liftIO $ do
BlasGen.syrk uploPtr transPtr
nPtr kPtr alphaPtr aPtr ldaPtr betaPtr cPtr ldcPtr
pack order n cPtr bPtr
skipCheckCongruence ::
((sh -> Unchecked sh) -> matrix0 -> matrix1) ->
(matrix1 -> Symmetric (Unchecked sh) a) -> matrix0 -> Symmetric sh a
skipCheckCongruence mapSize f a =
recheck $ f $ mapSize Unchecked a
congruenceDiagonal ::
(Shape.C height, Eq height, Shape.C width, Class.Floating a) =>
Vector height a -> Matrix.General height width a -> Symmetric width a
congruenceDiagonal d =
skipCheckCongruence Basic.mapWidth $ \a ->
scaledAnticommutator 0.5 a $ Basic.scaleRows d a
congruenceDiagonalTransposed ::
(Shape.C height, Shape.C width, Eq width, Class.Floating a) =>
Matrix.General height width a -> Vector width a -> Symmetric height a
congruenceDiagonalTransposed =
flip $ \d -> skipCheckCongruence Basic.mapHeight $ \a ->
scaledAnticommutatorTransposed 0.5 a $ Basic.scaleColumns d a
congruence ::
(Shape.C height, Eq height, Shape.C width, Class.Floating a) =>
Symmetric height a -> Matrix.General height width a -> Symmetric width a
congruence b =
skipCheckCongruence Basic.mapWidth $ \a ->
scaledAnticommutator one a $
Split.tallMultiplyR NonTransposed
(Split.takeHalf MatrixShape.triangularOrder b) a
congruenceTransposed ::
(Shape.C height, Shape.C width, Eq width, Class.Floating a) =>
Matrix.General height width a -> Symmetric width a -> Symmetric height a
congruenceTransposed =
flip $ \b -> skipCheckCongruence Basic.mapHeight $ \a ->
scaledAnticommutatorTransposed one a $
Basic.swapMultiply (Split.tallMultiplyR Transposed)
a (Split.takeHalf MatrixShape.triangularOrder b)
scaledAnticommutator ::
(Extent.C vert, Extent.C horiz,
Shape.C height, Eq height, Shape.C width, Eq width, Class.Floating a) =>
a ->
Full vert horiz height width a ->
Full vert horiz height width a -> Symmetric width a
scaledAnticommutator alpha arr (Array (MatrixShape.Full order extentB) b) = do
let (Array (MatrixShape.Full _ extentA) a) = Basic.forceOrder order arr
Array.unsafeCreate (symmetricShape order $ Extent.width extentB) $
\cpPtr -> do
Call.assert "Symmetric.anticommutator: extents mismatch"
(extentA==extentB)
scaledAnticommutatorIO alpha order a b cpPtr $
gramianParameters order extentB
scaledAnticommutatorTransposed ::
(Extent.C vert, Extent.C horiz,
Shape.C height, Eq height, Shape.C width, Eq width, Class.Floating a) =>
a ->
Full vert horiz height width a ->
Full vert horiz height width a -> Symmetric height a
scaledAnticommutatorTransposed
alpha arr (Array (MatrixShape.Full order extentB) b) = do
let (Array (MatrixShape.Full _ extentA) a) = Basic.forceOrder order arr
Array.unsafeCreate (symmetricShape order $ Extent.height extentB) $
\cpPtr -> do
Call.assert "Symmetric.anticommutatorTransposed: extents mismatch"
(extentA==extentB)
scaledAnticommutatorIO alpha order a b cpPtr $
gramianTransposedParameters order extentB
scaledAnticommutatorIO ::
(Class.Floating a) =>
a ->
Order -> ForeignPtr a -> ForeignPtr a -> Ptr a ->
((Int, Int), (Char, Char, Int)) -> IO ()
scaledAnticommutatorIO alpha order a b cpPtr ((n,k), (uplo,trans,lda)) =
evalContT $ do
uploPtr <- Call.char uplo
transPtr <- Call.char trans
nPtr <- Call.cint n
kPtr <- Call.cint k
alphaPtr <- Call.number alpha
aPtr <- ContT $ withForeignPtr a
ldaPtr <- Call.leadingDim lda
bPtr <- ContT $ withForeignPtr b
let ldbPtr = ldaPtr
betaPtr <- Call.number zero
cPtr <- Call.allocaArray (n*n)
ldcPtr <- Call.leadingDim n
liftIO $ do
BlasGen.syr2k uploPtr transPtr nPtr kPtr alphaPtr
aPtr ldaPtr bPtr ldbPtr betaPtr cPtr ldcPtr
pack order n cPtr cpPtr
symmetricShape :: Order -> size -> MatrixShape.Symmetric size
symmetricShape = MatrixShape.Triangular NonUnit MatrixShape.autoUplo