simple-vec3 0.3.1 → 0.4
raw patch · 9 files changed
+252/−152 lines, 9 filesdep +doctestdep +doctest-discoverdep −tasty-thdep −vector-th-unbox
Dependencies added: doctest, doctest-discover
Dependencies removed: tasty-th, vector-th-unbox
Files
- CHANGELOG.md +11/−0
- README.md +47/−0
- simple-vec3.cabal +20/−13
- src/Data/Vec3.hs +56/−7
- src/Data/Vec3/Class.hs +33/−0
- src/Data/Vec3/Tupled.hs +0/−64
- tests/Main.hs +84/−0
- tests/Tests.hs +0/−68
- tests/doctest-driver.hs +1/−0
CHANGELOG.md view
@@ -1,5 +1,15 @@ # Changelog +## [0.4] - 2018-02-20++### Added++- Doctests++### Changed++- `TVec3` is now just a type synonym for `(Double, Double, Double)`+ ## [0.3.1] - 2018-02-18 ### Added@@ -48,6 +58,7 @@ ## [0.1.0.0] - 2012-12-05 +[0.4]: https://github.com/dzhus/simple-vec3/compare/0.3.1...0.4 [0.3.1]: https://github.com/dzhus/simple-vec3/compare/0.3...0.3.1 [0.3]: https://github.com/dzhus/simple-vec3/compare/0.2...0.3 [0.2]: https://github.com/dzhus/simple-vec3/compare/0.1.0.1...0.2
+ README.md view
@@ -0,0 +1,47 @@+# simple-vec3++[](https://travis-ci.org/dzhus/simple-vec3)+[](https://hackage.haskell.org/package/simple-vec3)+[](http://packdeps.haskellers.com/feed?needle=simple-vec3)++*Simple* three-dimensional vectors of doubles with basic vector and+matrix operations, supporting `Data.Vector.Unboxed` and+`Data.Vector.Storable`.++```haskell+>>> let v1 = (-1, 0.0, 0.2) :: TVec3+>>> let v2 = ( 1, 2.3, 5.0) :: TVec3+>>> let v3 = ( 1, 1, -0.2) :: TVec3++-- Add two vectors:+>>> v1 <+> v2+(0.0, 2.3, 5.2)++-- Dot product:+>>> v1 .* v2+0.0++-- Multiply by a scalar:+>>> v1 .^ 5+(-5.0, 0.0, 1.0)++-- Cross product:+>>> v1 >< v3+(-0.2, 0.0, -1.0)++-- Matrix-vector product:+>>> diag 2 `mxv` v2+(2.0, 4.6, 10.0)+```++Please consult the [Hackage page for simple-vec3][hackage-doc] for full+documentation.++The package provides two different implementations for `Vec3` type+class, which differ in storage scheme. Benchmarks are included for+both. You most likely want to use `CVec3` which is based on contiguous+storage scheme and offers the best performance.++++[hackage-doc]: https://hackage.haskell.org/package/simple-vec3/docs/Data-Vec3.html
simple-vec3.cabal view
@@ -1,5 +1,5 @@ name: simple-vec3-version: 0.3.1+version: 0.4 cabal-version: >=1.10 build-type: Simple license: BSD3@@ -14,6 +14,7 @@ author: Dmitry Dzhus extra-source-files: CHANGELOG.md+ README.md source-repository head type: git@@ -26,26 +27,34 @@ build-depends: QuickCheck <2.11, base <5,- vector <0.13,- vector-th-unbox <0.3+ vector <0.13 default-language: Haskell2010 hs-source-dirs: src other-modules:- Data.Vec3.Tupled+ Paths_simple_vec3 ghc-options: -Wall -Wcompat -O2 +test-suite simple-vec3-doctests+ type: exitcode-stdio-1.0+ main-is: doctest-driver.hs+ build-depends:+ base <5,+ doctest <0.14,+ doctest-discover >=0.1.0.8 && <0.2+ default-language: Haskell2010+ hs-source-dirs: tests+ other-modules:+ Main+ Paths_simple_vec3+ ghc-options: -Wall -Wcompat -O2 -threaded test-suite simple-vec3-test type: exitcode-stdio-1.0- main-is: Tests.hs+ main-is: Main.hs build-depends:- QuickCheck <2.11, base <5, simple-vec3 -any, tasty <0.13,- tasty-quickcheck <0.10,- tasty-th <0.2,- vector <0.13,- vector-th-unbox <0.3+ tasty-quickcheck <0.10 default-language: Haskell2010 hs-source-dirs: tests other-modules:@@ -56,12 +65,10 @@ type: exitcode-stdio-1.0 main-is: Benchmark.hs build-depends:- QuickCheck <2.11, base <5, criterion <1.3, simple-vec3 -any,- vector <0.13,- vector-th-unbox <0.3+ vector <0.13 default-language: Haskell2010 hs-source-dirs: benchmark other-modules:
src/Data/Vec3.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeFamilies #-} @@ -13,9 +14,13 @@ -} module Data.Vec3- ( Vec3(..)+ ( -- * Examples+ -- $examples+ -- * Type class+ Vec3(..)+ -- * Implementations , CVec3(..)- , TVec3(..)+ , TVec3 ) where@@ -28,13 +33,47 @@ import Data.Vector.Unboxed as VU import Data.Vector.Generic as VG import Data.Vector.Generic.Mutable as VGM-import Test.QuickCheck+import Test.QuickCheck (Arbitrary(..)) import Data.Vec3.Class -import Data.Vec3.Tupled +-- $setup+-- >>> :set -XFlexibleContexts ++-- $examples+--+-- >>> let v1 = (-1, 0.0, 0.2) :: TVec3+-- >>> let v2 = ( 1, 2.3, 5.0) :: TVec3+-- >>> let v3 = ( 1, 1, -0.2) :: TVec3+--+-- Add two vectors:+--+-- >>> v1 <+> v2+-- (0.0,2.3,5.2)+--+-- Dot product:+--+-- >>> v1 .* v2+-- 0.0+--+-- Multiply by a scalar:+--+-- >>> v1 .^ 5+-- (-5.0,0.0,1.0)+--+-- Cross product:+--+-- >>> v1 >< v3+-- (-0.2,0.0,-1.0)+--+-- Matrix-vector product:+--+-- >>> diag 2 `mxv` v2+-- (2.0,4.6,10.0)++ -- | 'Vec3' implementation with 'Data.Vector.Unboxed.Unbox' and -- 'Data.Vector.Unboxed.Storable' instances based on a single -- contiguous array storage scheme, suitable for use with@@ -52,7 +91,7 @@ instance Vec3 CVec3 where- newtype Matrix CVec3 = TMatrix (CVec3, CVec3, CVec3)+ newtype Matrix CVec3 = CMatrix (CVec3, CVec3, CVec3) deriving (Eq, Show) fromXYZ (x, y, z) = CVec3 x y z@@ -61,10 +100,10 @@ toXYZ (CVec3 x y z) = (x, y, z) {-# INLINE toXYZ #-} - fromRows (r1, r2, r3) = TMatrix (r1, r2, r3)+ fromRows (r1, r2, r3) = CMatrix (r1, r2, r3) {-# INLINE fromRows #-} - toRows (TMatrix (r1, r2, r3)) = (r1, r2, r3)+ toRows (CMatrix (r1, r2, r3)) = (r1, r2, r3) {-# INLINE toRows #-} @@ -174,3 +213,13 @@ shrink (CVec3 x y z) = Prelude.map fromXYZ $ shrink (x, y, z)++instance Arbitrary (Matrix CVec3) where+ arbitrary = do+ r1 <- arbitrary+ r2 <- arbitrary+ r3 <- arbitrary+ return $ fromRows (r1, r2, r3)++ shrink (CMatrix (r1, r2, r3)) =+ Prelude.map fromRows $ shrink (r1, r2, r3)
src/Data/Vec3/Class.hs view
@@ -1,13 +1,19 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeSynonymInstances #-} module Data.Vec3.Class ( Vec3(..)+ , TVec3 ) where import Prelude hiding (zipWith) +import Test.QuickCheck (Arbitrary(..))+ -- | Three-dimensional vector, with an associated matrix type. class Vec3 v where -- | Associated type for 3×3 matrix.@@ -164,3 +170,30 @@ (r11, r12, r13) = toRows m1 (r21, r22, r23) = toRows m2 {-# INLINE addM #-}+++-- | 'Vec3' implementation with 'Data.Vector.Unboxed.Unbox' instance+-- based on default Unbox instance for tuples of arrays, which wraps a+-- vector of tuples as a tuple of vectors.+--+-- @+-- interface: [v1 (x, y, z); v2 (x, y, z) ...], length = N+-- | | | | | |+-- storage(x): [v1x-+ | | ; v2x-+ | | ...], length = N+-- storage(y): [v1y----+ | ; v2y----+ | ...], length = N+-- storage(z): [v1z-------+ ; v2z-------+ ...], length = N+-- @+--+-- You almost definitely want to use 'Data.Vec3.CVec3' instead as it has better+-- performance.+type TVec3 = (Double, Double, Double)++instance Vec3 TVec3 where+ newtype Matrix TVec3 = TMatrix { unTMatrix :: (TVec3, TVec3, TVec3) }+ deriving (Arbitrary, Eq, Show)++ fromXYZ = id+ toXYZ = id++ fromRows = TMatrix+ toRows = unTMatrix
− src/Data/Vec3/Tupled.hs
@@ -1,64 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeFamilies #-}--module Data.Vec3.Tupled- ( TVec3(..)- )--where--import Prelude--import Data.Vector.Unboxed.Deriving--import Data.Vec3.Class----- | 'Vec3' implementation with 'Data.Vector.Unboxed.Unbox' instance--- based on default Unbox instance for tuples of arrays, which wraps a--- vector of tuples as a tuple of vectors.------ @--- interface: [v1 (x, y, z); v2 (x, y, z) ...], length = N--- | | | | | |--- storage(x): [v1x-+ | | ; v2x-+ | | ...], length = N--- storage(y): [v1y----+ | ; v2y----+ | ...], length = N--- storage(z): [v1z-------+ ; v2z-------+ ...], length = N--- @------ You almost definitely want to use 'CVec3' instead as it has better--- performance.-newtype TVec3 = TVec3 (Double, Double, Double)- deriving (Eq, Show)---derivingUnbox "TVec3"- [t|TVec3 -> (Double, Double, Double)|]- [|\(TVec3 v) -> v|]- [|TVec3|]---instance Vec3 TVec3 where- newtype Matrix TVec3 = TMatrix (TVec3, TVec3, TVec3)- deriving (Eq, Show)--- fromXYZ = TVec3- {-# INLINE fromXYZ #-}-- toXYZ (TVec3 v) = v- {-# INLINE toXYZ #-}-- fromRows (r1, r2, r3) = TMatrix (r1, r2, r3)- {-# INLINE fromRows #-}-- toRows (TMatrix (r1, r2, r3)) = (r1, r2, r3)- {-# INLINE toRows #-}---derivingUnbox "TMatrix"- [t|Matrix TVec3 -> (TVec3, TVec3, TVec3)|]- [|\(TMatrix v) -> v|]- [|TMatrix|]
+ tests/Main.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}++import Data.Proxy++import Test.Tasty+import Test.Tasty.QuickCheck++import Data.Vec3+++infix 4 <~=>+(<~=>) :: forall v1 v2. (Vec3 v1, Vec3 v2) => v1 -> v2 -> Bool+(<~=>) a b = ax ~= bx &&+ ay ~= by &&+ az ~= bz+ where+ (ax, ay, az) = toXYZ (a :: v1)+ (bx, by, bz) = toXYZ (b :: v2)+++infix 4 ~=+(~=) :: Double -> Double -> Bool+(~=) a b | a == b = True+ | a == 0 || b == 0 || isDenormalized absDiff = absDiff < maxError+ | otherwise = absDiff / (abs a + abs b) < maxError+ where+ absDiff = abs $ a - b+ maxError = 1e-13+++tests+ :: forall ty.+ ( Arbitrary ty, Arbitrary (Matrix ty)+ , Show ty, Show (Matrix ty)+ , Vec3 ty, Eq ty+ )+ => Proxy ty+ -> [TestTree]+tests _ =+ [ testProperty+ "Commutativity of addition: a + b = b + a"+ (\(a :: ty) b -> a <+> b <~=> b <+> a)+ , testProperty+ "Associativity of addition: (a + b) + c = a + (b + c)"+ (\(a :: ty) b c -> (a <+> b) <+> c <~=> a <+> (b <+> c))+ , testProperty+ "Identity element of addition (zero): v + 0 = v"+ (\(v :: ty) -> (v <+> origin <~=> v))+ , testProperty+ "Inverse elements of addition: v + (-v) = 0"+ (\(v :: ty) -> (v <+> invert v <~=> (origin :: ty)))+ , testProperty+ "Compatibility of scalar and field multiplication"+ (\(v :: ty) p q -> (v .^ p .^ q <~=> v .^ (p * q)))+ , testProperty+ "Identity of scalar multiplication"+ (\(v :: ty) -> (v .^ 1 <~=> v))+ , testProperty+ "Distributivity wrt vector addition"+ (\(a :: ty) b p -> ((a <+> b) .^ p) <~=> (a .^ p) <+> (b .^ p))+ , testProperty+ "Distributivity wrt scalar addition"+ (\(a :: ty) p q -> (a .^ (p + q) <~=> (a .^ p) <+> (a .^ q)))+ , testProperty+ "Subtraction definition"+ (\(a :: ty) b -> (a <+> invert b <~=> a <-> b))+ , testProperty+ "Normalization"+ (\(v :: ty) -> (v <~=> (origin :: ty) || norm (normalize v) ~= 1))+ , testProperty+ "Triangle inequality"+ (\(a :: ty) b c -> (distance a b + distance b c >= distance a c))+ , testProperty+ "Diagonal matrix multiplication"+ (\(v :: ty) (s :: Double) -> (diag s `mxv` v == v .^ s))+ ]+++main :: IO ()+main = defaultMain $ testGroup "Tests"+ [ testGroup "CVec3" (tests (Proxy :: Proxy CVec3))+ , testGroup "TVec3" (tests (Proxy :: Proxy TVec3))+ ]
− tests/Tests.hs
@@ -1,68 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}--import Test.Tasty-import Test.Tasty.QuickCheck--import Data.Vec3---infix 4 <~=>-(<~=>) :: CVec3 -> CVec3 -> Bool-(<~=>) a b = ax ~= bx &&- ay ~= by &&- az ~= bz- where- (ax, ay, az) = toXYZ (a :: CVec3)- (bx, by, bz) = toXYZ (b :: CVec3)---infix 4 ~=-(~=) :: Double -> Double -> Bool-(~=) a b | a == b = True- | a == 0 || b == 0 || isDenormalized absDiff = absDiff < maxError- | otherwise = absDiff / (abs a + abs b) < maxError- where- absDiff = abs $ a - b- maxError = 1e-13---tests :: [TestTree]-tests =- [ testProperty- "Commutativity of addition: a + b = b + a"- (\(a :: CVec3) b -> a <+> b <~=> b <+> a)- , testProperty- "Associativity of addition: (a + b) + c = a + (b + c)"- (\(a :: CVec3) b c -> (a <+> b) <+> c <~=> a <+> (b <+> c))- , testProperty- "Identity element of addition (zero): v + 0 = v"- (\(v :: CVec3) -> (v <+> origin <~=> v))- , testProperty- "Inverse elements of addition: v + (-v) = 0"- (\(v :: CVec3) -> (v <+> invert v <~=> origin))- , testProperty- "Compatibility of scalar and field multiplication"- (\(v :: CVec3) p q -> (v .^ p .^ q <~=> v .^ (p * q)))- , testProperty- "Identity of scalar multiplication"- (\(v :: CVec3) -> (v .^ 1 <~=> v))- , testProperty- "Distributivity wrt vector addition"- (\(a :: CVec3) b p -> ((a <+> b) .^ p) <~=> (a .^ p) <+> (b .^ p))- , testProperty- "Distributivity wrt scalar addition"- (\(a :: CVec3) p q -> (a .^ (p + q) <~=> (a .^ p) <+> (a .^ q)))- , testProperty- "Subtraction definition"- (\(a :: CVec3) b -> (a <+> invert b <~=> a <-> b))- , testProperty- "Normalization"- (\(v :: CVec3) -> (v <~=> origin || norm (normalize v) ~= 1))- , testProperty- "Triangle inequality"- (\(a :: CVec3) b c -> (distance a b + distance b c >= distance a c))- ]---main :: IO ()-main = defaultMain $ testGroup "Tests" tests
+ tests/doctest-driver.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF doctest-discover #-}