packages feed

linear-tests-0.1.1.0: test/Linear/MatrixSpec.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ExplicitForAll      #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications    #-}


module Linear.MatrixSpec (
  spec
) where

import           Test.Hspec
import           Test.QuickCheck

import           Control.Lens

import           Linear.Epsilon
import qualified Linear.Matrix           as M
import qualified Linear.V3               as V3
import qualified Linear.V4               as V4

import           Linear.Matrix.Arbitrary


-- | test the property `m * m^-1 == identity`
prop_Matrix_InvertibleM33_isInvertible :: (Epsilon a, Floating a) => InvertibleM33 a -> Bool
prop_Matrix_InvertibleM33_isInvertible (InvertibleM33 m) = nearZero ((m M.!*! M.inv33 m ) - M.identity)

isDiagonal :: (Epsilon a) => M.M33 a -> Bool
isDiagonal m33 = all nearZero $ map (`view` m33) [
  V3._x . V3._y
  , V3._x . V3._z
  , V3._y . V3._x
  , V3._y . V3._z
  , V3._z . V3._x
  , V3._z . V3._y]

-- | test the property that all off diagonal entries are zero
prop_Matrix_DiagM33_isDiagonal :: (Epsilon a, Floating a) => DiagM33 a -> Bool
prop_Matrix_DiagM33_isDiagonal = isDiagonal . unDiagM33

isAffine :: (Epsilon a, Floating a) => M.M44 a -> Bool
isAffine m44 = nearZero $ view V4._w m44 - V4.V4 0 0 0 1

-- | test the property `m * m^-1 == identity`
prop_Matrix_InvertibleM44_isInvertible :: (Epsilon a, Floating a) => InvertibleM44 a -> Bool
prop_Matrix_InvertibleM44_isInvertible (InvertibleM44 m) = nearZero ((m M.!*! M.inv44 m ) - M.identity)

-- | test the property that last row is [0,0,0,1]
prop_Matrix_AffineM44_isAffine :: (Epsilon a, Floating a) => AffineM44 a -> Bool
prop_Matrix_AffineM44_isAffine (AffineM44 m44) = isAffine m44

-- | test that it is closed under multiplication
prop_Matrix_AffineM44_isClosedUnderMultiplication :: (Epsilon a, Floating a) => NonEmptyList (AffineM44 a) -> Bool
prop_Matrix_AffineM44_isClosedUnderMultiplication = isAffine . foldr1 (M.!*!) . map unAffineM44 . getNonEmpty

-- | test the property that last row is [0,0,0,1]
prop_Matrix_InvertibleAffineM44_isAffine :: (Epsilon a, Floating a) => InvertibleAffineM44 a -> Bool
prop_Matrix_InvertibleAffineM44_isAffine (InvertibleAffineM44 m44) = isAffine m44

-- | test the property `m * m^-1 == identity`
prop_Matrix_InvertibleAffineM44_isInvertible :: (Epsilon a, Floating a) => InvertibleAffineM44 a -> Bool
prop_Matrix_InvertibleAffineM44_isInvertible (InvertibleAffineM44 m44) = isAffine m44

spec :: Spec
spec = specTyped @Double

specTyped :: forall a. (Eq a, Show a, Arbitrary a, Epsilon a, Floating a) => Spec
specTyped = do
  describe "Matrix" $ do
    describe "M33" $ do
      describe "Arbitrary" $ do
        describe "InvertibleM33" $ do
          it "satifies property `m * m^-1 == identity`" $
            property $ prop_Matrix_InvertibleM33_isInvertible @a
        describe "DiagM33" $ do
          it "satisfies property that all off diagonal entries are zero" $
            property $ prop_Matrix_DiagM33_isDiagonal @a
    describe "M44" $ do
      describe "Arbitrary" $ do
        describe "InvertibleM44" $ do
          it "satifies property `m * m^-1 == identity`" $
            property $ prop_Matrix_InvertibleM44_isInvertible @a
        describe "AffineM44" $ do
          it "satisfies property [0,0,0,1] in last row" $
            property $ prop_Matrix_AffineM44_isAffine @a
          it "is closed under multiplication" $
            property $ prop_Matrix_AffineM44_isClosedUnderMultiplication @a
        describe "InvertibleAffineM44" $ do
          it "satisfies property [0,0,0,1] in last row" $
            property $ prop_Matrix_InvertibleAffineM44_isAffine @a
          it "satifies `m * m^-1 == identity`" $
            property $ prop_Matrix_InvertibleAffineM44_isInvertible @a