comfort-array 0.4.1 → 0.5
raw patch · 21 files changed
+1147/−442 lines, 21 filesdep +storablevectorPVP ok
version bump matches the API change (PVP)
Dependencies added: storablevector
API changes (from Hackage documentation)
- Data.Array.Comfort.Shape: (:+:) :: sh0 -> sh1 -> (:+:) sh0 sh1
- Data.Array.Comfort.Shape: instance (Control.DeepSeq.NFData sh0, Control.DeepSeq.NFData sh1) => Control.DeepSeq.NFData (sh0 Data.Array.Comfort.Shape.:+: sh1)
- Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.C sh0, Data.Array.Comfort.Shape.C sh1) => Data.Array.Comfort.Shape.C (sh0 Data.Array.Comfort.Shape.:+: sh1)
- Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.Indexed sh0, Data.Array.Comfort.Shape.Indexed sh1) => Data.Array.Comfort.Shape.Indexed (sh0 Data.Array.Comfort.Shape.:+: sh1)
- Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.InvIndexed sh0, Data.Array.Comfort.Shape.InvIndexed sh1) => Data.Array.Comfort.Shape.InvIndexed (sh0 Data.Array.Comfort.Shape.:+: sh1)
- Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.Static sh0, Data.Array.Comfort.Shape.Static sh1) => Data.Array.Comfort.Shape.Static (sh0 Data.Array.Comfort.Shape.:+: sh1)
- Data.Array.Comfort.Shape: instance (GHC.Classes.Eq sh0, GHC.Classes.Eq sh1) => GHC.Classes.Eq (sh0 Data.Array.Comfort.Shape.:+: sh1)
- Data.Array.Comfort.Shape: instance (GHC.Show.Show sh0, GHC.Show.Show sh1) => GHC.Show.Show (sh0 Data.Array.Comfort.Shape.:+: sh1)
- Data.Array.Comfort.Shape: uncheckedSize :: C sh => sh -> Int
+ Data.Array.Comfort.Boxed: accessMaybe :: Indexed sh => Array sh a -> Index sh -> Maybe a
+ Data.Array.Comfort.Boxed.Unchecked: (!) :: Indexed sh => Array sh a -> Index sh -> a
+ Data.Array.Comfort.Boxed.Unchecked: Array :: sh -> Array a -> Array sh a
+ Data.Array.Comfort.Boxed.Unchecked: [buffer] :: Array sh a -> Array a
+ Data.Array.Comfort.Boxed.Unchecked: [shape] :: Array sh a -> sh
+ Data.Array.Comfort.Boxed.Unchecked: data Array sh a
+ Data.Array.Comfort.Boxed.Unchecked: fromList :: C sh => sh -> [a] -> Array sh a
+ Data.Array.Comfort.Boxed.Unchecked: infixl 9 !
+ Data.Array.Comfort.Boxed.Unchecked: instance (Data.Array.Comfort.Shape.C sh, Control.DeepSeq.NFData sh, Control.DeepSeq.NFData a) => Control.DeepSeq.NFData (Data.Array.Comfort.Boxed.Unchecked.Array sh a)
+ Data.Array.Comfort.Boxed.Unchecked: instance (Data.Array.Comfort.Shape.C sh, GHC.Show.Show sh, GHC.Show.Show a) => GHC.Show.Show (Data.Array.Comfort.Boxed.Unchecked.Array sh a)
+ Data.Array.Comfort.Boxed.Unchecked: instance Data.Array.Comfort.Shape.C sh => Data.Foldable.Foldable (Data.Array.Comfort.Boxed.Unchecked.Array sh)
+ Data.Array.Comfort.Boxed.Unchecked: instance Data.Array.Comfort.Shape.C sh => Data.Traversable.Traversable (Data.Array.Comfort.Boxed.Unchecked.Array sh)
+ Data.Array.Comfort.Boxed.Unchecked: instance Data.Array.Comfort.Shape.C sh => GHC.Base.Functor (Data.Array.Comfort.Boxed.Unchecked.Array sh)
+ Data.Array.Comfort.Boxed.Unchecked: instance Data.Array.Comfort.Shape.Static sh => GHC.Base.Applicative (Data.Array.Comfort.Boxed.Unchecked.Array sh)
+ Data.Array.Comfort.Boxed.Unchecked: map :: C sh => (a -> b) -> Array sh a -> Array sh b
+ Data.Array.Comfort.Boxed.Unchecked: mapShape :: (sh0 -> sh1) -> Array sh0 a -> Array sh1 a
+ Data.Array.Comfort.Boxed.Unchecked: replicate :: C sh => sh -> a -> Array sh a
+ Data.Array.Comfort.Boxed.Unchecked: reshape :: sh1 -> Array sh0 a -> Array sh1 a
+ Data.Array.Comfort.Boxed.Unchecked: toList :: C sh => Array sh a -> [a]
+ Data.Array.Comfort.Boxed.Unchecked: vectorFromList :: [a] -> Array (ZeroBased Int) a
+ Data.Array.Comfort.Boxed.Unchecked: zipWith :: C sh => (a -> b -> c) -> Array sh a -> Array sh b -> Array sh c
+ Data.Array.Comfort.Shape: (::+) :: sh0 -> sh1 -> (::+) sh0 sh1
+ Data.Array.Comfort.Shape: AllDistinct :: AllDistinct
+ Data.Array.Comfort.Shape: Distinct :: Collision
+ Data.Array.Comfort.Shape: Repetitive :: Collision
+ Data.Array.Comfort.Shape: Simplex :: SimplexOrder order -> f coll -> size -> Simplex order coll f size
+ Data.Array.Comfort.Shape: SomeRepetitive :: SomeRepetitive
+ Data.Array.Comfort.Shape: [Ascending] :: SimplexOrder Ascending
+ Data.Array.Comfort.Shape: [Checked] :: CheckSingleton Checked
+ Data.Array.Comfort.Shape: [Descending] :: SimplexOrder Descending
+ Data.Array.Comfort.Shape: [Unchecked] :: CheckSingleton Unchecked
+ Data.Array.Comfort.Shape: [simplexDimension] :: Simplex order coll f size -> f coll
+ Data.Array.Comfort.Shape: [simplexOrder] :: Simplex order coll f size -> SimplexOrder order
+ Data.Array.Comfort.Shape: [simplexSize] :: Simplex order coll f size -> size
+ Data.Array.Comfort.Shape: assert :: Checking check => String -> Bool -> Result check ()
+ Data.Array.Comfort.Shape: assertIndexFromOffset :: Checking check => String -> Int -> Bool -> Result check ()
+ Data.Array.Comfort.Shape: class Checking check where {
+ Data.Array.Comfort.Shape: class CollisionC coll
+ Data.Array.Comfort.Shape: class SimplexOrderC order
+ Data.Array.Comfort.Shape: data AllDistinct
+ Data.Array.Comfort.Shape: data Ascending
+ Data.Array.Comfort.Shape: data CheckSingleton check
+ Data.Array.Comfort.Shape: data Collision
+ Data.Array.Comfort.Shape: data Descending
+ Data.Array.Comfort.Shape: data Simplex order coll f size
+ Data.Array.Comfort.Shape: data SimplexOrder order
+ Data.Array.Comfort.Shape: data SomeRepetitive
+ Data.Array.Comfort.Shape: data family Result check a;
+ Data.Array.Comfort.Shape: instance (Control.DeepSeq.NFData sh0, Control.DeepSeq.NFData sh1) => Control.DeepSeq.NFData (sh0 Data.Array.Comfort.Shape.::+ sh1)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.C sh0, Data.Array.Comfort.Shape.C sh1) => Data.Array.Comfort.Shape.C (sh0 Data.Array.Comfort.Shape.::+ sh1)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.Checking check, GHC.Classes.Eq a) => GHC.Classes.Eq (Data.Array.Comfort.Shape.Result check a)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.Indexed sh0, Data.Array.Comfort.Shape.Indexed sh1) => Data.Array.Comfort.Shape.Indexed (sh0 Data.Array.Comfort.Shape.::+ sh1)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.InvIndexed sh0, Data.Array.Comfort.Shape.InvIndexed sh1) => Data.Array.Comfort.Shape.InvIndexed (sh0 Data.Array.Comfort.Shape.::+ sh1)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.SimplexOrderC order, Data.Array.Comfort.Shape.CollisionC coll, Data.Traversable.Traversable f, Data.Array.Comfort.Shape.C size) => Data.Array.Comfort.Shape.C (Data.Array.Comfort.Shape.Simplex order coll f size)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.SimplexOrderC order, Data.Array.Comfort.Shape.CollisionC coll, Data.Traversable.Traversable f, Data.Functor.Classes.Eq1 f, Data.Array.Comfort.Shape.Indexed size) => Data.Array.Comfort.Shape.Indexed (Data.Array.Comfort.Shape.Simplex order coll f size)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.SimplexOrderC order, Data.Array.Comfort.Shape.CollisionC coll, Data.Traversable.Traversable f, Data.Functor.Classes.Eq1 f, Data.Array.Comfort.Shape.InvIndexed size) => Data.Array.Comfort.Shape.InvIndexed (Data.Array.Comfort.Shape.Simplex order coll f size)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.SimplexOrderC order, GHC.Show.Show coll, Data.Functor.Classes.Show1 f, GHC.Show.Show size) => GHC.Show.Show (Data.Array.Comfort.Shape.Simplex order coll f size)
+ Data.Array.Comfort.Shape: instance (Data.Array.Comfort.Shape.Static sh0, Data.Array.Comfort.Shape.Static sh1) => Data.Array.Comfort.Shape.Static (sh0 Data.Array.Comfort.Shape.::+ sh1)
+ Data.Array.Comfort.Shape: instance (GHC.Classes.Eq sh0, GHC.Classes.Eq sh1) => GHC.Classes.Eq (sh0 Data.Array.Comfort.Shape.::+ sh1)
+ Data.Array.Comfort.Shape: instance (GHC.Show.Show sh0, GHC.Show.Show sh1) => GHC.Show.Show (sh0 Data.Array.Comfort.Shape.::+ sh1)
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Checking Data.Array.Comfort.Shape.Checked
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Checking Data.Array.Comfort.Shape.Unchecked
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Checking check => GHC.Base.Applicative (Data.Array.Comfort.Shape.Result check)
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Checking check => GHC.Base.Functor (Data.Array.Comfort.Shape.Result check)
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.Checking check => GHC.Base.Monad (Data.Array.Comfort.Shape.Result check)
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.CollisionC Data.Array.Comfort.Shape.AllDistinct
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.CollisionC Data.Array.Comfort.Shape.Collision
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.CollisionC Data.Array.Comfort.Shape.SomeRepetitive
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.SimplexOrderC Data.Array.Comfort.Shape.Ascending
+ Data.Array.Comfort.Shape: instance Data.Array.Comfort.Shape.SimplexOrderC Data.Array.Comfort.Shape.Descending
+ Data.Array.Comfort.Shape: instance GHC.Classes.Eq (Data.Array.Comfort.Shape.SimplexOrder order)
+ Data.Array.Comfort.Shape: instance GHC.Classes.Eq Data.Array.Comfort.Shape.AllDistinct
+ Data.Array.Comfort.Shape: instance GHC.Classes.Eq Data.Array.Comfort.Shape.Collision
+ Data.Array.Comfort.Shape: instance GHC.Classes.Eq Data.Array.Comfort.Shape.SomeRepetitive
+ Data.Array.Comfort.Shape: instance GHC.Classes.Ord Data.Array.Comfort.Shape.Collision
+ Data.Array.Comfort.Shape: instance GHC.Enum.Enum Data.Array.Comfort.Shape.Collision
+ Data.Array.Comfort.Shape: instance GHC.Show.Show (Data.Array.Comfort.Shape.SimplexOrder order)
+ Data.Array.Comfort.Shape: instance GHC.Show.Show Data.Array.Comfort.Shape.AllDistinct
+ Data.Array.Comfort.Shape: instance GHC.Show.Show Data.Array.Comfort.Shape.Collision
+ Data.Array.Comfort.Shape: instance GHC.Show.Show Data.Array.Comfort.Shape.SomeRepetitive
+ Data.Array.Comfort.Shape: messageIndexFromOffset :: String -> Int -> String
+ Data.Array.Comfort.Shape: requireCheck :: CheckSingleton check -> Result check a -> Result check a
+ Data.Array.Comfort.Shape: runChecked :: String -> Result Checked a -> a
+ Data.Array.Comfort.Shape: runUnchecked :: Result Unchecked a -> a
+ Data.Array.Comfort.Shape: simplexAscending :: f coll -> size -> SimplexAscending coll f size
+ Data.Array.Comfort.Shape: simplexDescending :: f coll -> size -> SimplexDescending coll f size
+ Data.Array.Comfort.Shape: switchCheck :: Checking check => f Checked -> f Unchecked -> f check
+ Data.Array.Comfort.Shape: throwOrError :: Checking check => String -> Result check a
+ Data.Array.Comfort.Shape: type SimplexAscending = Simplex Ascending
+ Data.Array.Comfort.Shape: type SimplexDescending = Simplex Descending
+ Data.Array.Comfort.Shape: unifiedIndexFromOffset :: (InvIndexed sh, Checking check) => sh -> Int -> Result check (Index sh)
+ Data.Array.Comfort.Shape: unifiedOffset :: (Indexed sh, Checking check) => sh -> Index sh -> Result check Int
+ Data.Array.Comfort.Shape: unifiedSizeOffset :: (Indexed sh, Checking check) => sh -> (Int, Index sh -> Result check Int)
+ Data.Array.Comfort.Storable: accessMaybe :: (Indexed sh, Storable a) => Array sh a -> Index sh -> Maybe a
+ Data.Array.Comfort.Storable: fromRowArray :: (C sh0, C sh1, Eq sh1, Storable a) => sh1 -> Array sh0 (Array sh1 a) -> Array (sh0, sh1) a
+ Data.Array.Comfort.Storable: fromStorableVector :: Storable a => Vector a -> Array (ZeroBased Int) a
+ Data.Array.Comfort.Storable: infixr 5 `append`
+ Data.Array.Comfort.Storable: pick :: (Indexed sh0, C sh1, Storable a) => Array (sh0, sh1) a -> Index sh0 -> Array sh1 a
+ Data.Array.Comfort.Storable: toRowArray :: (Indexed sh0, C sh1, Storable a) => Array (sh0, sh1) a -> Array sh0 (Array sh1 a)
+ Data.Array.Comfort.Storable: toStorableVector :: (C sh, Storable a) => Array sh a -> Vector a
+ Data.Array.Comfort.Storable.Mutable: readMaybe :: (PrimMonad m, Indexed sh, Storable a) => Array m sh a -> Index sh -> Maybe (m a)
+ Data.Array.Comfort.Storable.Mutable.Private: readMaybe :: (PrimMonad m, Indexed sh, Storable a) => Array m sh a -> Index sh -> Maybe (m a)
+ Data.Array.Comfort.Storable.Mutable.Unchecked: readMaybe :: (PrimMonad m, Indexed sh, Storable a) => Array m sh a -> Index sh -> Maybe (m a)
+ Data.Array.Comfort.Storable.Unchecked: infixr 5 `append`
- Data.Array.Comfort.Shape: data sh0 :+: sh1
+ Data.Array.Comfort.Shape: data sh0 ::+ sh1
- Data.Array.Comfort.Shape: infixr 5 :+:
+ Data.Array.Comfort.Shape: infixr 5 ::+
- Data.Array.Comfort.Shape: type family Index sh :: *;
+ Data.Array.Comfort.Shape: type family Index sh;
- Data.Array.Comfort.Shape: zeroBasedSplit :: Real n => n -> ZeroBased n -> ZeroBased n :+: ZeroBased n
+ Data.Array.Comfort.Shape: zeroBasedSplit :: Real n => n -> ZeroBased n -> ZeroBased n ::+ ZeroBased n
- Data.Array.Comfort.Storable: append :: (C shx, C shy, Storable a) => Array shx a -> Array shy a -> Array (shx :+: shy) a
+ Data.Array.Comfort.Storable: append :: (C shx, C shy, Storable a) => Array shx a -> Array shy a -> Array (shx ::+ shy) a
- Data.Array.Comfort.Storable: split :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> (Array sh0 a, Array sh1 a)
+ Data.Array.Comfort.Storable: split :: (C sh0, C sh1, Storable a) => Array (sh0 ::+ sh1) a -> (Array sh0 a, Array sh1 a)
- Data.Array.Comfort.Storable: takeCenter :: (C sh0, C sh1, C sh2, Storable a) => Array (sh0 :+: (sh1 :+: sh2)) a -> Array sh1 a
+ Data.Array.Comfort.Storable: takeCenter :: (C sh0, C sh1, C sh2, Storable a) => Array (sh0 ::+ (sh1 ::+ sh2)) a -> Array sh1 a
- Data.Array.Comfort.Storable: takeLeft :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> Array sh0 a
+ Data.Array.Comfort.Storable: takeLeft :: (C sh0, C sh1, Storable a) => Array (sh0 ::+ sh1) a -> Array sh0 a
- Data.Array.Comfort.Storable: takeRight :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> Array sh1 a
+ Data.Array.Comfort.Storable: takeRight :: (C sh0, C sh1, Storable a) => Array (sh0 ::+ sh1) a -> Array sh1 a
- Data.Array.Comfort.Storable.Unchecked: append :: (C shx, C shy, Storable a) => Array shx a -> Array shy a -> Array (shx :+: shy) a
+ Data.Array.Comfort.Storable.Unchecked: append :: (C shx, C shy, Storable a) => Array shx a -> Array shy a -> Array (shx ::+ shy) a
- Data.Array.Comfort.Storable.Unchecked: split :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> (Array sh0 a, Array sh1 a)
+ Data.Array.Comfort.Storable.Unchecked: split :: (C sh0, C sh1, Storable a) => Array (sh0 ::+ sh1) a -> (Array sh0 a, Array sh1 a)
- Data.Array.Comfort.Storable.Unchecked: takeCenter :: (C sh0, C sh1, C sh2, Storable a) => Array (sh0 :+: (sh1 :+: sh2)) a -> Array sh1 a
+ Data.Array.Comfort.Storable.Unchecked: takeCenter :: (C sh0, C sh1, C sh2, Storable a) => Array (sh0 ::+ (sh1 ::+ sh2)) a -> Array sh1 a
- Data.Array.Comfort.Storable.Unchecked: takeLeft :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> Array sh0 a
+ Data.Array.Comfort.Storable.Unchecked: takeLeft :: (C sh0, C sh1, Storable a) => Array (sh0 ::+ sh1) a -> Array sh0 a
- Data.Array.Comfort.Storable.Unchecked: takeRight :: (C sh0, C sh1, Storable a) => Array (sh0 :+: sh1) a -> Array sh1 a
+ Data.Array.Comfort.Storable.Unchecked: takeRight :: (C sh0, C sh1, Storable a) => Array (sh0 ::+ sh1) a -> Array sh1 a
Files
- Changes.md +18/−0
- comfort-array.cabal +26/−8
- set/0.4.0/Data/Array/Comfort/Shape/Set.hs +6/−10
- set/0.5.4/Data/Array/Comfort/Shape/Set.hs +13/−6
- src/Data/Array/Comfort/Boxed.hs +11/−5
- src/Data/Array/Comfort/Boxed/Strict/Unchecked.hs +35/−0
- src/Data/Array/Comfort/Boxed/Unchecked.hs +27/−25
- src/Data/Array/Comfort/Container.hs +0/−1
- src/Data/Array/Comfort/Shape.hs +605/−269
- src/Data/Array/Comfort/Shape/Test.hs +91/−5
- src/Data/Array/Comfort/Shape/Utility.hs +9/−2
- src/Data/Array/Comfort/Storable.hs +90/−6
- src/Data/Array/Comfort/Storable/Mutable.hs +5/−4
- src/Data/Array/Comfort/Storable/Mutable/Private.hs +8/−0
- src/Data/Array/Comfort/Storable/Mutable/Unchecked.hs +1/−0
- src/Data/Array/Comfort/Storable/Unchecked.hs +14/−11
- test/DocTest/Data/Array/Comfort/Shape.hs +106/−58
- test/DocTest/Data/Array/Comfort/Storable.hs +40/−13
- test/DocTest/Data/Array/Comfort/Storable/Unchecked.hs +15/−15
- test/Main.hs +0/−1
- test/Test/Shape.hs +27/−3
Changes.md view
@@ -1,5 +1,23 @@ # Change log for the `comfort-array` package +## 0.5++ * `Array.Boxed`.`map`, `zipWith`, `toList`: make lazy++ * add `unified` methods to `Shape` classes:+ `unifiedSize`, `unifiedOffset`, `unifiedSizeOffset`,+ `uncheckedIndexFromOffset`.+ They simplify to share code between checked and unchecked variants.+ Actually, many implementations of these methods+ recursively call themselves on part shapes.+ However, the default methods have changed.++ * `Shape.:+:` -> `Shape.::+`.+ This resolves the name clash with the `:+:` operator from `tfp`.+ It also highlights the right associativity and non-commutativity.++ * `Shape.Simplex`+ ## 0.4.1 * use `doctest-extract` for tests
comfort-array.cabal view
@@ -1,5 +1,5 @@ Name: comfort-array-Version: 0.4.1+Version: 0.5 License: BSD3 License-File: LICENSE Author: Henning Thielemann <haskell@henning-thielemann.de>@@ -45,10 +45,10 @@ * @Enumeration@: Arrays with indices like 'LT', 'EQ', 'GT' and a shape of fixed size. .- * @(:+:)@:+ * @(::+)@: The Append type constructor allows to respresent block arrays, e.g. block matrices.- It also allows to represent non-empty arrays via @():+:sh@.+ It also allows to represent non-empty arrays via @()::+sh@. . * @Set@: Use an arbitrary ordered set as index set. .@@ -57,16 +57,32 @@ * @Triangular@: A 2D array with the shape of a lower or upper triangular matrix. .+ * @Simplex@:+ Simplices of any dimension, where the dimension is encoded in the type.+ An index is a tuple of monotonic ordered sub-indices.+ . * @Square@: A 2D array where both dimensions always have equal size. . * @Cube@: A 3D array where all three dimensions always have equal size. . * @Tagged@: Statically distinguish shapes and indices that are isomorphic. .- The @lapack@ package defines even more fancy shapes- like tall rectangular matrices, triangular matrices and banded matrices.+ With our @Array@ type you can perform+ .+ * Fast Linear Algebra using the package @lapack@.+ The @lapack@ package defines even more fancy shapes+ like tall rectangular matrices, triangular matrices and banded matrices.+ .+ * Fast Fourier Transforms using the package @comfort-fftw@+ .+ * Efficient Array Processing via LLVM Just-In-Time code generation+ using the package @knead@.+ .+ See also @comfort-graph@ for a Graph data structure,+ with non-Int node identifiers and flexible edge types. -Tested-With: GHC==7.4.2, GHC==7.8.4, GHC==8.2.2+Tested-With: GHC==7.4.2, GHC==7.8.4+Tested-With: GHC==8.2.2, GHC==8.6.5, GHC==8.10.4 Cabal-Version: 1.14 Build-Type: Simple Extra-Source-Files:@@ -74,7 +90,7 @@ test-module.list Source-Repository this- Tag: 0.4.1+ Tag: 0.5 Type: darcs Location: https://hub.darcs.net/thielema/comfort-array/ @@ -88,6 +104,7 @@ Library Build-Depends:+ storablevector >=0.2 && <0.3, primitive >=0.6.4 && <0.8, guarded-allocation >=0.0.1 && <0.1, storable-record >=0.0.1 && <0.1,@@ -122,11 +139,12 @@ Data.Array.Comfort.Storable.Mutable.Unchecked Data.Array.Comfort.Storable.Mutable.Private Data.Array.Comfort.Boxed+ Data.Array.Comfort.Boxed.Unchecked Data.Array.Comfort.Container Other-Modules: Data.Array.Comfort.Shape.Set Data.Array.Comfort.Shape.Utility- Data.Array.Comfort.Boxed.Unchecked+ Data.Array.Comfort.Boxed.Strict.Unchecked Data.Array.Comfort.Storable.Memory Data.Array.Comfort.Check
set/0.4.0/Data/Array/Comfort/Shape/Set.hs view
@@ -5,24 +5,20 @@ import qualified Data.Set as Set import Data.Set (Set) import Data.Tuple.HT (fst3)+import Data.Maybe.HT (toMaybe) -offset :: Ord a => Set a -> a -> Int+offset :: Ord a => Set a -> a -> Maybe Int offset set ix = case Set.splitMember ix set of- (less, hit, _) ->- if hit- then Set.size less- else error "Shape.Set: array index not member of the index set"+ (less, hit, _) -> toMaybe hit (Set.size less) uncheckedOffset :: Ord a => Set a -> a -> Int uncheckedOffset set = Set.size . fst3 . flip Set.splitMember set -indexFromOffset :: Set a -> Int -> a-indexFromOffset set k =- if 0<=k- then uncheckedIndexFromOffset set k- else errorIndexFromOffset "Set" k++indexFromOffset :: Set a -> Int -> Maybe a+indexFromOffset set k = toMaybe (0<=k) (uncheckedIndexFromOffset set k) uncheckedIndexFromOffset :: Set a -> Int -> a uncheckedIndexFromOffset set k =
set/0.5.4/Data/Array/Comfort/Shape/Set.hs view
@@ -2,12 +2,19 @@ import qualified Data.Set as Set import Data.Set (Set)+import Data.Maybe.HT (toMaybe) -offset, uncheckedOffset :: Ord a => Set a -> a -> Int-offset = flip Set.findIndex-uncheckedOffset = offset+offset :: Ord a => Set a -> a -> Maybe Int+offset = flip Set.lookupIndex -indexFromOffset, uncheckedIndexFromOffset :: Set a -> Int -> a-indexFromOffset = flip Set.elemAt-uncheckedIndexFromOffset = indexFromOffset+uncheckedOffset :: Ord a => Set a -> a -> Int+uncheckedOffset = flip Set.findIndex+++indexFromOffset :: Set a -> Int -> Maybe a+indexFromOffset set k =+ toMaybe (0<=k && k<Set.size set) (Set.elemAt k set)++uncheckedIndexFromOffset :: Set a -> Int -> a+uncheckedIndexFromOffset = flip Set.elemAt
src/Data/Array/Comfort/Boxed.hs view
@@ -3,7 +3,7 @@ shape, reshape, mapShape,- (!),+ accessMaybe, (!), Array.toList, Array.fromList, Array.vectorFromList,@@ -40,6 +40,8 @@ import Data.Map (Map) import Data.Set (Set) import Data.Foldable (forM_)+import Data.Either.HT (maybeRight)+import Data.Maybe (fromMaybe) import Prelude hiding (zipWith, replicate) @@ -74,10 +76,14 @@ infixl 9 ! (!) :: (Shape.Indexed sh) => Array sh a -> Shape.Index sh -> a-(!) (Array sh arr) ix =- if Shape.inBounds sh ix- then Prim.indexArray arr $ Shape.offset sh ix- else error "Array.Comfort.Boxed.!: index out of bounds"+(!) arr ix =+ fromMaybe (error "Array.Comfort.Boxed.!: index out of bounds") $+ accessMaybe arr ix++accessMaybe :: (Shape.Indexed sh) => Array sh a -> Shape.Index sh -> Maybe a+accessMaybe (Array sh arr) ix =+ fmap (Prim.indexArray arr) $ maybeRight $+ Shape.getChecked $ Shape.unifiedOffset sh ix zipWith ::
+ src/Data/Array/Comfort/Boxed/Strict/Unchecked.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE TypeFamilies #-}+module Data.Array.Comfort.Boxed.Strict.Unchecked where++import qualified Data.Array.Comfort.Shape as Shape+import Data.Array.Comfort.Boxed.Unchecked (Array(Array))++import qualified Data.Primitive.Array as Prim++import qualified Control.Monad.ST.Strict as STStrict+import qualified Control.Monad.Trans.Class as MT+import qualified Control.Monad.Trans.State as MS++import Prelude hiding (map, zipWith)+++toList :: (Shape.C sh) => Array sh a -> [a]+toList (Array sh arr) =+ STStrict.runST (mapM (Prim.indexArrayM arr) $ take (Shape.size sh) [0..])++map :: (Shape.C sh) => (a -> b) -> Array sh a -> Array sh b+map f (Array sh arr) = Array sh $ Prim.mapArray' f arr++zipWith ::+ (Shape.C sh) => (a -> b -> c) -> Array sh a -> Array sh b -> Array sh c+zipWith f (Array sha arra) (Array _shb arrb) =+ Array sha $+ STStrict.runST+ (flip MS.evalStateT 0 $+ Prim.traverseArrayP+ (\a -> do+ k <- MS.get+ b <- MT.lift $ Prim.indexArrayM arrb k+ MS.put (k+1)+ return $ f a b)+ arra)
src/Data/Array/Comfort/Boxed/Unchecked.hs view
@@ -1,12 +1,23 @@ {-# LANGUAGE TypeFamilies #-}-module Data.Array.Comfort.Boxed.Unchecked where+module Data.Array.Comfort.Boxed.Unchecked (+ Array(..),+ reshape,+ mapShape,+ (!),+ toList,+ fromList,+ vectorFromList,+ replicate,+ map,+ zipWith,+ ) where import qualified Data.Array.Comfort.Shape as Shape import qualified Data.Primitive.Array as Prim -import qualified Control.Monad.ST.Strict as STStrict-import qualified Control.Monad.Trans.Class as MT-import qualified Control.Monad.Trans.State as MS+-- FixMe: In GHC-7.4.2 there is no instance PrimMonad (Lazy.ST s)+-- import qualified Control.Monad.ST.Lazy as ST+import qualified Control.Monad.ST.Strict as ST import Control.Monad (liftM) import Control.Applicative (Applicative, pure, (<*>), (<$>)) import Control.DeepSeq (NFData, rnf)@@ -29,11 +40,11 @@ showString "BoxedArray.fromList " . showsPrec 11 (shape arr) . showChar ' ' .- shows (toListLazy arr)+ shows (toList arr) instance (Shape.C sh, NFData sh, NFData a) => NFData (Array sh a) where- rnf a@(Array sh _arr) = rnf (sh, toListLazy a)+ rnf a@(Array sh _arr) = rnf (sh, toList a) instance (Shape.C sh) => Functor (Array sh) where fmap = map@@ -61,7 +72,6 @@ sequence (Array sh arr) = liftM (Array sh) $ Trav.sequence arr --- add assertion, at least in an exposed version reshape :: sh1 -> Array sh0 a -> Array sh1 a reshape sh (Array _ arr) = Array sh arr @@ -74,13 +84,9 @@ (!) :: (Shape.Indexed sh) => Array sh a -> Shape.Index sh -> a (!) (Array sh arr) ix = Prim.indexArray arr $ Shape.uncheckedOffset sh ix -toListLazy :: (Shape.C sh) => Array sh a -> [a]-toListLazy (Array sh arr) =- List.map (Prim.indexArray arr) $ take (Shape.size sh) [0..]- toList :: (Shape.C sh) => Array sh a -> [a] toList (Array sh arr) =- STStrict.runST (mapM (Prim.indexArrayM arr) $ take (Shape.size sh) [0..])+ List.map (Prim.indexArray arr) $ take (Shape.size sh) [0..] fromList :: (Shape.C sh) => sh -> [a] -> Array sh a fromList sh xs = Array sh $ Prim.fromListN (Shape.size sh) xs@@ -93,21 +99,17 @@ replicate :: (Shape.C sh) => sh -> a -> Array sh a replicate sh a = Array sh $- STStrict.runST (Prim.unsafeFreezeArray =<< Prim.newArray (Shape.size sh) a)+ ST.runST (Prim.unsafeFreezeArray =<< Prim.newArray (Shape.size sh) a) map :: (Shape.C sh) => (a -> b) -> Array sh a -> Array sh b-map f (Array sh arr) = Array sh $ Prim.mapArray' f arr+map f (Array sh arr) = Array sh $+ let n = Shape.size sh+ in Prim.fromListN n $ List.map (f . Prim.indexArray arr) $ take n [0..] zipWith :: (Shape.C sh) => (a -> b -> c) -> Array sh a -> Array sh b -> Array sh c-zipWith f (Array sha arra) (Array _shb arrb) =- Array sha $- STStrict.runST- (flip MS.evalStateT 0 $- Prim.traverseArrayP- (\a -> do- k <- MS.get- b <- MT.lift $ Prim.indexArrayM arrb k- MS.put (k+1)- return $ f a b)- arra)+zipWith f (Array sha arra) (Array _shb arrb) = Array sha $+ let n = Shape.size sha+ in Prim.fromListN n $+ List.map (\k -> f (Prim.indexArray arra k) (Prim.indexArray arrb k)) $+ take n [0..]
src/Data/Array/Comfort/Container.hs view
@@ -49,7 +49,6 @@ instance (C f) => Shape.C (Shape f) where size = shapeSize- uncheckedSize = shapeSize instance C [] where
src/Data/Array/Comfort/Shape.hs view
@@ -1,11 +1,22 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-}+{-# LANGUAGE EmptyDataDecls #-}+{-# LANGUAGE GADTs #-} module Data.Array.Comfort.Shape ( C(..), Indexed(..),- InvIndexed(..),+ InvIndexed(..), messageIndexFromOffset, assertIndexFromOffset, Static(..), + requireCheck,+ CheckSingleton(..),+ Checking(..),+ Result(..),+ runChecked,+ runUnchecked,+ assert,+ throwOrError,+ Zero(Zero), ZeroBased(..), zeroBasedSplit, OneBased(..),@@ -15,7 +26,7 @@ Enumeration(..), Deferred(..), DeferredIndex(..), deferIndex, revealIndex, - (:+:)(..),+ (::+)(..), Square(..), Cube(..),@@ -25,11 +36,23 @@ lowerTriangular, upperTriangular, triangleSize, triangleRoot, + Simplex(..),+ SimplexAscending, simplexAscending,+ SimplexDescending, simplexDescending,+ Ascending,+ Descending,+ SimplexOrder(..),+ SimplexOrderC,+ AllDistinct(..),+ SomeRepetitive(..),+ Collision(..),+ CollisionC,+ Cyclic(..), ) where import qualified Data.Array.Comfort.Shape.Set as ShapeSet-import Data.Array.Comfort.Shape.Utility (errorIndexFromOffset)+import Data.Array.Comfort.Shape.Utility (messageIndexFromOffset, isRight) import qualified Foreign.Storable.Newtype as Store import Foreign.Storable@@ -40,25 +63,32 @@ import qualified Control.Monad.Trans.State as MS import qualified Control.Monad.HT as Monad+import qualified Control.Applicative.HT as AppHT import qualified Control.Applicative.Backwards as Back import Control.DeepSeq (NFData, rnf)-import Control.Applicative (Applicative, pure, liftA2, liftA3, (<*>))+import Control.Monad (liftM)+import Control.Applicative (Applicative, pure, liftA2, liftA3, (<*>), (<$>)) import Control.Applicative (Const(Const, getConst))+import Control.Functor.HT (void) +import qualified Data.Functor.Classes as FunctorC import qualified Data.Traversable as Trav import qualified Data.Foldable as Fold import qualified Data.Map as Map import qualified Data.Set as Set import qualified Data.NonEmpty as NonEmpty+import qualified Data.List.Match as Match+import qualified Data.List.HT as ListHT import qualified Data.List as List+import Data.Traversable (Traversable)+import Data.Foldable (Foldable) import Data.Functor.Identity (Identity(Identity), runIdentity) import Data.Function.HT (compose2) import Data.Tagged (Tagged(Tagged, unTagged)) import Data.Map (Map) import Data.Set (Set) import Data.List.HT (tails)-import Data.Maybe (fromMaybe)-import Data.Tuple.HT (mapSnd, mapPair, swap, fst3, snd3, thd3)+import Data.Tuple.HT (mapFst, mapSnd, swap, fst3, snd3, thd3) import Data.Eq.HT (equating) @@ -66,45 +96,153 @@ >>> import qualified Data.Array.Comfort.Shape as Shape >>> import qualified Data.Map as Map >>> import qualified Data.Set as Set->>> import Data.Array.Comfort.Shape ((:+:)((:+:)))+>>> import Data.Array.Comfort.Shape ((::+)((::+))) -} +data Checked+data Unchecked++class Checking check where+ data Result check a+ switchCheck :: f Checked -> f Unchecked -> f check++data CheckSingleton check where+ Checked :: CheckSingleton Checked+ Unchecked :: CheckSingleton Unchecked++autoCheck :: (Checking check) => CheckSingleton check+autoCheck = switchCheck Checked Unchecked++checkFromResult :: (Checking check) => Result check a -> CheckSingleton check+checkFromResult _ = autoCheck++withCheck ::+ (Checking check) =>+ (CheckSingleton check -> Result check a) -> Result check a+withCheck f = f autoCheck++requireCheck :: CheckSingleton check -> Result check a -> Result check a+requireCheck _ = id+++instance Checking Checked where+ newtype Result Checked a = CheckedResult {getChecked :: Either String a}+ switchCheck f _ = f++runChecked :: String -> Result Checked a -> a+runChecked name (CheckedResult m) =+ either (error . (("Shape." ++ name ++ ": ") ++)) id m++instance Checking Unchecked where+ newtype Result Unchecked a = UncheckedResult {getUnchecked :: a}+ switchCheck _ f = f++runUnchecked :: Result Unchecked a -> a+runUnchecked = getUnchecked+++throw :: String -> Result Checked a+throw = CheckedResult . Left++throwOrError :: (Checking check) => String -> Result check a+throwOrError msg = withCheck $ \check ->+ case check of+ Checked -> throw msg+ Unchecked -> error msg++assert :: (Checking check) => String -> Bool -> Result check ()+assert msg cond = withCheck $ \check ->+ case check of+ Unchecked -> UncheckedResult ()+ Checked -> if cond then pure () else throw msg+++instance (Checking check, Eq a) => Eq (Result check a) where+ a0 == b0 =+ case (checkFromResult a0, a0, b0) of+ (Checked, CheckedResult a, CheckedResult b) -> a==b+ (Unchecked, UncheckedResult a, UncheckedResult b) -> a==b++instance (Checking check) => Functor (Result check) where+ fmap f m =+ case (checkFromResult m, m) of+ (Checked, CheckedResult e) -> CheckedResult $ fmap f e+ (Unchecked, UncheckedResult a) -> UncheckedResult $ f a++instance (Checking check) => Applicative (Result check) where+ pure a = withCheck $ \check ->+ case check of+ Checked -> CheckedResult $ Right a+ Unchecked -> UncheckedResult a+ f<*>a =+ case (checkFromResult a, f, a) of+ (Checked, CheckedResult ff, CheckedResult fa) ->+ CheckedResult $ ff<*>fa+ (Unchecked, UncheckedResult xf, UncheckedResult xa) ->+ UncheckedResult $ xf xa++instance (Checking check) => Monad (Result check) where+ return = pure+ a >>= b =+ case (checkFromResult a, a) of+ (Checked, CheckedResult e) -> CheckedResult $ getChecked . b =<< e+ (Unchecked, UncheckedResult x) -> b x++ class C sh where- -- Ix.rangeSize+ {-+ This is the counterpart to 'Ix.rangeSize'.+ We do not support a counterpart to 'Ix.unsafeRangeSize' anymore.+ First, there is hardly any speed advantage+ of using 'Ix.unsafeRangeSize' instead of 'Ix.rangeSize'.+ Second, I do not know of an 'Ix' instance+ where 'Ix.rangeSize' and 'Ix.unsafeRangeSize' differ.+ -} size :: sh -> Int- -- Ix.unsafeRangeSize- uncheckedSize :: sh -> Int- uncheckedSize = size class C sh => Indexed sh where- {-# MINIMAL indices, (sizeOffset|offset), inBounds #-}- type Index sh :: *+ {-# MINIMAL indices, (unifiedOffset|unifiedSizeOffset) #-}+ type Index sh -- Ix.range indices :: sh -> [Index sh] -- Ix.index offset :: sh -> Index sh -> Int- offset sh = snd $ sizeOffset sh+ offset sh = runChecked "offset" . unifiedOffset sh -- Ix.unsafeIndex uncheckedOffset :: sh -> Index sh -> Int- uncheckedOffset = offset+ uncheckedOffset sh = getUnchecked . unifiedOffset sh+ unifiedOffset :: (Checking check) => sh -> Index sh -> Result check Int+ unifiedOffset sh = snd $ unifiedSizeOffset sh -- Ix.inRange inBounds :: sh -> Index sh -> Bool+ inBounds sh = isRight . getChecked . unifiedOffset sh sizeOffset :: sh -> (Int, Index sh -> Int) sizeOffset sh = (size sh, offset sh) uncheckedSizeOffset :: sh -> (Int, Index sh -> Int)- uncheckedSizeOffset sh = (uncheckedSize sh, uncheckedOffset sh)+ uncheckedSizeOffset sh = (size sh, uncheckedOffset sh)+ unifiedSizeOffset ::+ (Checking check) => sh -> (Int, Index sh -> Result check Int)+ unifiedSizeOffset sh = (size sh, unifiedOffset sh) class Indexed sh => InvIndexed sh where+ {-# MINIMAL unifiedIndexFromOffset #-} {- | It should hold @indexFromOffset sh k == indices sh !! k@, but 'indexFromOffset' should generally be faster. -} indexFromOffset :: sh -> Int -> Index sh+ indexFromOffset sh = runChecked "indexFromOffset" . unifiedIndexFromOffset sh uncheckedIndexFromOffset :: sh -> Int -> Index sh- uncheckedIndexFromOffset = indexFromOffset+ uncheckedIndexFromOffset sh = getUnchecked . unifiedIndexFromOffset sh+ unifiedIndexFromOffset ::+ (Checking check) => sh -> Int -> Result check (Index sh) +assertIndexFromOffset ::+ (Checking check) => String -> Int -> Bool -> Result check ()+assertIndexFromOffset name k cond = assert (messageIndexFromOffset name k) cond+ class (C sh, Eq sh) => Static sh where static :: sh @@ -114,7 +252,6 @@ instance C Zero where size Zero = 0- uncheckedSize Zero = 0 instance Static Zero where static = Zero@@ -122,7 +259,6 @@ instance C () where size () = 1- uncheckedSize () = 1 {- | >>> Shape.indices ()@@ -131,14 +267,11 @@ instance Indexed () where type Index () = () indices () = [()]- offset () () = 0- uncheckedOffset () () = 0+ unifiedOffset () () = pure 0 inBounds () () = True instance InvIndexed () where- indexFromOffset () 0 = ()- indexFromOffset () k = errorIndexFromOffset "()" k- uncheckedIndexFromOffset () _ = ()+ unifiedIndexFromOffset () k = assertIndexFromOffset "()" k (k==0) instance Static () where static = ()@@ -171,28 +304,24 @@ instance (Integral n) => C (ZeroBased n) where size (ZeroBased len) = fromIntegral len- uncheckedSize (ZeroBased len) = fromIntegral len instance (Integral n) => Indexed (ZeroBased n) where type Index (ZeroBased n) = n indices (ZeroBased len) = indices $ Shifted 0 len- offset (ZeroBased len) = offset $ Shifted 0 len- uncheckedOffset _ ix = fromIntegral ix+ unifiedOffset (ZeroBased len) = unifiedOffset $ Shifted 0 len inBounds (ZeroBased len) ix = 0<=ix && ix<len instance (Integral n) => InvIndexed (ZeroBased n) where- indexFromOffset (ZeroBased len) k0 =+ unifiedIndexFromOffset (ZeroBased len) k0 = do let k = fromIntegral k0- in if 0<=k && k<len- then k- else errorIndexFromOffset "ZeroBased" k0- uncheckedIndexFromOffset _ k = fromIntegral k+ assertIndexFromOffset "ZeroBased" k0 $ 0<=k && k<len+ pure k -zeroBasedSplit :: (Real n) => n -> ZeroBased n -> ZeroBased n :+: ZeroBased n+zeroBasedSplit :: (Real n) => n -> ZeroBased n -> ZeroBased n ::+ ZeroBased n zeroBasedSplit n (ZeroBased m) = if n<0 then error "Shape.zeroBasedSplit: negative number of elements"- else let k = min n m in ZeroBased k :+: ZeroBased (m-k)+ else let k = min n m in ZeroBased k ::+ ZeroBased (m-k) {- |@@ -222,22 +351,18 @@ instance (Integral n) => C (OneBased n) where size (OneBased len) = fromIntegral len- uncheckedSize (OneBased len) = fromIntegral len instance (Integral n) => Indexed (OneBased n) where type Index (OneBased n) = n indices (OneBased len) = indices $ Shifted 1 len- offset (OneBased len) = offset $ Shifted 1 len- uncheckedOffset _ ix = fromIntegral ix - 1+ unifiedOffset (OneBased len) = unifiedOffset $ Shifted 1 len inBounds (OneBased len) ix = 0<ix && ix<=len instance (Integral n) => InvIndexed (OneBased n) where- indexFromOffset (OneBased len) k0 =+ unifiedIndexFromOffset (OneBased len) k0 = do let k = fromIntegral k0- in if 0<=k && k<len- then 1+k- else errorIndexFromOffset "OneBased" k0- uncheckedIndexFromOffset _ k = 1 + fromIntegral k+ assertIndexFromOffset "OneBased" k0 $ 0<=k && k<len+ pure $ 1+k {- |@@ -262,22 +387,22 @@ instance (Ix.Ix n) => C (Range n) where size (Range from to) = Ix.rangeSize (from,to)- uncheckedSize (Range from to) = Ix.unsafeRangeSize (from,to) instance (Ix.Ix n) => Indexed (Range n) where type Index (Range n) = n indices (Range from to) = Ix.range (from,to) offset (Range from to) ix = Ix.index (from,to) ix uncheckedOffset (Range from to) ix = Ix.unsafeIndex (from,to) ix+ unifiedOffset (Range from to) ix = do+ assert "Shape.Range: index out of range" $ Ix.inRange (from,to) ix+ return $ Ix.unsafeIndex (from,to) ix inBounds (Range from to) ix = Ix.inRange (from,to) ix -- pretty inefficient when we rely solely on Ix instance (Ix.Ix n) => InvIndexed (Range n) where- indexFromOffset (Range from to) k =- if 0<=k && k < Ix.rangeSize (from,to)- then Ix.range (from,to) !! k- else errorIndexFromOffset "Range" k- uncheckedIndexFromOffset (Range from to) k = Ix.range (from,to) !! k+ unifiedIndexFromOffset (Range from to) k = do+ assertIndexFromOffset "Range" k $ 0<=k && k < Ix.rangeSize (from,to)+ return $ Ix.range (from,to) !! k -- cf. sample-frame:Stereo instance Storable n => Storable (Range n) where@@ -312,7 +437,6 @@ instance (Integral n) => C (Shifted n) where size (Shifted _offs len) = fromIntegral len- uncheckedSize (Shifted _offs len) = fromIntegral len instance (Integral n) => Indexed (Shifted n) where type Index (Shifted n) = n@@ -322,24 +446,18 @@ zip (iterate (subtract 1) len) (iterate (1+) offs)- offset (Shifted offs len) ix =- if ix<offs- then error "Shape.Shifted: array index too small"- else- let k = ix-offs- in if k<len- then fromIntegral k- else error "Shape.Shifted: array index too big"- uncheckedOffset (Shifted offs _len) ix = fromIntegral $ ix-offs+ unifiedOffset (Shifted offs len) ix = do+ assert "Shape.Shifted: array index too small" $ ix>=offs+ let k = ix-offs+ assert "Shape.Shifted: array index too big" $ k<len+ return $ fromIntegral k inBounds (Shifted offs len) ix = offs <= ix && ix < offs+len instance (Integral n) => InvIndexed (Shifted n) where- indexFromOffset (Shifted offs len) k0 =+ unifiedIndexFromOffset (Shifted offs len) k0 = do let k = fromIntegral k0- in if 0<=k && k<len- then offs+k- else errorIndexFromOffset "Shifted" k0- uncheckedIndexFromOffset (Shifted offs _len) k = offs + fromIntegral k+ assertIndexFromOffset "Shifted" k0 $ 0<=k && k<len+ return $ offs+k -- cf. sample-frame:Stereo instance Storable n => Storable (Shifted n) where@@ -380,22 +498,20 @@ rnf Enumeration = () instance (Enum n, Bounded n) => C (Enumeration n) where- size = uncheckedSize- uncheckedSize sh = intFromEnum sh maxBound - intFromEnum sh minBound + 1+ size sh = intFromEnum sh maxBound - intFromEnum sh minBound + 1 instance (Enum n, Bounded n) => Indexed (Enumeration n) where type Index (Enumeration n) = n indices sh = [asEnumType sh minBound .. asEnumType sh maxBound]- offset = uncheckedOffset- uncheckedOffset sh ix = fromEnum ix - intFromEnum sh minBound+ unifiedOffset sh ix = pure $ fromEnum ix - intFromEnum sh minBound inBounds _sh _ix = True instance (Enum n, Bounded n) => InvIndexed (Enumeration n) where- indexFromOffset sh k =- if 0<=k && k <= intFromEnum sh maxBound - intFromEnum sh minBound- then uncheckedIndexFromOffset sh k- else errorIndexFromOffset "Enumeration" k- uncheckedIndexFromOffset sh k = toEnum $ intFromEnum sh minBound + k+ unifiedIndexFromOffset sh k = do+ let minBnd = intFromEnum sh minBound+ assertIndexFromOffset "Enumeration" k $+ 0<=k && k <= intFromEnum sh maxBound - minBnd+ return $ toEnum $ minBnd + k asEnumType :: Enumeration n -> n -> n asEnumType Enumeration = id@@ -418,26 +534,41 @@ instance (Ord n) => C (Set n) where- size = uncheckedSize- uncheckedSize = Set.size+ size = Set.size {- | You can use an arbitrary 'Set' of indices as shape. The array elements are ordered according to the index order in the 'Set'. +Disadvantage is that combinators of different Set indexed arrays+have to compare whole sets.+However, the Set implementation may have low-level optimizations+for pointer equality.+ >>> Shape.indices (Set.fromList "comfort") "cfmort" -} instance (Ord n) => Indexed (Set n) where type Index (Set n) = n indices = Set.toAscList- offset = ShapeSet.offset- uncheckedOffset = ShapeSet.uncheckedOffset+ unifiedOffset sh ix = withCheck $ \check ->+ case check of+ Unchecked -> pure $ ShapeSet.uncheckedOffset sh ix+ Checked ->+ case ShapeSet.offset sh ix of+ Just k -> pure k+ Nothing ->+ throw "Shape.Set: array index not member of the index set" inBounds = flip Set.member instance (Ord n) => InvIndexed (Set n) where- indexFromOffset = ShapeSet.indexFromOffset- uncheckedIndexFromOffset = ShapeSet.uncheckedIndexFromOffset+ unifiedIndexFromOffset sh k = withCheck $ \check ->+ case check of+ Unchecked -> pure $ ShapeSet.uncheckedIndexFromOffset sh k+ Checked ->+ case ShapeSet.indexFromOffset sh k of+ Just ix -> pure ix+ Nothing -> throw $ messageIndexFromOffset "Set" k {- |@@ -445,7 +576,6 @@ -} instance (Ord k, C shape) => C (Map k shape) where size = Fold.sum . Map.map size- uncheckedSize = Fold.sum . Map.map uncheckedSize {- | The implementations of 'offset' et.al.@@ -458,54 +588,45 @@ type Index (Map k shape) = (k, Index shape) indices = Fold.fold . Map.mapWithKey (\k shape -> map ((,) k) $ indices shape)- offset m =- let mu = snd $ Trav.mapAccumL (\l sh -> (l + size sh, (l,sh))) 0 m- in \(k,ix) ->- case Map.lookup k mu of- Nothing -> error "Shape.Map.offset: unknown key"- Just (l,sh) -> l + offset sh ix- uncheckedOffset m =- let mu =- snd $ Trav.mapAccumL (\l sh -> (l + uncheckedSize sh, (l,sh))) 0 m+ unifiedOffset m =+ let ms = fmap unifiedSizeOffset m+ mu = snd $+ Trav.mapAccumL (\l (sz,getOffset) -> (l + sz, (l,getOffset))) 0 ms in \(k,ix) -> case Map.lookup k mu of- Nothing -> error "Shape.Map.uncheckedOffset: unknown key"- Just (l,sh) -> l + uncheckedOffset sh ix+ Nothing -> throwOrError "Shape.Map.offset: unknown key"+ Just (l,getOffset) -> (l+) <$> getOffset ix inBounds m (k,ix) = Fold.any (flip inBounds ix) $ Map.lookup k m - sizeOffset = mapSizeOffset . Map.map sizeOffset- uncheckedSizeOffset = mapSizeOffset . Map.map uncheckedSizeOffset+ unifiedSizeOffset = mapSizeOffset . fmap unifiedSizeOffset {-# INLINE mapSizeOffset #-}-mapSizeOffset :: (Ord k, Num i) => Map k (i, ix -> i) -> (i, (k, ix) -> i)+mapSizeOffset ::+ (Checking check, Ord k, Num i) =>+ Map k (i, ix -> Result check i) -> (i, (k, ix) -> Result check i) mapSizeOffset ms = (Fold.sum $ Map.map fst ms,- let mu = snd $ Trav.mapAccumL (\l (sz,offs) -> (l + sz, (l+) . offs)) 0 ms+ let mu = snd $+ Trav.mapAccumL (\l (sz,offs) -> (l + sz, fmap (l+) . offs)) 0 ms in \(k,ix) ->- fromMaybe (error "Shape.Map.sizeOffset: unknown key")- (Map.lookup k mu) ix)+ maybe+ (throwOrError "Shape.Map.sizeOffset: unknown key")+ ($ix)+ (Map.lookup k mu)) instance (Ord k, InvIndexed shape) => InvIndexed (Map k shape) where- indexFromOffset m i =+ unifiedIndexFromOffset m i = (\xs -> case xs of (_u,ix):_ -> ix- [] -> errorIndexFromOffset "Map" i) $+ [] -> throwOrError $ messageIndexFromOffset "Map" i) $ dropWhile (\(u,_ix) -> u<=i) $ snd $ List.mapAccumL (\l (k,sh) -> let u = l + size sh- in (u, (u, (k, indexFromOffset sh (i-l))))) 0 $+ in (u, (u, (,) k <$> unifiedIndexFromOffset sh (i-l)))) 0 $ Map.toAscList m - uncheckedIndexFromOffset m i =- (\((_u,ix):_) -> ix) $- dropWhile (\(u,_ix) -> u<=i) $ snd $- List.mapAccumL- (\l (k,sh) ->- let u = l + size sh- in (u, (u, (k, uncheckedIndexFromOffset sh (i-l))))) 0 $- Map.toAscList m {- |@@ -554,19 +675,17 @@ instance (C sh) => C (Deferred sh) where size (Deferred sh) = size sh- uncheckedSize (Deferred sh) = uncheckedSize sh instance (C sh) => Indexed (Deferred sh) where type Index (Deferred sh) = DeferredIndex sh indices (Deferred sh) = map DeferredIndex $ take (size sh) [0 ..]- offset (Deferred sh) (DeferredIndex k) = offset (ZeroBased $ size sh) k- uncheckedOffset _ (DeferredIndex k) = k- sizeOffset (Deferred sh) =+ unifiedOffset (Deferred sh) (DeferredIndex k) = withCheck $ \check ->+ case check of+ Checked -> unifiedOffset (ZeroBased $ size sh) k+ Unchecked -> pure k+ unifiedSizeOffset (Deferred sh) = mapSnd (\offs (DeferredIndex k) -> offs k) $- sizeOffset (ZeroBased $ size sh)- uncheckedSizeOffset (Deferred sh) =- mapSnd (\ _offs (DeferredIndex k) -> k) $- uncheckedSizeOffset (ZeroBased $ size sh)+ unifiedSizeOffset (ZeroBased $ size sh) inBounds (Deferred sh) (DeferredIndex k) = inBounds (ZeroBased $ size sh) k @@ -574,6 +693,11 @@ indexFromOffset (Deferred sh) k = DeferredIndex $ indexFromOffset (ZeroBased $ size sh) k uncheckedIndexFromOffset _sh = DeferredIndex+ unifiedIndexFromOffset (Deferred sh) k = withCheck $ \check ->+ case check of+ Unchecked -> pure $ DeferredIndex k+ Checked ->+ DeferredIndex <$> unifiedIndexFromOffset (ZeroBased $ size sh) k deferIndex :: (Indexed sh, Index sh ~ ix) => sh -> ix -> DeferredIndex sh deferIndex sh ix = DeferredIndex $ offset sh ix@@ -598,22 +722,18 @@ instance (C sh) => C (Tagged s sh) where size (Tagged sh) = size sh- uncheckedSize (Tagged sh) = uncheckedSize sh instance (Indexed sh) => Indexed (Tagged s sh) where type Index (Tagged s sh) = Tagged s (Index sh) indices (Tagged sh) = map Tagged $ indices sh- offset (Tagged sh) (Tagged k) = offset sh k- uncheckedOffset (Tagged sh) (Tagged k) = uncheckedOffset sh k- sizeOffset (Tagged sh) = mapSnd (. unTagged) $ sizeOffset sh- uncheckedSizeOffset (Tagged sh) =- mapSnd (. unTagged) $ uncheckedSizeOffset sh+ unifiedOffset (Tagged sh) = unifiedOffset sh . unTagged+ unifiedSizeOffset (Tagged sh) =+ mapSnd (. unTagged) $ unifiedSizeOffset sh inBounds (Tagged sh) (Tagged k) = inBounds sh k instance (InvIndexed sh) => InvIndexed (Tagged s sh) where- indexFromOffset (Tagged sh) k = Tagged $ indexFromOffset sh k- uncheckedIndexFromOffset (Tagged sh) k =- Tagged $ uncheckedIndexFromOffset sh k+ unifiedIndexFromOffset (Tagged sh) k =+ Tagged <$> unifiedIndexFromOffset sh k instance (Static sh) => Static (Tagged s sh) where static = Tagged static@@ -622,7 +742,6 @@ instance (C sh0, C sh1) => C (sh0,sh1) where size (sh0,sh1) = size sh0 * size sh1- uncheckedSize (sh0,sh1) = uncheckedSize sh0 * uncheckedSize sh1 {- | Row-major composition of two dimensions.@@ -633,29 +752,22 @@ instance (Indexed sh0, Indexed sh1) => Indexed (sh0,sh1) where type Index (sh0,sh1) = (Index sh0, Index sh1) indices (sh0,sh1) = Monad.lift2 (,) (indices sh0) (indices sh1)- offset (sh0,sh1) =- offset sh0 . fst- `combineOffset`- mapSnd (.snd) (sizeOffset sh1)- uncheckedOffset (sh0,sh1) =- uncheckedOffset sh0 . fst+ unifiedOffset (sh0,sh1) =+ (unifiedOffset sh0 . fst) `combineOffset`- mapSnd (.snd) (uncheckedSizeOffset sh1)- sizeOffset (sh0,sh1) =- mapSnd (.fst) (sizeOffset sh0)- `combineSizeOffset`- mapSnd (.snd) (sizeOffset sh1)- uncheckedSizeOffset (sh0,sh1) =- mapSnd (.fst) (uncheckedSizeOffset sh0)+ (mapSnd (.snd) $ unifiedSizeOffset sh1)+ unifiedSizeOffset (sh0,sh1) =+ (mapSnd (.fst) $ unifiedSizeOffset sh0) `combineSizeOffset`- mapSnd (.snd) (uncheckedSizeOffset sh1)+ (mapSnd (.snd) $ unifiedSizeOffset sh1) inBounds (sh0,sh1) (ix0,ix1) = inBounds sh0 ix0 && inBounds sh1 ix1 instance (InvIndexed sh0, InvIndexed sh1) => InvIndexed (sh0,sh1) where- indexFromOffset (sh0,sh1) k =- runInvIndex k $ liftA2 (,) (pickLastIndex sh0) (pickIndex sh1)- uncheckedIndexFromOffset (sh0,sh1) k =- runInvIndex k $ liftA2 (,) (uncheckedPickLastIndex sh0) (pickIndex sh1)+ unifiedIndexFromOffset (sh0,sh1) k = do+ let (rix0,ix1) =+ runInvIndex k $ liftA2 (,) (pickLastIndex sh0) (pickIndex sh1)+ ix0 <- rix0+ return (ix0,ix1) instance (Static sh0, Static sh1) => Static (sh0,sh1) where static = (static, static)@@ -663,43 +775,35 @@ instance (C sh0, C sh1, C sh2) => C (sh0,sh1,sh2) where size (sh0,sh1,sh2) = size sh0 * size sh1 * size sh2- uncheckedSize (sh0,sh1,sh2) =- uncheckedSize sh0 * uncheckedSize sh1 * uncheckedSize sh2 instance (Indexed sh0, Indexed sh1, Indexed sh2) => Indexed (sh0,sh1,sh2) where type Index (sh0,sh1,sh2) = (Index sh0, Index sh1, Index sh2) indices (sh0,sh1,sh2) = Monad.lift3 (,,) (indices sh0) (indices sh1) (indices sh2)- uncheckedOffset (sh0,sh1,sh2) =- uncheckedOffset sh0 . fst3+ unifiedOffset (sh0,sh1,sh2) =+ (unifiedOffset sh0 . fst3) `combineOffset`- mapSnd (.snd3) (uncheckedSizeOffset sh1)- `combineSizeOffset`- mapSnd (.thd3) (uncheckedSizeOffset sh2)- sizeOffset (sh0,sh1,sh2) =- mapSnd (.fst3) (sizeOffset sh0)- `combineSizeOffset`- mapSnd (.snd3) (sizeOffset sh1)+ (mapSnd (.snd3) $ unifiedSizeOffset sh1) `combineSizeOffset`- mapSnd (.thd3) (sizeOffset sh2)- uncheckedSizeOffset (sh0,sh1,sh2) =- mapSnd (.fst3) (uncheckedSizeOffset sh0)+ (mapSnd (.thd3) $ unifiedSizeOffset sh2)+ unifiedSizeOffset (sh0,sh1,sh2) =+ (mapSnd (.fst3) $ unifiedSizeOffset sh0) `combineSizeOffset`- mapSnd (.snd3) (uncheckedSizeOffset sh1)+ (mapSnd (.snd3) $ unifiedSizeOffset sh1) `combineSizeOffset`- mapSnd (.thd3) (uncheckedSizeOffset sh2)+ (mapSnd (.thd3) $ unifiedSizeOffset sh2) inBounds (sh0,sh1,sh2) (ix0,ix1,ix2) = inBounds sh0 ix0 && inBounds sh1 ix1 && inBounds sh2 ix2 instance (InvIndexed sh0, InvIndexed sh1, InvIndexed sh2) => InvIndexed (sh0,sh1,sh2) where- indexFromOffset (sh0,sh1,sh2) k =- runInvIndex k $- liftA3 (,,) (pickLastIndex sh0) (pickIndex sh1) (pickIndex sh2)- uncheckedIndexFromOffset (sh0,sh1,sh2) k =- runInvIndex k $- liftA3 (,,) (uncheckedPickLastIndex sh0) (pickIndex sh1) (pickIndex sh2)+ unifiedIndexFromOffset (sh0,sh1,sh2) k = do+ let (rix0,ix1,ix2) =+ runInvIndex k $+ liftA3 (,,) (pickLastIndex sh0) (pickIndex sh1) (pickIndex sh2)+ ix0 <- rix0+ return (ix0,ix1,ix2) instance (Static sh0, Static sh1, Static sh2) => Static (sh0,sh1,sh2) where static = (static, static, static)@@ -708,14 +812,10 @@ runInvIndex k = flip MS.evalState k . Back.forwards pickLastIndex ::- (InvIndexed sh) => sh -> Back.Backwards (MS.State Int) (Index sh)+ (Checking check, InvIndexed sh) =>+ sh -> Back.Backwards (MS.State Int) (Result check (Index sh)) pickLastIndex sh =- Back.Backwards $ MS.gets $ indexFromOffset sh--uncheckedPickLastIndex ::- (InvIndexed sh) => sh -> Back.Backwards (MS.State Int) (Index sh)-uncheckedPickLastIndex sh =- Back.Backwards $ MS.gets $ uncheckedIndexFromOffset sh+ Back.Backwards $ MS.gets $ unifiedIndexFromOffset sh pickIndex :: (InvIndexed sh) => sh -> Back.Backwards (MS.State Int) (Index sh) pickIndex sh =@@ -727,13 +827,18 @@ infixr 7 `combineOffset`, `combineSizeOffset` {-# INLINE combineOffset #-}-combineOffset :: Num a => (ix -> a) -> (a, ix -> a) -> ix -> a-combineOffset offset0 (size1,offset1) ix = offset0 ix * size1 + offset1 ix+combineOffset ::+ (Applicative f, Num a) =>+ (ix -> f a) -> (a, ix -> f a) -> (ix -> f a)+combineOffset offset0 (size1,offset1) ix =+ offset0 ix |* size1 |+| offset1 ix {-# INLINE combineSizeOffset #-}-combineSizeOffset :: Num a => (a, ix -> a) -> (a, ix -> a) -> (a, ix -> a)+combineSizeOffset ::+ (Applicative f, Num a) =>+ (a, ix -> f a) -> (a, ix -> f a) -> (a, ix -> f a) combineSizeOffset (size0,offset0) (size1,offset1) =- (size0*size1, \ix -> offset0 ix * size1 + offset1 ix)+ (size0*size1, \ix -> offset0 ix |* size1 |+| offset1 ix) @@ -765,24 +870,18 @@ instance (C sh) => C (Square sh) where size (Square sh) = size sh ^ (2::Int)- uncheckedSize (Square sh) = uncheckedSize sh ^ (2::Int) instance (Indexed sh) => Indexed (Square sh) where type Index (Square sh) = (Index sh, Index sh) indices (Square sh) = indices (sh,sh)- offset (Square sh) = offset (sh,sh)- uncheckedOffset (Square sh) = uncheckedOffset (sh,sh)- sizeOffset (Square sh) =- let szo = sizeOffset sh- in mapSnd (.fst) szo `combineSizeOffset` mapSnd (.snd) szo- uncheckedSizeOffset (Square sh) =- let szo = uncheckedSizeOffset sh+ unifiedSizeOffset (Square sh) =+ let szo = unifiedSizeOffset sh in mapSnd (.fst) szo `combineSizeOffset` mapSnd (.snd) szo inBounds (Square sh) = inBounds (sh,sh) instance (InvIndexed sh) => InvIndexed (Square sh) where- indexFromOffset (Square sh) = indexFromOffset (sh,sh)- uncheckedIndexFromOffset (Square sh) = uncheckedIndexFromOffset (sh,sh)+ unifiedIndexFromOffset (Square sh) =+ unifiedIndexFromOffset (sh,sh) @@ -814,22 +913,12 @@ instance (C sh) => C (Cube sh) where size (Cube sh) = size sh ^ (3::Int)- uncheckedSize (Cube sh) = uncheckedSize sh ^ (3::Int) instance (Indexed sh) => Indexed (Cube sh) where type Index (Cube sh) = (Index sh, Index sh, Index sh) indices (Cube sh) = indices (sh,sh,sh)- offset (Cube sh) = offset (sh,sh,sh)- uncheckedOffset (Cube sh) = uncheckedOffset (sh,sh,sh)- sizeOffset (Cube sh) =- let szo = sizeOffset sh- in mapSnd (.fst3) szo- `combineSizeOffset`- mapSnd (.snd3) szo- `combineSizeOffset`- mapSnd (.thd3) szo- uncheckedSizeOffset (Cube sh) =- let szo = uncheckedSizeOffset sh+ unifiedSizeOffset (Cube sh) =+ let szo = unifiedSizeOffset sh in mapSnd (.fst3) szo `combineSizeOffset` mapSnd (.snd3) szo@@ -838,8 +927,8 @@ inBounds (Cube sh) = inBounds (sh,sh,sh) instance (InvIndexed sh) => InvIndexed (Cube sh) where- indexFromOffset (Cube sh) = indexFromOffset (sh,sh,sh)- uncheckedIndexFromOffset (Cube sh) = uncheckedIndexFromOffset (sh,sh,sh)+ unifiedIndexFromOffset (Cube sh) =+ unifiedIndexFromOffset (sh,sh,sh) @@ -900,7 +989,6 @@ instance (TriangularPart part, C size) => C (Triangular part size) where size (Triangular _part sz) = triangleSize $ size sz- uncheckedSize (Triangular _part sz) = triangleSize $ uncheckedSize sz instance (TriangularPart part, Indexed size) =>@@ -915,21 +1003,14 @@ (NonEmpty.tail $ NonEmpty.inits ixs) ixs) (zipWith (\r cs -> map ((,) r) cs) ixs $ tails ixs) - uncheckedOffset sh = snd $ uncheckedSizeOffset sh-- sizeOffset (Triangular part sz) =- let (n, getOffset) = sizeOffset sz- in (triangleSize n, \(rs,cs) ->- let r = getOffset rs- c = getOffset cs- in if compareIndices part r c- then triangleOffset part n (r,c)- else error "Shape.Triangular.sizeOffset: wrong array part")-- uncheckedSizeOffset (Triangular part sz) =- let (n, getOffset) = uncheckedSizeOffset sz- in (triangleSize n, \(rs,cs) ->- triangleOffset part n (getOffset rs, getOffset cs))+ unifiedSizeOffset (Triangular part sz) =+ let (n, getOffset) = unifiedSizeOffset sz+ in (triangleSize n, \(rs,cs) -> do+ r <- getOffset rs+ c <- getOffset cs+ assert "Shape.Triangular.sizeOffset: wrong array part" $+ compareIndices part r c+ return $ triangleOffset part n (r,c)) inBounds (Triangular part sz) ix@(r,c) = inBounds (sz,sz) ix@@ -950,13 +1031,13 @@ (TriangularPart part, InvIndexed size) => InvIndexed (Triangular part size) where - indexFromOffset (Triangular part sz) k =- mapPair (indexFromOffset sz, indexFromOffset sz) $- caseTriangularPart part+ unifiedIndexFromOffset (Triangular part sz) k =+ let n = size sz in+ AppHT.mapPair (unifiedIndexFromOffset sz, unifiedIndexFromOffset sz) $+ caseTriangularPart part (let r = floor (triangleRootDouble k) in (r, k - triangleSize r))- (let n = size sz- triSize = triangleSize n+ (let triSize = triangleSize n rr = ceiling (triangleRootDouble (triSize-k)) r = n - rr in (r, k+r - (triSize - triangleSize rr)))@@ -988,6 +1069,265 @@ {- |+Simplex is a generalization of 'Triangular' to more than two dimensions.+Indices are tuples of fixed size+with elements ordered in ascending, strictly ascending,+descending or strictly descending order.+\"Order\" refers to the index order in 'indices'.+In order to avoid confusion we suggest that the order of 'indices'+is consistent with '<='.++Obviously, 'offset' implements ranking+and 'indexFromOffset' implements unranking+of combinations (in the combinatorial sense)+with or without repetitions.++>>> Shape.indices $ Shape.simplexAscending (replicate 3 Shape.AllDistinct) $ Shape.ZeroBased (4::Int)+[[0,1,2],[0,1,3],[0,2,3],[1,2,3]]+>>> Shape.indices $ Shape.simplexAscending (replicate 3 Shape.SomeRepetitive) $ Shape.ZeroBased (3::Int)+[[0,0,0],[0,0,1],[0,0,2],[0,1,1],[0,1,2],[0,2,2],[1,1,1],[1,1,2],[1,2,2],[2,2,2]]+>>> Shape.indices $ Shape.simplexAscending [Shape.Repetitive,Shape.Distinct,Shape.Repetitive] $ Shape.ZeroBased (4::Int)+[[0,0,1],[0,0,2],[0,0,3],[0,1,2],[0,1,3],[0,2,3],[1,1,2],[1,1,3],[1,2,3],[2,2,3]]+>>> Shape.indices $ Shape.simplexAscending [Shape.Repetitive,Shape.Distinct,Shape.Distinct] $ Shape.ZeroBased (4::Int)+[[0,0,1],[0,0,2],[0,0,3],[0,1,2],[0,1,3],[0,2,3],[1,1,2],[1,1,3],[1,2,3],[2,2,3]]++>>> Shape.indices $ Shape.simplexDescending (replicate 3 Shape.AllDistinct) $ Shape.ZeroBased (4::Int)+[[2,1,0],[3,1,0],[3,2,0],[3,2,1]]+>>> Shape.indices $ Shape.simplexDescending (replicate 3 Shape.SomeRepetitive) $ Shape.ZeroBased (3::Int)+[[0,0,0],[1,0,0],[1,1,0],[1,1,1],[2,0,0],[2,1,0],[2,1,1],[2,2,0],[2,2,1],[2,2,2]]+>>> Shape.indices $ Shape.simplexDescending [Shape.Repetitive,Shape.Distinct,Shape.Repetitive] $ Shape.ZeroBased (4::Int)+[[1,1,0],[2,1,0],[2,2,0],[2,2,1],[3,1,0],[3,2,0],[3,2,1],[3,3,0],[3,3,1],[3,3,2]]+>>> Shape.indices $ Shape.simplexDescending [Shape.Repetitive,Shape.Distinct,Shape.Distinct] $ Shape.ZeroBased (4::Int)+[[1,1,0],[2,1,0],[2,2,0],[2,2,1],[3,1,0],[3,2,0],[3,2,1],[3,3,0],[3,3,1],[3,3,2]]+-}+data Simplex order coll f size =+ Simplex {+ simplexOrder :: SimplexOrder order,+ simplexDimension :: f coll,+ simplexSize :: size+ }++data Ascending+data Descending+data SimplexOrder order where+ Ascending :: SimplexOrder Ascending+ Descending :: SimplexOrder Descending++instance Eq (SimplexOrder order) where+ Ascending == Ascending = True+ Descending == Descending = True++instance Show (SimplexOrder order) where+ show Ascending = "Ascending"+ show Descending = "Descending"++type SimplexAscending = Simplex Ascending+type SimplexDescending = Simplex Descending++simplexAscending :: f coll -> size -> SimplexAscending coll f size+simplexAscending = Simplex Ascending++simplexDescending :: f coll -> size -> SimplexDescending coll f size+simplexDescending = Simplex Descending++isAscending :: SimplexOrder order -> Bool+isAscending Ascending = True+isAscending Descending = False++class SimplexOrderC order where+instance SimplexOrderC Ascending where+instance SimplexOrderC Descending where++data AllDistinct = AllDistinct deriving (Show, Eq)+data SomeRepetitive = SomeRepetitive deriving (Show, Eq)+data Collision = Distinct | Repetitive deriving (Show, Eq, Ord, Enum)++class CollisionC coll where repetitionAllowed :: coll -> Bool+instance CollisionC AllDistinct where repetitionAllowed AllDistinct = False+instance CollisionC SomeRepetitive where repetitionAllowed SomeRepetitive = True+instance CollisionC Collision where+ repetitionAllowed Distinct = False+ repetitionAllowed Repetitive = True++instance+ (SimplexOrderC order, Show coll, FunctorC.Show1 f, Show size) =>+ Show (Simplex order coll f size) where+ showsPrec p (Simplex order d sz) =+ showParen (p>10) $+ showString "Simplex " .+ shows order .+ showString " " .+ FunctorC.showsPrec1 11 d .+ showString " " .+ showsPrec 11 sz++instance+ (SimplexOrderC order, CollisionC coll, Traversable f, C size) =>+ C (Simplex order coll f size) where+ size (Simplex _order d sz) =+ let ds = Fold.toList d+ rep = length $ filter repetitionAllowed $ laxInit ds+ in simplexLayoutSize (length ds) (size sz + rep)++laxInit :: [a] -> [a]+laxInit xs = Match.take (drop 1 xs) xs++simplexLayoutSize :: Integral i => Int -> i -> i+simplexLayoutSize d n =+ case drop d $ binomials n of+ [] -> 0+ m:_ -> m++-- cf. package combinatorial+binomials :: Integral a => a -> [a]+binomials n =+ scanl (\acc (num,den) -> div (acc*num) den) 1+ (zip [n, pred n ..] [1..n])++foldLength :: (Foldable f) => f a -> Int+foldLength = length . Fold.toList++instance+ (SimplexOrderC order, CollisionC coll,+ Traversable f, FunctorC.Eq1 f, Indexed size) =>+ Indexed (Simplex order coll f size) where+ type Index (Simplex order coll f size) = f (Index size)+ indices (Simplex order d sz) =+ flip MS.evalStateT (indices sz) $+ Trav.traverse+ (if isAscending order+ then chooseIndexAscending+ else chooseIndexDescending)+ d+ inBounds (Simplex order d sz) =+ let getOffset = offset sz in \ix ->+ let ixs = Fold.toList ix in+ all (inBounds sz) ixs &&+ FunctorC.eq1 (void d) (void ix) &&+ isMonotonic order (Fold.toList d) (map getOffset ixs)+ unifiedSizeOffset (Simplex order d sz) =+ let (n, getOffset) = unifiedSizeOffset sz in+ let dInt = foldLength d+ prep = prepareSimplexIndexingOrder order d n in+ (simplexLayoutSize dInt (fst prep),+ -- cf. Combinatorics.chooseRank+ \ixf -> do+ ks <- Trav.traverse getOffset $ Fold.toList ixf+ assert+ "Shape.Simplex.offset: simplex and index structure mismatch"+ (FunctorC.eq1 (void d) (void ixf))+ assert+ "Shape.Simplex.offset: index elements not monotonic"+ (isMonotonic order (Fold.toList d) ks)+ return $+ simplexOffset order dInt+ (mapSnd (map snd . Fold.toList) prep) ks)++simplexOffset ::+ (Integral i) => SimplexOrder order -> Int -> (i, [(Int, i)]) -> [i] -> i+simplexOffset order d (nsum,cis) ks =+ case order of+ Ascending ->+ simplexLayoutSize d nsum - 1+ -+ sum (zipWith (\k (x,y) -> simplexLayoutSize x (y-k)) ks cis)+ Descending ->+ sum (zipWith (\k (x,y) -> simplexLayoutSize x (y+k)) ks cis)++isMonotonic ::+ (CollisionC coll) => SimplexOrder order -> [coll] -> [Int] -> Bool+isMonotonic order cs =+ and+ .+ (if isAscending order+ then+ ListHT.mapAdjacent+ (\(c,x) (_,y) -> if repetitionAllowed c then x<=y else x<y)+ else+ ListHT.mapAdjacent+ (\(c,x) (_,y) -> if repetitionAllowed c then x>=y else x>y))+ .+ zip cs++chooseIndexAscending, chooseIndexDescending ::+ (CollisionC coll) => coll -> MS.StateT [a] [] a++chooseIndexAscending coll =+ MS.StateT $ \as -> zip as $+ (if repetitionAllowed coll then NonEmpty.flatten else NonEmpty.tail) $+ NonEmpty.tails as++chooseIndexDescending coll =+ MS.StateT $ \as -> zip as $+ (if repetitionAllowed coll then NonEmpty.tail else NonEmpty.flatten) $+ NonEmpty.inits as++instance+ (SimplexOrderC order, CollisionC coll,+ Traversable f, FunctorC.Eq1 f, InvIndexed size) =>+ InvIndexed (Simplex order coll f size) where+ unifiedIndexFromOffset (Simplex order d sh) =+ let n = size sh in+ let (nSum,deco) = prepareSimplexIndexingOrder order d n in+ let dInt = foldLength d in \k ->+ maybe+ (throwOrError $ messageIndexFromOffset "Simplex" k)+ (Trav.traverse (unifiedIndexFromOffset sh) . snd) $+ if isAscending order+ then+ mapAccumLM+ (\(a,k0) (db,(x,y)) ->+ case dropWhile ((<0) . snd) $+ map (\bi -> (bi, k0 - simplexLayoutSize x (y-bi))) $+ takeWhile (<n) $ iterate (1+) a of+ [] -> Nothing+ (b,k1):_ -> Just ((b+db, k1), b))+ (0, simplexLayoutSize dInt nSum - 1 - k)+ deco+ else+ mapAccumLM+ (\(a,k0) (db,(x,y)) ->+ case dropWhile ((<0) . snd) $+ map (\bi -> (bi, k0 - simplexLayoutSize x (y+bi))) $+ takeWhile (>=0) $ iterate (subtract 1) a of+ [] -> Nothing+ (b,k1):_ -> Just ((b-db, k1), b))+ (n,k)+ deco++mapAccumLM ::+ (Traversable t, Monad m) => (a -> b -> m (a, c)) -> a -> t b -> m (a, t c)+mapAccumLM f a0 xs =+ liftM swap $+ MS.runStateT+ (Trav.mapM (\b -> MS.StateT $ \a -> liftM swap $ f a b) xs) a0+++prepareSimplexIndexingOrder ::+ (Traversable t, Num i, CollisionC coll) =>+ SimplexOrder order -> t coll -> Int -> (Int, t (Int, (i, Int)))+prepareSimplexIndexingOrder order d n =+ if isAscending order+ then mapFst (1+) $ prepareSimplexIndexing d (n-1)+ else mapFst (n+) $ prepareSimplexIndexing d 0++prepareSimplexIndexing ::+ (Traversable t, Num i, CollisionC coll) =>+ t coll -> Int -> (Int, t (Int, (i, Int)))+prepareSimplexIndexing d n =+ let ((_,(_,nSum)), deco) =+ Trav.mapAccumR+ (\(c0,(x,y)) ci ->+ let c1 = fromEnum (ci&&c0)+ p = (x+1,y+c1)+ in ((True,p),(1-c1,p)))+ (False,(0,n))+ (fmap repetitionAllowed d)+ in (nSum, deco)++++{- | 'Cyclic' is a shape, where the indices wrap around at the array boundaries. E.g. @@ -1020,75 +1360,71 @@ instance (Integral n) => C (Cyclic n) where size (Cyclic len) = fromIntegral len- uncheckedSize (Cyclic len) = fromIntegral len instance (Integral n) => Indexed (Cyclic n) where type Index (Cyclic n) = n indices (Cyclic len) = indices $ ZeroBased len- offset = uncheckedOffset- uncheckedOffset (Cyclic len) ix = fromIntegral $ mod ix len+ unifiedOffset (Cyclic len) ix = pure $ fromIntegral $ mod ix len inBounds (Cyclic len) _ix = len>0 instance (Integral n) => InvIndexed (Cyclic n) where- indexFromOffset (Cyclic len) k0 =+ unifiedIndexFromOffset (Cyclic len) k0 = do let k = fromIntegral k0- in if 0<=k && k<len- then k- else errorIndexFromOffset "Cyclic" k0- uncheckedIndexFromOffset _ k = fromIntegral k+ assertIndexFromOffset "Cyclic" k0 $ 0<=k && k<len+ return k -infixr 5 :+:+infixr 5 ::+ {- | Row-major composition of two dimensions. ->>> Shape.indices (Shape.ZeroBased (3::Int) :+: Shape.Range 'a' 'c')+>>> Shape.indices (Shape.ZeroBased (3::Int) ::+ Shape.Range 'a' 'c') [Left 0,Left 1,Left 2,Right 'a',Right 'b',Right 'c'] -}-data sh0:+:sh1 = sh0:+:sh1+data sh0::+sh1 = sh0::+sh1 deriving (Eq, Show) -instance (NFData sh0, NFData sh1) => NFData (sh0:+:sh1) where- rnf (sh0:+:sh1) = rnf (sh0,sh1)+instance (NFData sh0, NFData sh1) => NFData (sh0::+sh1) where+ rnf (sh0::+sh1) = rnf (sh0,sh1) -instance (C sh0, C sh1) => C (sh0:+:sh1) where- size (sh0:+:sh1) = size sh0 + size sh1- uncheckedSize (sh0:+:sh1) = uncheckedSize sh0 + uncheckedSize sh1+instance (C sh0, C sh1) => C (sh0::+sh1) where+ size (sh0::+sh1) = size sh0 + size sh1 -instance (Indexed sh0, Indexed sh1) => Indexed (sh0:+:sh1) where- type Index (sh0:+:sh1) = Either (Index sh0) (Index sh1)- indices (sh0:+:sh1) = map Left (indices sh0) ++ map Right (indices sh1)- offset (sh0:+:sh1) ix =- case ix of- Left ix0 -> offset sh0 ix0- Right ix1 -> size sh0 + offset sh1 ix1- uncheckedOffset (sh0:+:sh1) ix =- case ix of- Left ix0 -> uncheckedOffset sh0 ix0- Right ix1 -> uncheckedSize sh0 + uncheckedOffset sh1 ix1- sizeOffset (sh0:+:sh1) =- let (n0, getOffset0) = sizeOffset sh0- (n1, getOffset1) = sizeOffset sh1- in (n0+n1, either getOffset0 ((n0+) . getOffset1))- uncheckedSizeOffset (sh0:+:sh1) =- let (n0, getOffset0) = uncheckedSizeOffset sh0- (n1, getOffset1) = uncheckedSizeOffset sh1- in (n0+n1, either getOffset0 ((n0+) . getOffset1))- inBounds (sh0:+:sh1) = either (inBounds sh0) (inBounds sh1)+instance (Indexed sh0, Indexed sh1) => Indexed (sh0::+sh1) where+ type Index (sh0::+sh1) = Either (Index sh0) (Index sh1)+ indices (sh0::+sh1) = map Left (indices sh0) ++ map Right (indices sh1)+ unifiedOffset (sh0::+sh1) =+ let (n0,getOffset0) = unifiedSizeOffset sh0+ getOffset1 = unifiedOffset sh1+ in \ix ->+ case ix of+ Left ix0 -> getOffset0 ix0+ Right ix1 -> (n0 +) <$> getOffset1 ix1+ unifiedSizeOffset (sh0::+sh1) =+ let (n0, getOffset0) = unifiedSizeOffset sh0+ (n1, getOffset1) = unifiedSizeOffset sh1+ in (n0+n1, either getOffset0 (fmap (n0+) . getOffset1))+ inBounds (sh0::+sh1) = either (inBounds sh0) (inBounds sh1) -instance (InvIndexed sh0, InvIndexed sh1) => InvIndexed (sh0:+:sh1) where- indexFromOffset (sh0:+:sh1) k =- let pivot = size sh0- in if k < pivot- then Left $ indexFromOffset sh0 k- else Right $ indexFromOffset sh1 $ k-pivot- uncheckedIndexFromOffset (sh0:+:sh1) k =+instance (InvIndexed sh0, InvIndexed sh1) => InvIndexed (sh0::+sh1) where+ unifiedIndexFromOffset (sh0::+sh1) = let pivot = size sh0- in if k < pivot- then Left $ uncheckedIndexFromOffset sh0 k- else Right $ uncheckedIndexFromOffset sh1 $ k-pivot+ in \k ->+ if k < pivot+ then Left <$> unifiedIndexFromOffset sh0 k+ else Right <$> unifiedIndexFromOffset sh1 (k-pivot) -instance (Static sh0, Static sh1) => Static (sh0:+:sh1) where- static = static:+:static+instance (Static sh0, Static sh1) => Static (sh0::+sh1) where+ static = static::+static+++infixl 7 |*+infixl 6 |+|++(|*) :: (Functor f, Num a) => f a -> a -> f a+f|*a = fmap (*a) f++(|+|) :: (Applicative f, Num a) => f a -> f a -> f a+(|+|) = liftA2 (+)
src/Data/Array/Comfort/Shape/Test.hs view
@@ -1,15 +1,16 @@ {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE GADTs #-} module Data.Array.Comfort.Shape.Test (tests) where import qualified Data.Array.Comfort.Shape as Shape+import Data.Array.Comfort.Shape.Utility (isRight)++import Control.Applicative (pure) import Data.Tuple.HT (mapSnd) import qualified Test.QuickCheck as QC -uncheckedSize :: (Shape.C sh) => sh -> Bool-uncheckedSize sh = Shape.size sh == Shape.uncheckedSize sh- inBounds :: (Shape.Indexed sh) => sh -> Bool inBounds sh = all (Shape.inBounds sh) $ Shape.indices sh @@ -21,6 +22,21 @@ let ixs = Shape.indices sh in not (null ixs) QC.==> QC.forAll (QC.elements ixs) f +-- ToDo: we need to check for indices outside of bounds, too+inBoundsOffset ::+ (Shape.Indexed sh, Shape.Index sh ~ ix, Show ix) => sh -> QC.Property+inBoundsOffset sh =+ forAllIndices sh $ \ix ->+ Shape.inBounds sh ix ==+ isRight (Shape.getChecked (Shape.unifiedOffset sh ix))++inBoundsSizeOffset ::+ (Shape.Indexed sh, Shape.Index sh ~ ix, Show ix) => sh -> QC.Property+inBoundsSizeOffset sh =+ forAllIndices sh $ \ix ->+ Shape.inBounds sh ix ==+ isRight (Shape.getChecked (snd (Shape.unifiedSizeOffset sh) ix))+ sizeOffset :: (Shape.Indexed sh, Shape.Index sh ~ ix, Show ix) => sh -> QC.Property sizeOffset sh =@@ -34,14 +50,45 @@ uncheckedSizeOffset sh = forAllIndices sh $ \ix -> mapSnd ($ix) (Shape.uncheckedSizeOffset sh) ==- (Shape.uncheckedSize sh, Shape.uncheckedOffset sh ix)+ (Shape.size sh, Shape.uncheckedOffset sh ix) +unifiedSizeOffsetA ::+ (Shape.Checking check, Shape.Indexed sh, Shape.Index sh ~ ix, Show ix) =>+ Shape.CheckSingleton check -> sh -> QC.Property+unifiedSizeOffsetA check sh =+ forAllIndices sh $ \ix ->+ mapSnd ($ix) (Shape.unifiedSizeOffset sh) ==+ (Shape.size sh, Shape.requireCheck check $ Shape.unifiedOffset sh ix)++unifiedSizeOffsetB ::+ (Shape.Checking check, Shape.Indexed sh, Shape.Index sh ~ ix, Show ix) =>+ Shape.CheckSingleton check -> sh -> QC.Property+unifiedSizeOffsetB check sh =+ forAllIndices sh $ \ix ->+ (mapSnd (Shape.requireCheck check . ($ix)) $ Shape.unifiedSizeOffset sh)+ ==+ case check of+ Shape.Checked ->+ mapSnd (pure . ($ix)) (Shape.sizeOffset sh)+ Shape.Unchecked ->+ mapSnd (pure . ($ix)) (Shape.uncheckedSizeOffset sh)+ uncheckedOffset :: (Shape.Indexed sh, Shape.Index sh ~ ix, Show ix) => sh -> QC.Property uncheckedOffset sh = forAllIndices sh $ \ix -> Shape.offset sh ix == Shape.uncheckedOffset sh ix +unifiedOffset ::+ (Shape.Checking check, Shape.Indexed sh, Shape.Index sh ~ ix, Show ix) =>+ Shape.CheckSingleton check -> sh -> QC.Property+unifiedOffset check sh =+ forAllIndices sh $ \ix ->+ Shape.requireCheck check (Shape.unifiedOffset sh ix) ==+ case check of+ Shape.Checked -> pure $ Shape.offset sh ix+ Shape.Unchecked -> pure $ Shape.uncheckedOffset sh ix+ lengthIndices :: (Shape.Indexed sh) => sh -> Bool lengthIndices sh = length (Shape.indices sh) == Shape.size sh @@ -60,13 +107,50 @@ Shape.indices sh == map (Shape.uncheckedIndexFromOffset sh) (take (Shape.size sh) [0..]) +unifiedInvIndicesA ::+ (Shape.Checking check, Shape.InvIndexed sh, Shape.Index sh ~ ix, Eq ix) =>+ Shape.CheckSingleton check -> sh -> Bool+unifiedInvIndicesA check sh =+ map pure (Shape.indices sh) ==+ map (Shape.requireCheck check . Shape.unifiedIndexFromOffset sh)+ (take (Shape.size sh) [0..]) +unifiedInvIndicesB ::+ (Shape.Checking check, Shape.InvIndexed sh, Shape.Index sh ~ ix, Eq ix) =>+ Shape.CheckSingleton check -> sh -> QC.Property+unifiedInvIndicesB check sh =+ let n = Shape.size sh in n>0 QC.==>+ QC.forAll (QC.choose (0, n-1)) $ \k ->+ Shape.requireCheck check (Shape.unifiedIndexFromOffset sh k) ==+ case check of+ Shape.Checked -> pure $ Shape.indexFromOffset sh k+ Shape.Unchecked -> pure $ Shape.uncheckedIndexFromOffset sh k+++unifiedTests ::+ (Shape.Checking check,+ Shape.InvIndexed sh, Show sh, Shape.Index sh ~ ix, Eq ix, Show ix) =>+ Shape.CheckSingleton check -> QC.Gen sh -> [(String, QC.Property)]+unifiedTests check gen =+ ("unifiedSizeOffsetA", QC.forAll gen (unifiedSizeOffsetA check)) :+ ("unifiedSizeOffsetB", QC.forAll gen (unifiedSizeOffsetB check)) :+ ("unifiedOffset", QC.forAll gen (unifiedOffset check)) :+ ("unifiedInvIndicesA", QC.forAll gen (unifiedInvIndicesA check)) :+ ("unifiedInvIndicesB", QC.forAll gen (unifiedInvIndicesB check)) :+ []++-- cf. Test.Utility+prefix :: String -> [(String, test)] -> [(String, test)]+prefix msg =+ map (\(str,test) -> (msg ++ "." ++ str, test))+ tests :: (Shape.InvIndexed sh, Show sh, Shape.Index sh ~ ix, Eq ix, Show ix) => QC.Gen sh -> [(String, QC.Property)] tests gen =- ("uncheckedSize", QC.forAll gen uncheckedSize) : ("inBounds", QC.forAll gen inBounds) :+ ("inBoundsOffset", QC.forAll gen inBoundsOffset) :+ ("inBoundsSizeOffset", QC.forAll gen inBoundsSizeOffset) : ("sizeOffset", QC.forAll gen sizeOffset) : ("uncheckedSizeOffset", QC.forAll gen uncheckedSizeOffset) : ("uncheckedOffset", QC.forAll gen uncheckedOffset) :@@ -74,4 +158,6 @@ ("indexOffsets", QC.forAll gen indexOffsets) : ("invIndices", QC.forAll gen invIndices) : ("uncheckedInvIndices", QC.forAll gen uncheckedInvIndices) :+ prefix "Checked" (unifiedTests Shape.Checked gen) +++ prefix "Unchecked" (unifiedTests Shape.Unchecked gen) ++ []
src/Data/Array/Comfort/Shape/Utility.hs view
@@ -3,6 +3,13 @@ import Text.Printf (printf) +messageIndexFromOffset :: String -> Int -> String+messageIndexFromOffset name k =+ printf "indexFromOffset (%s): index %d out of range" name k+ errorIndexFromOffset :: String -> Int -> a-errorIndexFromOffset name k =- error $ printf "indexFromOffset (%s): index %d out of range" name k+errorIndexFromOffset name = error . messageIndexFromOffset name+++isRight :: Either a b -> Bool+isRight = either (const False) (const True)
src/Data/Array/Comfort/Storable.hs view
@@ -5,7 +5,7 @@ reshape, mapShape, - (!),+ accessMaybe, (!), Array.toList, Array.vectorFromList, toAssociations,@@ -16,6 +16,8 @@ sample, fromBoxed, toBoxed,+ fromStorableVector,+ toStorableVector, Array.map, Array.mapWithIndex,@@ -24,6 +26,9 @@ accumulate, fromAssociations, + pick,+ toRowArray,+ fromRowArray, Array.singleton, Array.append, Array.take, Array.drop,@@ -48,21 +53,26 @@ import qualified Data.Array.Comfort.Check as Check import qualified Data.Array.Comfort.Shape as Shape import Data.Array.Comfort.Storable.Unchecked (Array(Array))+import Data.Array.Comfort.Shape ((::+)((::+))) import System.IO.Unsafe (unsafePerformIO)+import Foreign.Marshal.Array (copyArray, advancePtr) import Foreign.Storable (Storable) import Foreign.ForeignPtr (withForeignPtr) import Control.Monad.ST (runST) +import qualified Data.StorableVector.Base as SVB import qualified Data.Map as Map import qualified Data.Set as Set+import qualified Data.Traversable as Trav import qualified Data.Foldable as Fold import qualified Data.List as List import qualified Data.Tuple.Strict as StrictTuple import Data.Map (Map) import Data.Set (Set) import Data.Foldable (forM_)+import Data.Maybe (fromMaybe) import Data.Semigroup (Semigroup, (<>), Min(Min,getMin), Max(Max,getMax), Arg(Arg)) @@ -73,12 +83,12 @@ {- $setup >>> import qualified Data.Array.Comfort.Storable as Array >>> import qualified Data.Array.Comfort.Shape as Shape->>> import Data.Array.Comfort.Storable (Array)+>>> import Data.Array.Comfort.Storable (Array, (!)) >>> >>> import qualified Test.QuickCheck as QC >>> import Test.ChasingBottoms.IsBottom (isBottom) >>>->>> import Control.Applicative ((<$>))+>>> import Control.Applicative ((<$>), (<*>)) >>> >>> import Data.Word (Word16) >>>@@ -87,6 +97,23 @@ >>> genArray :: QC.Gen (Array ShapeInt Word16) >>> genArray = Array.vectorFromList <$> QC.arbitrary >>>+>>> genArray2 :: QC.Gen (Array (ShapeInt,ShapeInt) Word16)+>>> genArray2 = do+>>> xs <- QC.arbitrary+>>> let n = length xs+>>> (k,m) <-+>>> if n == 0+>>> then QC.elements [(,) 0, flip (,) 0] <*> QC.choose (1,n)+>>> else fmap (\m -> (div n m, m)) $ QC.choose (1,n)+>>> return $ Array.fromList (Shape.ZeroBased k, Shape.ZeroBased m) xs+>>>+>>> genNonEmptyArray2 :: QC.Gen (Array (ShapeInt,ShapeInt) Word16)+>>> genNonEmptyArray2 = do+>>> xs <- QC.getNonEmpty <$> QC.arbitrary+>>> let n = length xs+>>> m <- QC.choose (1,n)+>>> return $ Array.fromList (Shape.ZeroBased (div n m), Shape.ZeroBased m) xs+>>> >>> infix 4 ==? >>> (==?) :: a -> a -> (a,a) >>> (==?) = (,)@@ -141,17 +168,42 @@ toBoxed :: (Shape.C sh, Storable a) => Array sh a -> BoxedArray.Array sh a toBoxed arr = BoxedArray.fromList (Array.shape arr) $ Array.toList arr ++fromStorableVector ::+ (Storable a) => SVB.Vector a -> Array (Shape.ZeroBased Int) a+fromStorableVector xs =+ case SVB.toForeignPtr xs of+ (fptr,0,n) -> Array (Shape.ZeroBased n) fptr+ (fptr,s,n) ->+ Array.takeRight $+ Array (Shape.ZeroBased s ::+ Shape.ZeroBased n) fptr++toStorableVector :: (Shape.C sh, Storable a) => Array sh a -> SVB.Vector a+toStorableVector (Array sh fptr) =+ SVB.fromForeignPtr fptr $ Shape.size sh++ toAssociations :: (Shape.Indexed sh, Storable a) => Array sh a -> [(Shape.Index sh, a)] toAssociations arr = zip (Shape.indices $ shape arr) (Array.toList arr) +errorArray :: String -> String -> a+errorArray name msg =+ error ("Array.Comfort.Storable." ++ name ++ ": " ++ msg)+ infixl 9 ! (!) :: (Shape.Indexed sh, Storable a) => Array sh a -> Shape.Index sh -> a-(!) arr ix = runST (do+(!) arr ix =+ fromMaybe (errorArray "!" "index out of bounds") $+ accessMaybe arr ix++accessMaybe ::+ (Shape.Indexed sh, Storable a) => Array sh a -> Shape.Index sh -> Maybe a+accessMaybe arr ix = runST (do marr <- MutArrayNC.unsafeThaw arr- MutArray.read marr ix)+ Trav.sequenceA $ MutArray.readMaybe marr ix) zipWith ::@@ -160,7 +212,7 @@ zipWith f a b = if shape a == shape b then Array.zipWith f a b- else error "zipWith: shapes mismatch"+ else errorArray "zipWith" "shapes mismatch" (//) :: (Shape.Indexed sh, Storable a) =>@@ -186,6 +238,38 @@ forM_ xs $ uncurry $ MutArray.write marr MutArrayNC.unsafeFreeze marr) ++{- |+prop> QC.forAll genNonEmptyArray2 $ \xs -> QC.forAll (QC.elements $ Shape.indices $ Array.shape xs) $ \(ix0,ix1) -> Array.pick xs ix0 ! ix1 == xs!(ix0,ix1)+-}+pick ::+ (Shape.Indexed sh0, Shape.C sh1, Storable a) =>+ Array (sh0,sh1) a -> Shape.Index sh0 -> Array sh1 a+pick (Array (sh0,sh1) x) ix0 =+ Array.unsafeCreateWithSize sh1 $ \k yPtr ->+ withForeignPtr x $ \xPtr ->+ copyArray yPtr (advancePtr xPtr (Shape.offset sh0 ix0 * Shape.size sh1)) k++toRowArray ::+ (Shape.Indexed sh0, Shape.C sh1, Storable a) =>+ Array (sh0,sh1) a -> BoxedArray.Array sh0 (Array sh1 a)+toRowArray x = fmap (pick x) $ BoxedArray.indices $ fst $ Array.shape x++{- |+It is a checked error if a row width differs from the result array width.++prop> QC.forAll genArray2 $ \xs -> xs == Array.fromRowArray (snd $ Array.shape xs) (Array.toRowArray xs)+-}+fromRowArray ::+ (Shape.C sh0, Shape.C sh1, Eq sh1, Storable a) =>+ sh1 -> BoxedArray.Array sh0 (Array sh1 a) -> Array (sh0,sh1) a+fromRowArray sh1 x =+ Array.unsafeCreate (BoxedArray.shape x, sh1) $ \yPtr ->+ let k = Shape.size sh1 in+ forM_ (zip [0,k..] (BoxedArray.toList x)) $ \(j, Array sh1i row) ->+ if sh1 == sh1i+ then withForeignPtr row $ \xPtr -> copyArray (advancePtr yPtr j) xPtr k+ else errorArray "fromRowArray" "mismatching row width" {- |
src/Data/Array/Comfort/Storable/Mutable.hs view
@@ -5,7 +5,7 @@ shape, MutArray.new,- read,+ read, MutArray.readMaybe, write, update, toList,@@ -19,6 +19,7 @@ import qualified Data.Array.Comfort.Storable.Mutable.Unchecked as MutArray import qualified Data.Array.Comfort.Shape as Shape import Data.Array.Comfort.Storable.Mutable.Unchecked (Array)+import Data.Maybe (fromMaybe) import Foreign.Marshal.Array (pokeArray) import Foreign.Storable (Storable)@@ -36,9 +37,9 @@ (PrimMonad m, Shape.Indexed sh, Storable a) => Array m sh a -> Shape.Index sh -> m a read arr ix =- if Shape.inBounds (shape arr) ix- then MutArray.read arr ix- else error "Array.Comfort.Storable.Mutable.read: index out of bounds"+ fromMaybe+ (error "Array.Comfort.Storable.Mutable.read: index out of bounds")+ (MutArray.readMaybe arr ix) write :: (PrimMonad m, Shape.Indexed sh, Storable a) =>
src/Data/Array/Comfort/Storable/Mutable/Private.hs view
@@ -13,6 +13,7 @@ import Control.Monad (liftM) import Control.Applicative ((<$>)) +import Data.Either.HT (maybeRight) import Data.Tuple.HT (mapFst) import qualified Prelude as P@@ -100,6 +101,13 @@ Array m sh a -> Shape.Index sh -> m a read (Array sh fptr) ix = withArrayPtr fptr $ flip peekElemOff (Shape.uncheckedOffset sh ix)++readMaybe ::+ (PrimMonad m, Shape.Indexed sh, Storable a) =>+ Array m sh a -> Shape.Index sh -> Maybe (m a)+readMaybe (Array sh fptr) ix =+ fmap (withArrayPtr fptr . flip peekElemOff) $ maybeRight $+ Shape.getChecked $ Shape.unifiedOffset sh ix write :: (PrimMonad m, Shape.Indexed sh, Storable a) =>
src/Data/Array/Comfort/Storable/Mutable/Unchecked.hs view
@@ -15,6 +15,7 @@ MutArray.unsafeCreateWithSizeAndResult, MutArray.withPtr, MutArray.read,+ MutArray.readMaybe, MutArray.write, MutArray.update, MutArray.toList,
src/Data/Array/Comfort/Storable/Unchecked.hs view
@@ -38,7 +38,7 @@ import qualified Data.Array.Comfort.Storable.Memory as Memory import qualified Data.Array.Comfort.Shape as Shape import Data.Array.Comfort.Storable.Private (Array(Array), mapShape)-import Data.Array.Comfort.Shape ((:+:)((:+:)))+import Data.Array.Comfort.Shape ((::+)((::+))) import System.IO.Unsafe (unsafePerformIO) import Foreign.Marshal.Array (copyArray, advancePtr)@@ -136,11 +136,14 @@ singleton :: (Storable a) => a -> Array () a singleton a = unsafeCreate () $ flip poke a ++infixr 5 `append`+ append :: (Shape.C shx, Shape.C shy, Storable a) =>- Array shx a -> Array shy a -> Array (shx:+:shy) a+ Array shx a -> Array shy a -> Array (shx::+shy) a append (Array shX x) (Array shY y) =- unsafeCreate (shX:+:shY) $ \zPtr ->+ unsafeCreate (shX::+shY) $ \zPtr -> withForeignPtr x $ \xPtr -> withForeignPtr y $ \yPtr -> do let sizeX = Shape.size shX@@ -160,7 +163,7 @@ splitN :: (Integral n, Storable a) => n -> Array (Shape.ZeroBased n) a ->- Array (Shape.ZeroBased n :+: Shape.ZeroBased n) a+ Array (Shape.ZeroBased n ::+ Shape.ZeroBased n) a splitN n = mapShape (Shape.zeroBasedSplit n) {- |@@ -168,19 +171,19 @@ -} takeLeft :: (Shape.C sh0, Shape.C sh1, Storable a) =>- Array (sh0:+:sh1) a -> Array sh0 a+ Array (sh0::+sh1) a -> Array sh0 a takeLeft =- takeCenter . mapShape (\(sh0 :+: sh1) -> (Shape.Zero :+: sh0 :+: sh1))+ takeCenter . mapShape (\(sh0 ::+ sh1) -> (Shape.Zero ::+ sh0 ::+ sh1)) takeRight :: (Shape.C sh0, Shape.C sh1, Storable a) =>- Array (sh0:+:sh1) a -> Array sh1 a+ Array (sh0::+sh1) a -> Array sh1 a takeRight =- takeCenter . mapShape (\(sh0 :+: sh1) -> (sh0 :+: sh1 :+: Shape.Zero))+ takeCenter . mapShape (\(sh0 ::+ sh1) -> (sh0 ::+ sh1 ::+ Shape.Zero)) split :: (Shape.C sh0, Shape.C sh1, Storable a) =>- Array (sh0:+:sh1) a -> (Array sh0 a, Array sh1 a)+ Array (sh0::+sh1) a -> (Array sh0 a, Array sh1 a) split x = (takeLeft x, takeRight x) {- |@@ -188,8 +191,8 @@ -} takeCenter :: (Shape.C sh0, Shape.C sh1, Shape.C sh2, Storable a) =>- Array (sh0:+:sh1:+:sh2) a -> Array sh1 a-takeCenter (Array (sh0:+:sh1:+:_sh2) x) =+ Array (sh0::+sh1::+sh2) a -> Array sh1 a+takeCenter (Array (sh0::+sh1::+_sh2) x) = unsafeCreateWithSize sh1 $ \k yPtr -> withForeignPtr x $ \xPtr -> copyArray yPtr (advancePtr xPtr (Shape.size sh0)) k
test/DocTest/Data/Array/Comfort/Shape.hs view
@@ -1,77 +1,77 @@ -- Do not edit! Automatically created with doctest-extract from src/Data/Array/Comfort/Shape.hs-{-# LINE 65 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 95 "src/Data/Array/Comfort/Shape.hs" #-} module DocTest.Data.Array.Comfort.Shape where import Test.DocTest.Base import qualified Test.DocTest.Driver as DocTest -{-# LINE 66 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 96 "src/Data/Array/Comfort/Shape.hs" #-} import qualified Data.Array.Comfort.Shape as Shape import qualified Data.Map as Map import qualified Data.Set as Set-import Data.Array.Comfort.Shape ((:+:)((:+:)))+import Data.Array.Comfort.Shape ((::+)((::+))) test :: DocTest.T () test = do- DocTest.printPrefix "Data.Array.Comfort.Shape:128: "-{-# LINE 128 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:264: "+{-# LINE 264 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 128 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 264 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices ()) [ExpectedLine [LineChunk "[()]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:150: "-{-# LINE 150 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:283: "+{-# LINE 283 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 150 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 283 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices (Shape.ZeroBased (7::Int))) [ExpectedLine [LineChunk "[0,1,2,3,4,5,6]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:201: "-{-# LINE 201 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:330: "+{-# LINE 330 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 201 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 330 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices (Shape.OneBased (7::Int))) [ExpectedLine [LineChunk "[1,2,3,4,5,6,7]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:249: "-{-# LINE 249 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:374: "+{-# LINE 374 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 249 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 374 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices (Shape.Range (-5) (5::Int))) [ExpectedLine [LineChunk "[-5,-4,-3,-2,-1,0,1,2,3,4,5]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:251: "-{-# LINE 251 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:376: "+{-# LINE 376 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 251 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 376 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices (Shape.Range (-1,-1) (1::Int,1::Int))) [ExpectedLine [LineChunk "[(-1,-1),(-1,0),(-1,1),(0,-1),(0,0),(0,1),(1,-1),(1,0),(1,1)]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:301: "-{-# LINE 301 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:426: "+{-# LINE 426 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 301 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 426 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices (Shape.Shifted (-4) (8::Int))) [ExpectedLine [LineChunk "[-4,-3,-2,-1,0,1,2,3]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:373: "-{-# LINE 373 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:491: "+{-# LINE 491 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 373 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 491 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices (Shape.Enumeration :: Shape.Enumeration Ordering)) [ExpectedLine [LineChunk "[LT,EQ,GT]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:428: "-{-# LINE 428 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:548: "+{-# LINE 548 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 428 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 548 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices (Set.fromList "comfort")) [ExpectedLine [LineChunk "\"cfmort\""]]- DocTest.printPrefix "Data.Array.Comfort.Shape:454: "-{-# LINE 454 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:584: "+{-# LINE 584 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 454 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 584 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices $ fmap Shape.ZeroBased $ Map.fromList [('b', (0::Int)), ('a', 5), ('c', 2)]) [ExpectedLine [LineChunk "[('a',0),('a',1),('a',2),('a',3),('a',4),('c',0),('c',1)]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:528: "-{-# LINE 528 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:649: "+{-# LINE 649 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 528 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 649 "src/Data/Array/Comfort/Shape.hs" #-} ( let sh2 = (Shape.ZeroBased (2::Int), Shape.ZeroBased (2::Int)) in let sh3 = (Shape.ZeroBased (3::Int), Shape.ZeroBased (3::Int)) in@@ -80,50 +80,98 @@ Shape.indexFromOffset (Shape.Deferred sh2) 3) ) [ExpectedLine [LineChunk "(4,3)"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:630: "-{-# LINE 630 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:749: "+{-# LINE 749 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 630 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 749 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices (Shape.ZeroBased (3::Int), Shape.ZeroBased (3::Int))) [ExpectedLine [LineChunk "[(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:744: "-{-# LINE 744 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:849: "+{-# LINE 849 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 744 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 849 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices $ Shape.Square $ Shape.ZeroBased (3::Int)) [ExpectedLine [LineChunk "[(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:793: "-{-# LINE 793 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:892: "+{-# LINE 892 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 793 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 892 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices $ Shape.Cube $ Shape.ZeroBased (2::Int)) [ExpectedLine [LineChunk "[(0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0),(1,0,1),(1,1,0),(1,1,1)]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:862: "-{-# LINE 862 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:951: "+{-# LINE 951 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 862 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 951 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices $ Shape.Triangular Shape.Upper $ Shape.ZeroBased (3::Int)) [ExpectedLine [LineChunk "[(0,0),(0,1),(0,2),(1,1),(1,2),(2,2)]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:864: "-{-# LINE 864 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:953: "+{-# LINE 953 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 864 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 953 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices $ Shape.Triangular Shape.Lower $ Shape.ZeroBased (3::Int)) [ExpectedLine [LineChunk "[(0,0),(1,0),(1,1),(2,0),(2,1),(2,2)]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:994: "-{-# LINE 994 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:1085: "+{-# LINE 1085 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.example+{-# LINE 1085 "src/Data/Array/Comfort/Shape.hs" #-}+ (Shape.indices $ Shape.simplexAscending (replicate 3 Shape.AllDistinct) $ Shape.ZeroBased (4::Int))+ [ExpectedLine [LineChunk "[[0,1,2],[0,1,3],[0,2,3],[1,2,3]]"]]+ DocTest.printPrefix "Data.Array.Comfort.Shape:1087: "+{-# LINE 1087 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.example+{-# LINE 1087 "src/Data/Array/Comfort/Shape.hs" #-}+ (Shape.indices $ Shape.simplexAscending (replicate 3 Shape.SomeRepetitive) $ Shape.ZeroBased (3::Int))+ [ExpectedLine [LineChunk "[[0,0,0],[0,0,1],[0,0,2],[0,1,1],[0,1,2],[0,2,2],[1,1,1],[1,1,2],[1,2,2],[2,2,2]]"]]+ DocTest.printPrefix "Data.Array.Comfort.Shape:1089: "+{-# LINE 1089 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.example+{-# LINE 1089 "src/Data/Array/Comfort/Shape.hs" #-}+ (Shape.indices $ Shape.simplexAscending [Shape.Repetitive,Shape.Distinct,Shape.Repetitive] $ Shape.ZeroBased (4::Int))+ [ExpectedLine [LineChunk "[[0,0,1],[0,0,2],[0,0,3],[0,1,2],[0,1,3],[0,2,3],[1,1,2],[1,1,3],[1,2,3],[2,2,3]]"]]+ DocTest.printPrefix "Data.Array.Comfort.Shape:1091: "+{-# LINE 1091 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.example+{-# LINE 1091 "src/Data/Array/Comfort/Shape.hs" #-}+ (Shape.indices $ Shape.simplexAscending [Shape.Repetitive,Shape.Distinct,Shape.Distinct] $ Shape.ZeroBased (4::Int))+ [ExpectedLine [LineChunk "[[0,0,1],[0,0,2],[0,0,3],[0,1,2],[0,1,3],[0,2,3],[1,1,2],[1,1,3],[1,2,3],[2,2,3]]"]]+ DocTest.printPrefix "Data.Array.Comfort.Shape:1094: "+{-# LINE 1094 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.example+{-# LINE 1094 "src/Data/Array/Comfort/Shape.hs" #-}+ (Shape.indices $ Shape.simplexDescending (replicate 3 Shape.AllDistinct) $ Shape.ZeroBased (4::Int))+ [ExpectedLine [LineChunk "[[2,1,0],[3,1,0],[3,2,0],[3,2,1]]"]]+ DocTest.printPrefix "Data.Array.Comfort.Shape:1096: "+{-# LINE 1096 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.example+{-# LINE 1096 "src/Data/Array/Comfort/Shape.hs" #-}+ (Shape.indices $ Shape.simplexDescending (replicate 3 Shape.SomeRepetitive) $ Shape.ZeroBased (3::Int))+ [ExpectedLine [LineChunk "[[0,0,0],[1,0,0],[1,1,0],[1,1,1],[2,0,0],[2,1,0],[2,1,1],[2,2,0],[2,2,1],[2,2,2]]"]]+ DocTest.printPrefix "Data.Array.Comfort.Shape:1098: "+{-# LINE 1098 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.example+{-# LINE 1098 "src/Data/Array/Comfort/Shape.hs" #-}+ (Shape.indices $ Shape.simplexDescending [Shape.Repetitive,Shape.Distinct,Shape.Repetitive] $ Shape.ZeroBased (4::Int))+ [ExpectedLine [LineChunk "[[1,1,0],[2,1,0],[2,2,0],[2,2,1],[3,1,0],[3,2,0],[3,2,1],[3,3,0],[3,3,1],[3,3,2]]"]]+ DocTest.printPrefix "Data.Array.Comfort.Shape:1100: "+{-# LINE 1100 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.example+{-# LINE 1100 "src/Data/Array/Comfort/Shape.hs" #-}+ (Shape.indices $ Shape.simplexDescending [Shape.Repetitive,Shape.Distinct,Shape.Distinct] $ Shape.ZeroBased (4::Int))+ [ExpectedLine [LineChunk "[[1,1,0],[2,1,0],[2,2,0],[2,2,1],[3,1,0],[3,2,0],[3,2,1],[3,3,0],[3,3,1],[3,3,2]]"]]+ DocTest.printPrefix "Data.Array.Comfort.Shape:1334: "+{-# LINE 1334 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.property-{-# LINE 994 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 1334 "src/Data/Array/Comfort/Shape.hs" #-} (let shape = Shape.Cyclic (10::Int) in Shape.offset shape (-1) == Shape.offset shape 9)- DocTest.printPrefix "Data.Array.Comfort.Shape:999: "-{-# LINE 999 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:1339: "+{-# LINE 1339 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 999 "src/Data/Array/Comfort/Shape.hs" #-}+{-# LINE 1339 "src/Data/Array/Comfort/Shape.hs" #-} (Shape.indices (Shape.Cyclic (7::Int))) [ExpectedLine [LineChunk "[0,1,2,3,4,5,6]"]]- DocTest.printPrefix "Data.Array.Comfort.Shape:1047: "-{-# LINE 1047 "src/Data/Array/Comfort/Shape.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Shape:1383: "+{-# LINE 1383 "src/Data/Array/Comfort/Shape.hs" #-} DocTest.example-{-# LINE 1047 "src/Data/Array/Comfort/Shape.hs" #-}- (Shape.indices (Shape.ZeroBased (3::Int) :+: Shape.Range 'a' 'c'))+{-# LINE 1383 "src/Data/Array/Comfort/Shape.hs" #-}+ (Shape.indices (Shape.ZeroBased (3::Int) ::+ Shape.Range 'a' 'c')) [ExpectedLine [LineChunk "[Left 0,Left 1,Left 2,Right 'a',Right 'b',Right 'c']"]]
test/DocTest/Data/Array/Comfort/Storable.hs view
@@ -1,19 +1,19 @@ -- Do not edit! Automatically created with doctest-extract from src/Data/Array/Comfort/Storable.hs-{-# LINE 73 "src/Data/Array/Comfort/Storable.hs" #-}+{-# LINE 83 "src/Data/Array/Comfort/Storable.hs" #-} module DocTest.Data.Array.Comfort.Storable where import qualified Test.DocTest.Driver as DocTest -{-# LINE 74 "src/Data/Array/Comfort/Storable.hs" #-}+{-# LINE 84 "src/Data/Array/Comfort/Storable.hs" #-} import qualified Data.Array.Comfort.Storable as Array import qualified Data.Array.Comfort.Shape as Shape-import Data.Array.Comfort.Storable (Array)+import Data.Array.Comfort.Storable (Array, (!)) import qualified Test.QuickCheck as QC import Test.ChasingBottoms.IsBottom (isBottom) -import Control.Applicative ((<$>))+import Control.Applicative ((<$>), (<*>)) import Data.Word (Word16) @@ -22,6 +22,23 @@ genArray :: QC.Gen (Array ShapeInt Word16) genArray = Array.vectorFromList <$> QC.arbitrary +genArray2 :: QC.Gen (Array (ShapeInt,ShapeInt) Word16)+genArray2 = do+ xs <- QC.arbitrary+ let n = length xs+ (k,m) <-+ if n == 0+ then QC.elements [(,) 0, flip (,) 0] <*> QC.choose (1,n)+ else fmap (\m -> (div n m, m)) $ QC.choose (1,n)+ return $ Array.fromList (Shape.ZeroBased k, Shape.ZeroBased m) xs++genNonEmptyArray2 :: QC.Gen (Array (ShapeInt,ShapeInt) Word16)+genNonEmptyArray2 = do+ xs <- QC.getNonEmpty <$> QC.arbitrary+ let n = length xs+ m <- QC.choose (1,n)+ return $ Array.fromList (Shape.ZeroBased (div n m), Shape.ZeroBased m) xs+ infix 4 ==? (==?) :: a -> a -> (a,a) (==?) = (,)@@ -37,18 +54,28 @@ test :: DocTest.T () test = do- DocTest.printPrefix "Data.Array.Comfort.Storable:194: "-{-# LINE 194 "src/Data/Array/Comfort/Storable.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Storable:243: "+{-# LINE 243 "src/Data/Array/Comfort/Storable.hs" #-} DocTest.property-{-# LINE 194 "src/Data/Array/Comfort/Storable.hs" #-}+{-# LINE 243 "src/Data/Array/Comfort/Storable.hs" #-}+ (QC.forAll genNonEmptyArray2 $ \xs -> QC.forAll (QC.elements $ Shape.indices $ Array.shape xs) $ \(ix0,ix1) -> Array.pick xs ix0 ! ix1 == xs!(ix0,ix1))+ DocTest.printPrefix "Data.Array.Comfort.Storable:261: "+{-# LINE 261 "src/Data/Array/Comfort/Storable.hs" #-}+ DocTest.property+{-# LINE 261 "src/Data/Array/Comfort/Storable.hs" #-}+ (QC.forAll genArray2 $ \xs -> xs == Array.fromRowArray (snd $ Array.shape xs) (Array.toRowArray xs))+ DocTest.printPrefix "Data.Array.Comfort.Storable:278: "+{-# LINE 278 "src/Data/Array/Comfort/Storable.hs" #-}+ DocTest.property+{-# LINE 278 "src/Data/Array/Comfort/Storable.hs" #-} (forAllNonEmpty $ \xs -> Array.minimum xs ==? minimum (Array.toList xs))- DocTest.printPrefix "Data.Array.Comfort.Storable:202: "-{-# LINE 202 "src/Data/Array/Comfort/Storable.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Storable:286: "+{-# LINE 286 "src/Data/Array/Comfort/Storable.hs" #-} DocTest.property-{-# LINE 202 "src/Data/Array/Comfort/Storable.hs" #-}+{-# LINE 286 "src/Data/Array/Comfort/Storable.hs" #-} (forAllNonEmpty $ \xs -> Array.maximum xs ==? maximum (Array.toList xs))- DocTest.printPrefix "Data.Array.Comfort.Storable:214: "-{-# LINE 214 "src/Data/Array/Comfort/Storable.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Storable:298: "+{-# LINE 298 "src/Data/Array/Comfort/Storable.hs" #-} DocTest.property-{-# LINE 214 "src/Data/Array/Comfort/Storable.hs" #-}+{-# LINE 298 "src/Data/Array/Comfort/Storable.hs" #-} (forAllNonEmpty $ \xs -> Array.limits xs ==? (Array.minimum xs, Array.maximum xs))
test/DocTest/Data/Array/Comfort/Storable/Unchecked.hs view
@@ -29,28 +29,28 @@ DocTest.property {-# LINE 134 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} (\x -> Array.singleton x ! () == (x::Word16))- DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:152: "-{-# LINE 152 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:155: "+{-# LINE 155 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} DocTest.property-{-# LINE 152 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+{-# LINE 155 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} (\(QC.NonNegative n) (Array16 x) -> x == Array.mapShape (Shape.ZeroBased . Shape.size) (Array.append (Array.take n x) (Array.drop n x)))- DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:167: "-{-# LINE 167 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:170: "+{-# LINE 170 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} DocTest.property-{-# LINE 167 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+{-# LINE 170 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} (\(Array16 x) (Array16 y) -> let xy = Array.append x y in x == Array.takeLeft xy && y == Array.takeRight xy)- DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:187: "-{-# LINE 187 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:190: "+{-# LINE 190 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} DocTest.property-{-# LINE 187 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+{-# LINE 190 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} (\(Array16 x) (Array16 y) (Array16 z) -> let xyz = Array.append x $ Array.append y z in y == Array.takeCenter xyz)- DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:200: "-{-# LINE 200 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:203: "+{-# LINE 203 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} DocTest.property-{-# LINE 200 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+{-# LINE 203 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} (\(Array16 xs) -> Array.sum xs == sum (Array.toList xs))- DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:206: "-{-# LINE 206 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+ DocTest.printPrefix "Data.Array.Comfort.Storable.Unchecked:209: "+{-# LINE 209 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} DocTest.property-{-# LINE 206 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-}+{-# LINE 209 "src/Data/Array/Comfort/Storable/Unchecked.hs" #-} (\(Array16 xs) -> Array.product xs == product (Array.toList xs))
test/Main.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE TypeFamilies #-} module Main where import qualified DocTest.Main as DocTestMain
test/Test/Shape.hs view
@@ -2,12 +2,12 @@ import qualified Data.Array.Comfort.Shape.Test as ShapeTest import qualified Data.Array.Comfort.Shape as Shape-import Data.Array.Comfort.Shape ((:+:)((:+:)))+import Data.Array.Comfort.Shape ((::+)((::+))) import qualified Test.QuickCheck as QC import Test.Utility (prefix) -import Control.Applicative (liftA2, liftA3)+import Control.Applicative (liftA2, liftA3, pure, (<$>)) import qualified Data.Map as Map import qualified Data.Set as Set@@ -20,6 +20,27 @@ tag :: sh -> Tagged Ordering sh tag = Tagged +simplex ::+ (Shape.SimplexOrderC order) =>+ Shape.SimplexOrder order -> [(String, QC.Property)]+simplex order =+ prefix "Mixed"+ (ShapeTest.tests $+ liftA2 (Shape.Simplex order)+ (take 4 <$> QC.listOf (QC.elements [Shape.Distinct,Shape.Repetitive]))+ (genZeroBased 10)) +++ prefix "Strict"+ (ShapeTest.tests $+ liftA2 (Shape.Simplex order)+ (take 4 <$> QC.listOf (pure Shape.AllDistinct))+ (genZeroBased 10)) +++ prefix "Weak"+ (ShapeTest.tests $+ liftA2 (Shape.Simplex order)+ (take 4 <$> QC.listOf (pure Shape.SomeRepetitive))+ (genZeroBased 10)) +++ []+ tests :: [(String, QC.Property)] tests = prefix "ZeroBased"@@ -62,7 +83,7 @@ (ShapeTest.tests $ liftA3 (,,) (genZeroBased 10) (genZeroBased 10) (genZeroBased 10)) ++ prefix "Append"- (ShapeTest.tests $ liftA2 (:+:) (genZeroBased 10) (genZeroBased 10)) +++ (ShapeTest.tests $ liftA2 (::+) (genZeroBased 10) (genZeroBased 10)) ++ prefix "Square" (ShapeTest.tests $ fmap Shape.Square $ genZeroBased 10) ++ prefix "Cube"@@ -73,6 +94,9 @@ prefix "Triangular Upper" (ShapeTest.tests $ fmap (Shape.Triangular Shape.Upper) (genZeroBased 10)) +++ prefix "Simplex"+ (prefix "Upper" (simplex Shape.Ascending) +++ prefix "Lower" (simplex Shape.Descending)) ++ prefix "Cyclic" (ShapeTest.tests $ fmap Shape.Cyclic $ QC.choose (0,10::Int)) ++ []