packages feed

lapack-0.1: src/Numeric/LAPACK/Matrix/Triangular.hs

{-# LANGUAGE TypeFamilies #-}
module Numeric.LAPACK.Matrix.Triangular (
   Triangular, MatrixShape.Uplo(..),
   Upper, Lower,
   fromList, autoFromList,
   lowerFromList, autoLowerFromList,
   upperFromList, autoUpperFromList,
   identity,
   diagonal,
   getDiagonal,
   transposeUp, transposeDown,
   adjointUp, adjointDown,

   toSquare,

   multiplyVectorLeft,
   multiplyVectorRight,
   square,
   multiply,
   multiplySquareLeft,
   multiplyGeneralLeft,
   multiplySquareRight,
   multiplyGeneralRight,
   ) where

import qualified Numeric.LAPACK.Matrix.Shape.Private as MatrixShape
import qualified Numeric.LAPACK.Vector as Vector
import Numeric.LAPACK.Matrix.Triangular.Private
         (diagonalPointers, pack, unpack, unpackZero, unpackToTemp)
import Numeric.LAPACK.Matrix.Shape.Private
         (Order(RowMajor,ColumnMajor),
          flipOrder, transposeFromOrder, uploFromOrder, uploOrder)
import Numeric.LAPACK.Matrix.Square (Square)
import Numeric.LAPACK.Matrix.Private (General, ZeroInt, zeroInt)
import Numeric.LAPACK.Vector (Vector)
import Numeric.LAPACK.Private (fill, zero, one, copyBlock)

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.Internal as Array
import qualified Data.Array.Comfort.Shape as Shape
import Data.Array.Comfort.Storable.Internal (Array(Array))

import Foreign.ForeignPtr (ForeignPtr, withForeignPtr)
import Foreign.Ptr (Ptr)
import Foreign.Storable (Storable, poke, peek)

import Control.Monad.Trans.Cont (ContT(ContT), evalContT)
import Control.Monad.IO.Class (liftIO)

import Data.Foldable (forM_)


type Triangular uplo sh = Array (MatrixShape.Triangular uplo sh)

type Lower sh = Array (MatrixShape.LowerTriangular sh)
type Upper sh = Array (MatrixShape.UpperTriangular sh)

transposeUp :: Lower sh a -> Upper sh a
transposeUp (Array sh a) =
   Array (MatrixShape.triangularTransposeUp sh) a

transposeDown :: Upper sh a -> Lower sh a
transposeDown (Array sh a) =
   Array (MatrixShape.triangularTransposeDown sh) a

adjointUp :: (Shape.C sh, Class.Floating a) => Lower sh a -> Upper sh a
adjointUp = Vector.conjugate . transposeUp

adjointDown :: (Shape.C sh, Class.Floating a) => Upper sh a -> Lower sh a
adjointDown = Vector.conjugate . transposeDown


fromList ::
   (MatrixShape.Uplo uplo, Shape.C sh, Storable a) =>
   Order -> sh -> [a] -> Triangular uplo sh a
fromList order sh =
   Array.fromList (MatrixShape.Triangular MatrixShape.autoUplo order sh)

lowerFromList :: (Shape.C sh, Storable a) => Order -> sh -> [a] -> Lower sh a
lowerFromList = fromList

upperFromList :: (Shape.C sh, Storable a) => Order -> sh -> [a] -> Upper sh a
upperFromList = fromList


autoFromList ::
   (MatrixShape.Uplo uplo, Storable a) =>
   Order -> [a] -> Triangular uplo ZeroInt a
autoFromList order xs =
   fromList order
      (zeroInt $ MatrixShape.triangleExtent "Triangular.autoFromList" $
       length xs)
      xs

autoLowerFromList :: (Storable a) => Order -> [a] -> Lower ZeroInt a
autoLowerFromList = autoFromList

autoUpperFromList :: (Storable a) => Order -> [a] -> Upper ZeroInt a
autoUpperFromList = autoFromList


toSquare ::
   (MatrixShape.Uplo uplo, Shape.C sh, Class.Floating a) =>
   Triangular uplo sh a -> Square sh a
toSquare (Array (MatrixShape.Triangular uplo order sh) a) =
   Array.unsafeCreate (MatrixShape.Square order sh) $ \bPtr ->
      withForeignPtr a $ \aPtr ->
         unpackZero (uploOrder uplo order) (Shape.size sh) aPtr bPtr


identity ::
   (MatrixShape.Uplo uplo, Shape.C sh, Class.Floating a) =>
   Order -> sh -> Triangular uplo sh a
identity order sh =
   let (realOrder, uplo) = autoUploOrder order
   in Array.unsafeCreate (MatrixShape.Triangular uplo order sh) $ \aPtr -> do
      let n = Shape.size sh
      fill zero (MatrixShape.triangleSize n) aPtr
      forM_ (diagonalPointers realOrder n aPtr aPtr) $ flip poke one . snd

diagonal ::
   (MatrixShape.Uplo uplo, Shape.C sh, Class.Floating a) =>
   Order -> Vector sh a -> Triangular uplo sh a
diagonal order (Array sh x) =
   let (realOrder, uplo) = autoUploOrder order
   in Array.unsafeCreate (MatrixShape.Triangular uplo order sh) $ \aPtr -> do
      let n = Shape.size sh
      fill zero (MatrixShape.triangleSize n) aPtr
      withForeignPtr x $ \xPtr ->
         forM_ (diagonalPointers realOrder n xPtr aPtr) $
            \(srcPtr,dstPtr) -> poke dstPtr =<< peek srcPtr

getDiagonal ::
   (MatrixShape.Uplo uplo, Shape.C sh, Class.Floating a) =>
   Triangular uplo sh a -> Vector sh a
getDiagonal (Array (MatrixShape.Triangular uplo order sh) a) =
      Array.unsafeCreate sh $ \xPtr -> do
   withForeignPtr a $ \aPtr ->
      mapM_
         (\(dstPtr,srcPtr) -> poke dstPtr =<< peek srcPtr)
         (diagonalPointers (uploOrder uplo order) (Shape.size sh) xPtr aPtr)


multiplyVectorLeft, multiplyVectorRight ::
   (MatrixShape.Uplo uplo, Shape.C sh, Eq sh, Class.Floating a) =>
   Triangular uplo sh a -> Vector sh a -> Vector sh a
multiplyVectorLeft = multiplyVector True
multiplyVectorRight = multiplyVector False

multiplyVector ::
   (MatrixShape.Uplo uplo, Shape.C sh, Eq sh, Class.Floating a) =>
   Bool -> Triangular uplo sh a -> Vector sh a -> Vector sh a
multiplyVector transp
   (Array (MatrixShape.Triangular uplo order shA) a) (Array shX x) =
      Array.unsafeCreate shX $ \yPtr -> do
   Call.assert "Triangular.multiplyVector: width shapes mismatch" (shA == shX)
   let n = Shape.size shA
   evalContT $ do
      uploPtr <- Call.char $ uploFromOrder $ uploOrder uplo order
      transPtr <-
         Call.char $ transposeFromOrder $
         (if transp then flipOrder else id) order
      diagPtr <- Call.char 'N'
      nPtr <- Call.cint n
      aPtr <- ContT $ withForeignPtr a
      xPtr <- ContT $ withForeignPtr x
      incyPtr <- Call.cint 1
      liftIO $ do
         copyBlock n xPtr yPtr
         BlasGen.tpmv uploPtr transPtr diagPtr nPtr aPtr yPtr incyPtr


square ::
   (MatrixShape.Uplo uplo, Shape.C sh, Eq sh, Class.Floating a) =>
   Triangular uplo sh a -> Triangular uplo sh a
square
   (Array shape@(MatrixShape.Triangular uplo order sh) a) =
      Array.unsafeCreate shape $ \bpPtr -> do
   let n = Shape.size sh
   evalContT $ do
      sidePtr <- Call.char 'L'
      let realOrder = uploOrder uplo order
      uploPtr <- Call.char $ uploFromOrder realOrder
      transPtr <- Call.char 'N'
      diagPtr <- Call.char 'N'
      nPtr <- Call.cint n
      let ldPtr = nPtr
      aPtr <- unpackToTemp (unpack realOrder) n a
      bPtr <- unpackToTemp (unpackZero realOrder) n a
      alphaPtr <- Call.number one
      liftIO $ do
         BlasGen.trmm sidePtr uploPtr transPtr diagPtr
            nPtr nPtr alphaPtr aPtr ldPtr bPtr ldPtr
         pack realOrder n bPtr bpPtr

multiply ::
   (MatrixShape.Uplo uplo, Shape.C sh, Eq sh, Class.Floating a) =>
   Triangular uplo sh a -> Triangular uplo sh a -> Triangular uplo sh a
multiply
   (Array        (MatrixShape.Triangular uploA orderA shA) a)
   (Array shapeB@(MatrixShape.Triangular uploB orderB shB) b) =
      Array.unsafeCreate shapeB $ \cpPtr -> do
   Call.assert "Triangular.multiply: width shapes mismatch" (shA == shB)
   let n = Shape.size shA
   evalContT $ do
      let (side,trans) =
            case orderB of
               ColumnMajor -> ('L', orderA)
               RowMajor -> ('R', flipOrder orderA)
      sidePtr <- Call.char side
      let realOrderA = uploOrder uploA orderA
      let realOrderB = uploOrder uploB orderB
      uploPtr <- Call.char $ uploFromOrder realOrderA
      transPtr <- Call.char $ transposeFromOrder trans
      diagPtr <- Call.char 'N'
      nPtr <- Call.cint n
      let ldPtr = nPtr
      aPtr <- unpackToTemp (unpack realOrderA) n a
      bPtr <- unpackToTemp (unpackZero realOrderB) n b
      alphaPtr <- Call.number one
      liftIO $ do
         BlasGen.trmm sidePtr uploPtr transPtr diagPtr
            nPtr nPtr alphaPtr aPtr ldPtr bPtr ldPtr
         pack realOrderB n bPtr cpPtr


multiplySquareLeft ::
   (MatrixShape.Uplo uplo, Shape.C sh, Eq sh, Class.Floating a) =>
   Square sh a -> Triangular uplo sh a -> Square sh a
multiplySquareLeft
   (Array shapeB@(MatrixShape.Square orderB shB) b)
   (Array        (MatrixShape.Triangular uploA orderA shA) a) =
      Array.unsafeCreate shapeB $ \cPtr -> do
   Call.assert "Triangular.multiplySquareLeft: shapes mismatch" (shA == shB)
   let n = Shape.size shB
   MatrixShape.caseUplo uploA
      (multiplyAux MatrixShape.Upper)
      (multiplyAux MatrixShape.Lower)
      (flipOrder orderA) n a (flipOrder orderB) n b cPtr

multiplyGeneralLeft ::
   (MatrixShape.Uplo uplo,
    Shape.C height, Shape.C width, Eq width, Class.Floating a) =>
   General height width a -> Triangular uplo width a -> General height width a
multiplyGeneralLeft
   (Array shapeB@(MatrixShape.General orderB height width) b)
   (Array        (MatrixShape.Triangular uploA orderA shA) a) =
      Array.unsafeCreate shapeB $ \cPtr -> do
   Call.assert "Triangular.multiplyGeneralLeft: shapes mismatch" (shA == width)
   MatrixShape.caseUplo uploA
      (multiplyAux MatrixShape.Upper)
      (multiplyAux MatrixShape.Lower)
      (flipOrder orderA) (Shape.size width) a
      (flipOrder orderB) (Shape.size height) b cPtr

multiplySquareRight ::
   (MatrixShape.Uplo uplo, Shape.C sh, Eq sh, Class.Floating a) =>
   Triangular uplo sh a -> Square sh a -> Square sh a
multiplySquareRight
   (Array        (MatrixShape.Triangular uploA orderA shA) a)
   (Array shapeB@(MatrixShape.Square orderB shB) b) =
      Array.unsafeCreate shapeB $ \cPtr -> do
   Call.assert "Triangular.multiplySquareRight: shapes mismatch" (shA == shB)
   let n = Shape.size shB
   multiplyAux uploA orderA n a orderB n b cPtr

multiplyGeneralRight ::
   (MatrixShape.Uplo uplo,
    Shape.C height, Eq height, Shape.C width, Class.Floating a) =>
   Triangular uplo height a -> General height width a -> General height width a
multiplyGeneralRight
   (Array        (MatrixShape.Triangular uploA orderA shA) a)
   (Array shapeB@(MatrixShape.General orderB height width) b) =
      Array.unsafeCreate shapeB $ \cPtr -> do
   Call.assert "Triangular.multiplyGeneralRight: shapes mismatch"
      (shA == height)
   multiplyAux
      uploA orderA (Shape.size height) a orderB (Shape.size width) b cPtr

multiplyAux ::
   (MatrixShape.Uplo uplo, Class.Floating a) =>
   uplo ->
   Order -> Int -> ForeignPtr a ->
   Order -> Int -> ForeignPtr a -> Ptr a -> IO ()
multiplyAux uploA orderA m0 a orderB n0 b cPtr =
   evalContT $ do
      let (side,trans,(m,n)) =
            case orderB of
               ColumnMajor -> ('L', orderA, (m0,n0))
               RowMajor -> ('R', flipOrder orderA, (n0,m0))
      sidePtr <- Call.char side
      let realOrderA = uploOrder uploA orderA
      uploPtr <- Call.char $ uploFromOrder realOrderA
      transPtr <- Call.char $ transposeFromOrder trans
      diagPtr <- Call.char 'N'
      mPtr <- Call.cint m
      nPtr <- Call.cint n
      alphaPtr <- Call.number one
      aPtr <- unpackToTemp (unpack realOrderA) m0 a
      ldaPtr <- Call.cint m0
      bPtr <- ContT $ withForeignPtr b
      ldbPtr <- Call.cint m
      liftIO $ do
         copyBlock (m0*n0) bPtr cPtr
         BlasGen.trmm sidePtr uploPtr transPtr diagPtr
            mPtr nPtr alphaPtr aPtr ldaPtr cPtr ldbPtr


autoUploOrder :: MatrixShape.Uplo uplo => Order -> (Order, uplo)
autoUploOrder order =
   case MatrixShape.autoUplo of
      uplo -> (uploOrder uplo order, uplo)