{-# LANGUAGE RankNTypes #-}
module QLinear.Operations
( length,
mulMatricesWith,
neg,
transpose,
zipMatricesWith,
det,
algebraicComplement,
algebraicComplement',
adjugate,
inverted,
(*~),
(~*~),
(~+),
(+~),
(~+~),
(~-~),
)
where
import qualified Data.List as List
import Data.List.Split (chunksOf)
import Data.Tuple
import Internal.Determinant (adjugate, algebraicComplement, algebraicComplement', det)
import Internal.Matrix
import Internal.Quasi.Matrix.Quasi
import Prelude hiding (length)
(~+~) :: Num a => Matrix m n a -> Matrix m n a -> Matrix m n a
(~+~) = zipMatricesWith (+)
(*~) ::
Num a =>
a ->
Matrix m n a ->
Matrix m n a
(*~) n = fmap (n *)
(~+) ::
Num a =>
Matrix m n a ->
a ->
Matrix m n a
(~+) m n = (+ n) <$> m
(+~) :: Num a => a -> Matrix m n a -> Matrix m n a
(+~) = flip (~+)
(~-~) :: Num a => Matrix m n a -> Matrix m n a -> Matrix m n a
(~-~) = zipMatricesWith (-)
(~*~) :: Num a => Matrix m n a -> Matrix n k a -> Matrix m k a
(~*~) = mulMatricesWith (*) sum
mulMatricesWith ::
(a -> b -> c) ->
([c] -> d) ->
Matrix m n a ->
Matrix n k b ->
Matrix m k d
mulMatricesWith mul add (Matrix (m, _) left) (Matrix (_, k) right) =
Matrix (m, k) $
chunksOf k [add $ zipWith mul line column | line <- left, column <- List.transpose right]
zipMatricesWith ::
(a -> b -> c) ->
Matrix m n a ->
Matrix m n b ->
Matrix m n c
zipMatricesWith op (Matrix size l) (Matrix _ r) =
Matrix size $ zipWith (zipWith op) l r
transpose :: Matrix m n a -> Matrix n m a
transpose (Matrix size matrix) = Matrix (swap size) (List.transpose matrix)
neg :: Num a => Matrix m n a -> Matrix m n a
neg = ((-1) *~)
length :: (Real a, Floating b) => Vector n a -> b
length (Matrix _ matrix) = sqrt $ sum $ squares
where
toFloating = realToFrac :: (Real a, Floating b) => a -> b
squares = map ((** 2) . toFloating) $ concat matrix
inverted :: forall a b n. (Fractional b, Eq a, Real a) => Matrix n n a -> Maybe (Matrix n n b)
inverted (Matrix size@(1, 1) [[a]]) = if a /= 0 then Just (Matrix size [[1.0 / toFloating a]]) else Nothing
where
toFloating = realToFrac :: (Real a, Fractional b) => a -> b
inverted matrix = if determinant /= 0 then Just $ ((invertedDet *) . toFloating) <$> adj else Nothing
where
toFloating = realToFrac :: (Real a, Fractional b) => a -> b
determinant = det matrix
invertedDet = 1.0 / toFloating determinant
adj = adjugate matrix