packages feed

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 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++[![Travis CI build status](https://travis-ci.org/dzhus/simple-vec3.svg)](https://travis-ci.org/dzhus/simple-vec3)+[![Hackage](https://img.shields.io/hackage/v/simple-vec3.svg?colorB=5e5184&style=flat)](https://hackage.haskell.org/package/simple-vec3)+[![Hackage deps](https://img.shields.io/hackage-deps/v/simple-vec3.svg)](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.++![simple-vec3 benchmarks](benchmark.png)++[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 #-}