module Numeric.LAPACK.Orthogonal.Plain (
leastSquares,
minimumNorm,
leastSquaresMinimumNormRCond,
pseudoInverseRCond,
leastSquaresConstraint,
gaussMarkovLinearModel,
determinantAbsolute,
complement,
extractComplement,
) where
import qualified Numeric.LAPACK.Orthogonal.Private as HH
import qualified Numeric.LAPACK.Matrix.Square.Basic as Square
import qualified Numeric.LAPACK.Matrix.Shape.Private as MatrixShape
import qualified Numeric.LAPACK.Matrix.Extent.Private as Extent
import qualified Numeric.LAPACK.Matrix.Basic as Basic
import qualified Numeric.LAPACK.Vector as Vector
import Numeric.LAPACK.Matrix.Shape.Private (Order(RowMajor,ColumnMajor))
import Numeric.LAPACK.Matrix.Private
(Full, General, Tall, Wide, ShapeInt, shapeInt)
import Numeric.LAPACK.Vector (Vector)
import Numeric.LAPACK.Scalar (RealOf, zero, absolute)
import Numeric.LAPACK.Private
(lacgv, peekCInt,
copySubMatrix, copyToTemp,
copyToColumnMajorTemp, copyToSubColumnMajor,
withAutoWorkspaceInfo, rankMsg, errorCodeMsg, createHigherArray)
import qualified Numeric.LAPACK.FFI.Generic as LapackGen
import qualified Numeric.LAPACK.FFI.Complex as LapackComplex
import qualified Numeric.LAPACK.FFI.Real as LapackReal
import qualified Numeric.Netlib.Utility as Call
import qualified Numeric.Netlib.Class as Class
import qualified Data.Array.Comfort.Storable.Unchecked.Monadic as ArrayIO
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 System.IO.Unsafe (unsafePerformIO)
import Foreign.Marshal.Array (pokeArray)
import Foreign.C.Types (CInt, CChar)
import Foreign.ForeignPtr (ForeignPtr, withForeignPtr)
import Foreign.Ptr (Ptr)
import Control.Monad.Trans.Cont (ContT(ContT), evalContT)
import Control.Monad.IO.Class (liftIO)
import Data.Complex (Complex)
import Data.Tuple.HT (mapSnd)
leastSquares ::
(Extent.C vert, Extent.C horiz,
Shape.C height, Eq height, Shape.C width, Shape.C nrhs, Class.Floating a) =>
Full horiz Extent.Small height width a ->
Full vert horiz height nrhs a ->
Full vert horiz width nrhs a
leastSquares
(Array shapeA@(MatrixShape.Full orderA extentA) a)
(Array (MatrixShape.Full orderB extentB) b) =
case Extent.fuse (Extent.generalizeWide $ Extent.transpose extentA) extentB of
Nothing -> error "leastSquares: height shapes mismatch"
Just extent ->
Array.unsafeCreate (MatrixShape.Full ColumnMajor extent) $ \xPtr -> do
let widthA = Extent.width extentA
let (height,widthB) = Extent.dimensions extentB
let (m,n) = MatrixShape.dimensions shapeA
let lda = m
let nrhs = Shape.size widthB
let ldb = Shape.size height
let ldx = Shape.size widthA
evalContT $ do
mPtr <- Call.cint m
nPtr <- Call.cint n
nrhsPtr <- Call.cint nrhs
(transPtr,aPtr) <- adjointA orderA (m*n) a
ldaPtr <- Call.leadingDim lda
ldbPtr <- Call.leadingDim ldb
bPtr <- copyToColumnMajorTemp orderB ldb nrhs b
liftIO $ withAutoWorkspaceInfo rankMsg "gels" $
LapackGen.gels transPtr
mPtr nPtr nrhsPtr aPtr ldaPtr bPtr ldbPtr
liftIO $ copySubMatrix ldx nrhs ldb bPtr ldx xPtr
minimumNorm ::
(Extent.C vert, Extent.C horiz,
Shape.C height, Eq height, Shape.C width, Shape.C nrhs, Class.Floating a) =>
Full Extent.Small vert height width a ->
Full vert horiz height nrhs a ->
Full vert horiz width nrhs a
minimumNorm
(Array shapeA@(MatrixShape.Full orderA extentA) a)
(Array (MatrixShape.Full orderB extentB) b) =
case Extent.fuse (Extent.generalizeTall $ Extent.transpose extentA) extentB of
Nothing -> error "minimumNorm: height shapes mismatch"
Just extent ->
Array.unsafeCreate (MatrixShape.Full ColumnMajor extent) $ \xPtr -> do
let widthA = Extent.width extentA
let (height,widthB) = Extent.dimensions extentB
let (m,n) = MatrixShape.dimensions shapeA
let lda = m
let nrhs = Shape.size widthB
let ldb = Shape.size height
let ldx = Shape.size widthA
evalContT $ do
mPtr <- Call.cint m
nPtr <- Call.cint n
nrhsPtr <- Call.cint nrhs
(transPtr,aPtr) <- adjointA orderA (m*n) a
ldaPtr <- Call.leadingDim lda
bPtr <- ContT $ withForeignPtr b
ldxPtr <- Call.leadingDim ldx
liftIO $ copyToSubColumnMajor orderB ldb nrhs bPtr ldx xPtr
liftIO $ withAutoWorkspaceInfo rankMsg "gels" $
LapackGen.gels transPtr
mPtr nPtr nrhsPtr aPtr ldaPtr xPtr ldxPtr
adjointA ::
Class.Floating a =>
Order -> Int -> ForeignPtr a -> ContT r IO (Ptr CChar, Ptr a)
adjointA order size a = do
aPtr <- copyToTemp size a
trans <-
case order of
RowMajor -> do
sizePtr <- Call.cint size
incPtr <- Call.cint 1
liftIO $ lacgv sizePtr aPtr incPtr
return $ HH.invChar a
ColumnMajor -> return 'N'
transPtr <- Call.char trans
return (transPtr, aPtr)
leastSquaresMinimumNormRCond ::
(Extent.C vert, Extent.C horiz,
Shape.C height, Eq height, Shape.C width, Shape.C nrhs, Class.Floating a) =>
RealOf a ->
Full horiz vert height width a ->
Full vert horiz height nrhs a ->
(Int, Full vert horiz width nrhs a)
leastSquaresMinimumNormRCond rcond
(Array (MatrixShape.Full orderA extentA) a)
(Array (MatrixShape.Full orderB extentB) b) =
case Extent.fuse (Extent.transpose extentA) extentB of
Nothing -> error "leastSquaresMinimumNormRCond: height shapes mismatch"
Just extent ->
let widthA = Extent.width extentA
(height,widthB) = Extent.dimensions extentB
shapeX = MatrixShape.Full ColumnMajor extent
m = Shape.size height
n = Shape.size widthA
nrhs = Shape.size widthB
in if m == 0
then (0, Vector.zero shapeX)
else
if nrhs == 0
then
(fst $ unsafePerformIO $
case Vector.zero height of
Array _ b1 ->
leastSquaresMinimumNormIO rcond
(MatrixShape.general ColumnMajor widthA ())
orderA a orderB b1 m n 1,
Vector.zero shapeX)
else
unsafePerformIO $
leastSquaresMinimumNormIO rcond shapeX
orderA a orderB b m n nrhs
leastSquaresMinimumNormIO ::
(Shape.C sh, Class.Floating a) =>
RealOf a -> sh ->
Order -> ForeignPtr a ->
Order -> ForeignPtr a ->
Int -> Int -> Int -> IO (Int, Array sh a)
leastSquaresMinimumNormIO rcond shapeX orderA a orderB b m n nrhs =
createHigherArray shapeX m n nrhs $ \(tmpPtr,ldtmp) -> do
let lda = m
evalContT $ do
aPtr <- copyToColumnMajorTemp orderA m n a
ldaPtr <- Call.leadingDim lda
ldtmpPtr <- Call.leadingDim ldtmp
bPtr <- ContT $ withForeignPtr b
liftIO $ copyToSubColumnMajor orderB m nrhs bPtr ldtmp tmpPtr
jpvtPtr <- Call.allocaArray n
liftIO $ pokeArray jpvtPtr (replicate n 0)
rankPtr <- Call.alloca
gelsy m n nrhs aPtr ldaPtr tmpPtr ldtmpPtr jpvtPtr rcond rankPtr
liftIO $ peekCInt rankPtr
type GELSY_ r ar a =
Int -> Int -> Int -> Ptr a -> Ptr CInt -> Ptr a -> Ptr CInt ->
Ptr CInt -> ar -> Ptr CInt -> ContT r IO ()
newtype GELSY r a = GELSY {getGELSY :: GELSY_ r (RealOf a) a}
gelsy :: (Class.Floating a) => GELSY_ r (RealOf a) a
gelsy =
getGELSY $
Class.switchFloating
(GELSY gelsyReal)
(GELSY gelsyReal)
(GELSY gelsyComplex)
(GELSY gelsyComplex)
gelsyReal :: (Class.Real a) => GELSY_ r a a
gelsyReal m n nrhs aPtr ldaPtr bPtr ldbPtr jpvtPtr rcond rankPtr = do
mPtr <- Call.cint m
nPtr <- Call.cint n
nrhsPtr <- Call.cint nrhs
rcondPtr <- Call.real rcond
liftIO $ withAutoWorkspaceInfo errorCodeMsg "gelsy" $
LapackReal.gelsy mPtr nPtr nrhsPtr
aPtr ldaPtr bPtr ldbPtr jpvtPtr rcondPtr rankPtr
gelsyComplex :: (Class.Real a) => GELSY_ r a (Complex a)
gelsyComplex m n nrhs aPtr ldaPtr bPtr ldbPtr jpvtPtr rcond rankPtr = do
mPtr <- Call.cint m
nPtr <- Call.cint n
nrhsPtr <- Call.cint nrhs
rcondPtr <- Call.real rcond
rworkPtr <- Call.allocaArray (2*n)
liftIO $
withAutoWorkspaceInfo errorCodeMsg "gelsy" $ \workPtr lworkPtr infoPtr ->
LapackComplex.gelsy mPtr nPtr nrhsPtr
aPtr ldaPtr bPtr ldbPtr jpvtPtr rcondPtr rankPtr
workPtr lworkPtr rworkPtr infoPtr
pseudoInverseRCond ::
(Extent.C vert, Extent.C horiz,
Shape.C height, Eq height, Shape.C width, Eq width, Class.Floating a) =>
RealOf a ->
Full vert horiz height width a ->
(Int, Full horiz vert width height a)
pseudoInverseRCond rcond a =
case Basic.caseTallWide a of
Left _ ->
mapSnd Basic.transpose $
leastSquaresMinimumNormRCond rcond (Basic.transpose a) $
Square.toFull $ Square.identity $
MatrixShape.fullWidth $ Array.shape a
Right _ ->
leastSquaresMinimumNormRCond rcond a $
Square.toFull $ Square.identity $
MatrixShape.fullHeight $ Array.shape a
leastSquaresConstraint ::
(Shape.C height, Eq height,
Shape.C width, Eq width,
Shape.C constraints, Eq constraints, Class.Floating a) =>
General height width a -> Vector height a ->
Wide constraints width a -> Vector constraints a ->
Vector width a
leastSquaresConstraint
(Array (MatrixShape.Full orderA extentA) a) c
(Array (MatrixShape.Full orderB extentB) b) d =
let sameShape name shape0 shape1 =
if shape0 == shape1
then shape0
else error $ "leastSquaresConstraint: " ++ name ++ " shapes mismatch"
width = sameShape "width" (Extent.width extentA) (Extent.width extentB)
in
Array.unsafeCreate width $ \xPtr -> do
let height = sameShape "height" (Extent.height extentA) (Array.shape c)
let constraints =
sameShape "constraints" (Extent.height extentB) (Array.shape d)
let m = Shape.size height
let n = Shape.size width
let p = Shape.size constraints
evalContT $ do
mPtr <- Call.cint m
nPtr <- Call.cint n
pPtr <- Call.cint p
aPtr <- copyToColumnMajorTemp orderA m n a
ldaPtr <- Call.leadingDim m
bPtr <- copyToColumnMajorTemp orderB p n b
ldbPtr <- Call.leadingDim p
cPtr <- copyToTemp m (Array.buffer c)
dPtr <- copyToTemp p (Array.buffer d)
liftIO $ withAutoWorkspaceInfo rankMsg "gglse" $
LapackGen.gglse
mPtr nPtr pPtr aPtr ldaPtr bPtr ldbPtr cPtr dPtr xPtr
gaussMarkovLinearModel ::
(Shape.C height, Eq height,
Shape.C width, Eq width,
Shape.C opt, Eq opt, Class.Floating a) =>
Tall height width a -> General height opt a -> Vector height a ->
(Vector width a, Vector opt a)
gaussMarkovLinearModel
(Array (MatrixShape.Full orderA extentA) a)
(Array (MatrixShape.Full orderB extentB) b) d =
let width = Extent.width extentA in
let opt = Extent.width extentB in
Array.unsafeCreateWithSizeAndResult width $ \m xPtr -> do
ArrayIO.unsafeCreateWithSize opt $ \p yPtr -> do
let sameHeight shape0 shape1 =
if shape0 == shape1
then shape0
else error $ "gaussMarkovLinearModel: height shapes mismatch"
height =
sameHeight (Array.shape d) $
sameHeight (Extent.height extentA) (Extent.height extentB)
let n = Shape.size height
evalContT $ do
mPtr <- Call.cint m
nPtr <- Call.cint n
pPtr <- Call.cint p
aPtr <- copyToColumnMajorTemp orderA n m a
ldaPtr <- Call.leadingDim n
bPtr <- copyToColumnMajorTemp orderB n p b
ldbPtr <- Call.leadingDim n
dPtr <- copyToTemp n (Array.buffer d)
liftIO $ withAutoWorkspaceInfo rankMsg "ggglm" $
LapackGen.ggglm
nPtr mPtr pPtr aPtr ldaPtr bPtr ldbPtr dPtr xPtr yPtr
determinantAbsolute ::
(Extent.C vert, Extent.C horiz, Shape.C height, Shape.C width,
Class.Floating a) =>
Full vert horiz height width a -> RealOf a
determinantAbsolute =
absolute .
either (HH.determinantR . HH.fromMatrix) (const zero) .
Basic.caseTallWide
complement ::
(Shape.C height, Shape.C width, Class.Floating a) =>
Tall height width a -> Tall height ShapeInt a
complement = extractComplement . HH.fromMatrix
extractComplement ::
(Shape.C height, Shape.C width, Class.Floating a) =>
HH.Tall height width a -> Tall height ShapeInt a
extractComplement qr =
Basic.dropColumns
(Shape.size $ MatrixShape.splitWidth $ Array.shape $ HH.split_ qr) $
Basic.mapWidth (shapeInt . Shape.size) $ Square.toFull $
HH.extractQ qr