{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE ExistentialQuantification #-} module Test.Divide ( testsVar, testsVarAny, SquareMatrix(SquareMatrix), determinant, solve, solveIdentity, inverse, approxRelMatrix, approxRelArray, ) where import qualified Test.Generator as Gen import qualified Test.Logic as Logic import qualified Test.Utility as Util import Test.Generator ((<#\#>), (<#/#>)) import Test.Utility (Tagged, approxMatrix) import qualified Numeric.LAPACK.Linear.LowerUpper as LU import qualified Numeric.LAPACK.Matrix.Square as Square import qualified Numeric.LAPACK.Matrix.Extent as Extent import qualified Numeric.LAPACK.Matrix.Array as ArrMatrix import qualified Numeric.LAPACK.Matrix.Special as Special import qualified Numeric.LAPACK.Matrix.Shape as MatrixShape import qualified Numeric.LAPACK.Matrix as Matrix import qualified Numeric.LAPACK.Vector as Vector import qualified Numeric.LAPACK.Scalar as Scalar import Numeric.LAPACK.Matrix.Array (Quadratic, ArrayMatrix) import Numeric.LAPACK.Matrix (ShapeInt, (##/#), (##*#), (#*##), (#\##)) import Numeric.LAPACK.Scalar (RealOf) import qualified Numeric.Netlib.Class as Class import qualified Data.Array.Comfort.Shape as Shape import Control.Applicative ((<$>)) import Data.Tuple.HT (mapSnd) import qualified Test.QuickCheck as QC determinant :: (MatrixShape.Packing pack, MatrixShape.Property property, MatrixShape.Strip lower, MatrixShape.Strip upper, Class.Floating a, RealOf a ~ ar, Class.Real ar) => Quadratic pack property lower upper ShapeInt a -> Bool determinant a = let d = Square.determinant $ Matrix.toSquare a in Util.approx (max (Scalar.selectReal 1 1e-2) (Scalar.selectReal 1e-3 1e-5 * Scalar.absolute d)) d (Matrix.determinant a) approxRelMatrix, approxRelArray :: (MatrixShape.PowerStrip lower, MatrixShape.PowerStrip upper) => (Extent.Measure meas, Extent.C vert, Extent.C horiz) => (Shape.C height, Shape.C width, Eq height, Eq width) => (Class.Floating a, RealOf a ~ ar, Class.Real ar) => ArrayMatrix pack property lower upper meas vert horiz height width a -> ArrayMatrix pack property lower upper meas vert horiz height width a -> Bool approxRelMatrix a b = approxMatrix (Scalar.selectReal 0.5 1e-4 * (max 1 $ Vector.normInf $ ArrMatrix.unwrap a)) a b approxRelArray a b = Util.approxArrayTol (max (Scalar.selectReal 1e-1 1e-4) (Scalar.selectReal 1e-1 1e-5 * Vector.normInf (ArrMatrix.unwrap a))) a b multiplySolveTrans :: (Shape.C size, Eq size, Class.Floating a, RealOf a ~ ar, Class.Real ar) => LU.Transposition -> (SquareMatrix size a, Matrix.General size ShapeInt a) -> Bool multiplySolveTrans trans (SquareMatrix a, b) = approxRelMatrix b $ Matrix.multiplySquare trans a $ Matrix.solve trans a b multiplySolveRight :: (Shape.C size, Eq size, Class.Floating a, RealOf a ~ ar, Class.Real ar) => (SquareMatrix size a, Matrix.General size ShapeInt a) -> Bool multiplySolveRight (SquareMatrix a, b) = approxRelMatrix b (a #*## (a #\## b)) multiplySolveLeft :: (Shape.C size, Eq size, Class.Floating a, RealOf a ~ ar, Class.Real ar) => (Matrix.General ShapeInt size a, SquareMatrix size a) -> Bool multiplySolveLeft (b, SquareMatrix a) = approxRelMatrix b ((b ##/# a) ##*# a) multiplyInverseRight :: (Shape.C size, Eq size, Class.Floating a, RealOf a ~ ar, Class.Real ar) => (SquareMatrix size a, Matrix.General size ShapeInt a) -> Bool multiplyInverseRight (SquareMatrix a, b) = approxRelMatrix b (a #*## (Special.Inverse a #*## b)) multiplyInverseLeft :: (Shape.C size, Eq size, Class.Floating a, RealOf a ~ ar, Class.Real ar) => (Matrix.General ShapeInt size a, SquareMatrix size a) -> Bool multiplyInverseLeft (b, SquareMatrix a) = approxRelMatrix b ((b ##*# Special.Inverse a) ##*# a) solve :: (MatrixShape.Packing pack, MatrixShape.Property property, MatrixShape.Strip lower, MatrixShape.Strip upper) => (Class.Floating a, RealOf a ~ ar, Class.Real ar) => (Quadratic pack property upper lower ShapeInt a, Matrix.General ShapeInt ShapeInt a) -> Bool solve (a, b) = approxRelArray (Square.solve (Matrix.toSquare a) b) (Matrix.solveRight a b) solveIdentity :: (MatrixShape.Packing pack, MatrixShape.Property property, MatrixShape.Strip lower, MatrixShape.Strip upper) => (Class.Floating a, RealOf a ~ ar, Class.Real ar) => (Quadratic pack property upper lower ShapeInt a, Matrix.General ShapeInt ShapeInt a) -> Bool solveIdentity (eye, a) = approxMatrix (Scalar.selectReal 1e-3 1e-5) a (Matrix.solveRight eye a) inverse :: (MatrixShape.Packing pack, MatrixShape.Property property, MatrixShape.PowerStrip lower, MatrixShape.PowerStrip upper) => (Class.Floating a, RealOf a ~ ar, Class.Real ar) => Quadratic pack property upper lower ShapeInt a -> Bool inverse a = approxRelArray (Square.inverse $ Matrix.toSquare a) (Matrix.toSquare $ Matrix.inverse a) checkForAll :: (Show a, QC.Testable test) => Gen.T dim tag a -> (a -> test) -> Tagged tag QC.Property checkForAll gen = Util.checkForAll (Gen.run gen 3 5) data SquareMatrix size a = forall typ xl xu lower upper matrix. (Matrix.BoxExtra typ xl, Matrix.BoxExtra typ xu, Matrix.Solve typ, Matrix.SolveExtra typ xl, Matrix.SolveExtra typ xu, Matrix.MultiplySquare typ, Matrix.MultiplySquareExtra typ xl, Matrix.MultiplySquareExtra typ xu, Matrix.ToQuadratic typ, MatrixShape.Strip lower, MatrixShape.Strip upper, Matrix.Quadratic typ xl xu lower upper size a ~ matrix, Show matrix) => SquareMatrix (Matrix.Quadratic typ xl xu lower upper size a) instance Show (SquareMatrix size a) where show (SquareMatrix m) = show m testsVarAny :: (Logic.Dim sh, Shape.C sh, Show sh, Eq sh) => (Show a, Class.Floating a, Eq a, RealOf a ~ ar, Class.Real ar) => [(String, Gen.Square sh a (SquareMatrix sh a) -> Tagged a QC.Property)] testsVarAny = ("multiplySolveTrans", \gen -> Gen.withExtra checkForAll QC.arbitraryBoundedEnum ((,) <$> gen <#\#> Gen.matrix) multiplySolveTrans) : ("multiplySolveRight", \gen -> checkForAll ((,) <$> gen <#\#> Gen.matrix) multiplySolveRight) : ("multiplySolveLeft", \gen -> checkForAll ((,) <$> Gen.matrix <#/#> gen) multiplySolveLeft) : ("multiplyInverseRight", \gen -> checkForAll ((,) <$> gen <#\#> Gen.matrix) multiplyInverseRight) : ("multiplyInverseLeft", \gen -> checkForAll ((,) <$> Gen.matrix <#/#> gen) multiplyInverseLeft) : [] testsVar :: (Matrix.BoxExtra typ xl, Matrix.BoxExtra typ xu, Matrix.Solve typ, Matrix.SolveExtra typ xl, Matrix.SolveExtra typ xu, Matrix.MultiplySquare typ, Matrix.MultiplySquareExtra typ xl, Matrix.MultiplySquareExtra typ xu, Matrix.ToQuadratic typ, MatrixShape.Strip lower, MatrixShape.Strip upper, Logic.Dim sh, Shape.C sh, Show sh, Eq sh, Matrix.Quadratic typ xl xu lower upper sh a ~ matrix, Show matrix, Show a, Class.Floating a, Eq a, RealOf a ~ ar, Class.Real ar) => Gen.Square sh a (Matrix.Quadratic typ xl xu lower upper sh a) -> [(String, Tagged a QC.Property)] testsVar gen = map (mapSnd ($ (SquareMatrix <$> gen))) testsVarAny