impure-containers 0.1.1 → 0.2
raw patch · 17 files changed
+1233/−139 lines, 17 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Data.Graph.Immutable: SomeGraph :: Graph g e v -> SomeGraph e v
- Data.Graph.Immutable: [getSomeGraph] :: SomeGraph e v -> Graph g e v
- Data.Graph.Immutable: data SomeGraph e v
- Data.Graph.Immutable.Tagged: Edge :: !Int -> !Int -> Edge g
- Data.Graph.Immutable.Tagged: Graph :: !(Vector v) -> !(Vector (Vector Int)) -> !(Vector (Vector e)) -> Graph g e v
- Data.Graph.Immutable.Tagged: Vertex :: Int -> Vertex g
- Data.Graph.Immutable.Tagged: Vertices :: Vector v -> Vertices g v
- Data.Graph.Immutable.Tagged: [edgeVertexA] :: Edge g -> !Int
- Data.Graph.Immutable.Tagged: [edgeVertexB] :: Edge g -> !Int
- Data.Graph.Immutable.Tagged: [getVertex] :: Vertex g -> Int
- Data.Graph.Immutable.Tagged: [getVertices] :: Vertices g v -> Vector v
- Data.Graph.Immutable.Tagged: [graphOutboundNeighborEdges] :: Graph g e v -> !(Vector (Vector e))
- Data.Graph.Immutable.Tagged: [graphOutboundNeighborVertices] :: Graph g e v -> !(Vector (Vector Int))
- Data.Graph.Immutable.Tagged: [graphVertices] :: Graph g e v -> !(Vector v)
- Data.Graph.Immutable.Tagged: breadthFirstBy :: (Ord s, Monoid s) => (v -> v -> s -> e -> s) -> Vertex g -> Graph g e v -> Vertices g s
- Data.Graph.Immutable.Tagged: data Edge g
- Data.Graph.Immutable.Tagged: data Graph g e v
- Data.Graph.Immutable.Tagged: instance GHC.Base.Functor (Data.Graph.Immutable.Tagged.Graph g e)
- Data.Graph.Immutable.Tagged: instance GHC.Base.Functor (Data.Graph.Immutable.Tagged.Vertices g)
- Data.Graph.Immutable.Tagged: lookupVertex :: Eq v => v -> Graph g e v -> Maybe (Vertex g)
- Data.Graph.Immutable.Tagged: mutableIFoldM' :: PrimMonad m => (a -> Int -> b -> m a) -> a -> MVector (PrimState m) b -> m a
- Data.Graph.Immutable.Tagged: mutableIForM_ :: PrimMonad m => MVector (PrimState m) a -> (Int -> a -> m b) -> m ()
- Data.Graph.Immutable.Tagged: newtype Vertex g
- Data.Graph.Immutable.Tagged: newtype Vertices g v
- Data.Graph.Immutable.Tagged: traverseNeighbors_ :: Applicative m => (e -> Vertex g -> v -> m a) -> Vertex g -> Graph g e v -> m ()
- Lib: someFunc :: IO ()
+ Data.ArrayList.Generic: ArrayList :: !(MutVar s Int) -> !(MutVar s (v s a)) -> ArrayList v s a
+ Data.ArrayList.Generic: [arrayListSize] :: ArrayList v s a -> !(MutVar s Int)
+ Data.ArrayList.Generic: [arrayListVector] :: ArrayList v s a -> !(MutVar s (v s a))
+ Data.ArrayList.Generic: data ArrayList v s a
+ Data.ArrayList.Generic: freeze :: (PrimMonad m, Vector v a) => ArrayList (Mutable v) (PrimState m) a -> m (v a)
+ Data.ArrayList.Generic: new :: (PrimMonad m, MVector v a) => Int -> m (ArrayList v (PrimState m) a)
+ Data.ArrayList.Generic: push :: (PrimMonad m, MVector v a) => ArrayList v (PrimState m) a -> a -> m ()
+ Data.Graph.Immutable: create :: PrimMonad m => (forall g. MGraph g (PrimState m) e v -> m ()) -> m (SomeGraph e v)
+ Data.Graph.Immutable: dijkstra :: (Ord s, Monoid s) => (v -> v -> s -> e -> s) -> s -> Vertex g -> Vertex g -> Graph g e v -> s
+ Data.Graph.Immutable: dijkstraTraversal :: (Ord s, Monoid s) => (v -> v -> s -> e -> s) -> s -> Vertex g -> Graph g e v -> Vertices g s
+ Data.Graph.Immutable: freeze :: PrimMonad m => MGraph g (PrimState m) e v -> m (Graph g e v)
+ Data.Graph.Immutable: lookupEdge :: Vertex g -> Vertex g -> Graph g e v -> Maybe e
+ Data.Graph.Immutable: lookupVertex :: Eq v => v -> Graph g e v -> Maybe (Vertex g)
+ Data.Graph.Immutable: mapVertices :: (v -> w) -> Graph g e v -> Graph g e w
+ Data.Graph.Immutable: mutableIFoldM' :: PrimMonad m => (a -> Int -> b -> m a) -> a -> MVector (PrimState m) b -> m a
+ Data.Graph.Immutable: mutableIForM_ :: PrimMonad m => MVector (PrimState m) a -> (Int -> a -> m b) -> m ()
+ Data.Graph.Immutable: size :: Graph g e v -> Size g
+ Data.Graph.Immutable: traverseNeighbors_ :: Applicative m => (e -> Vertex g -> v -> m a) -> Vertex g -> Graph g e v -> m ()
+ Data.Graph.Immutable: unSize :: Size g -> Int
+ Data.Graph.Immutable: vertexInt :: Vertex g -> Int
+ Data.Graph.Immutable: vertices :: Graph g e v -> Vertices g v
+ Data.Graph.Immutable: verticesFreeze :: PrimMonad m => MVertices g (PrimState m) v -> m (Vertices g v)
+ Data.Graph.Immutable: verticesLength :: Vertices g v -> Int
+ Data.Graph.Immutable: verticesRead :: Vertices g v -> Vertex g -> v
+ Data.Graph.Immutable: verticesThaw :: PrimMonad m => Vertices g v -> m (MVertices g (PrimState m) v)
+ Data.Graph.Immutable: verticesToVector :: Vertices g v -> Vector v
+ Data.Graph.Immutable: verticesToVertexList :: Vertices g v -> [Vertex g]
+ Data.Graph.Immutable: verticesTraverse_ :: Monad m => (Vertex g -> v -> m a) -> Vertices g v -> m ()
+ Data.Graph.Immutable: with :: SomeGraph e v -> (forall g. Graph g e v -> a) -> a
+ Data.Graph.Mutable: insertEdge :: PrimMonad m => MGraph g (PrimState m) e v -> Vertex g -> Vertex g -> e -> m ()
+ Data.Graph.Mutable: insertEdgeWith :: PrimMonad m => MGraph g (PrimState m) e v -> (e -> e -> e) -> Vertex g -> Vertex g -> e -> m ()
+ Data.Graph.Mutable: insertVertex :: (PrimMonad m, Hashable v, Eq v) => MGraph g (PrimState m) e v -> v -> m (Vertex g)
+ Data.Graph.Mutable: verticesRead :: PrimMonad m => MVertices g (PrimState m) v -> Vertex g -> m v
+ Data.Graph.Mutable: verticesReplicate :: PrimMonad m => Size g -> v -> m (MVertices g (PrimState m) v)
+ Data.Graph.Mutable: verticesURead :: (PrimMonad m, Unbox v) => MUVertices g (PrimState m) v -> Vertex g -> m v
+ Data.Graph.Mutable: verticesUReplicate :: (PrimMonad m, Unbox v) => Size g -> v -> m (MUVertices g (PrimState m) v)
+ Data.Graph.Mutable: verticesUWrite :: (PrimMonad m, Unbox v) => MUVertices g (PrimState m) v -> Vertex g -> v -> m ()
+ Data.Graph.Mutable: verticesWrite :: PrimMonad m => MVertices g (PrimState m) v -> Vertex g -> v -> m ()
+ Data.Graph.Types: Graph :: SomeGraph e v -> Graph g e v
+ Data.Graph.Types: IntPair :: !Int -> !Int -> IntPair
+ Data.Graph.Types: MGraph :: !(HashTable s v Int) -> !(MutVar s Int) -> !(HashTable s IntPair e) -> MGraph g s e v
+ Data.Graph.Types: MUVertices :: MVector s v -> MUVertices g s v
+ Data.Graph.Types: MVertices :: MVector s v -> MVertices g s v
+ Data.Graph.Types: Size :: Int -> Size g
+ Data.Graph.Types: SomeGraph :: !(Vector v) -> !(Vector (Vector Int)) -> !(Vector (Vector e)) -> SomeGraph e v
+ Data.Graph.Types: Vertex :: Int -> Vertex g
+ Data.Graph.Types: Vertices :: Vector v -> Vertices g v
+ Data.Graph.Types: [getGraphInternal] :: Graph g e v -> SomeGraph e v
+ Data.Graph.Types: [getMUVerticesInternal] :: MUVertices g s v -> MVector s v
+ Data.Graph.Types: [getMVerticesInternal] :: MVertices g s v -> MVector s v
+ Data.Graph.Types: [getSizeInternal] :: Size g -> Int
+ Data.Graph.Types: [getVertexInternal] :: Vertex g -> Int
+ Data.Graph.Types: [getVerticesInternal] :: Vertices g v -> Vector v
+ Data.Graph.Types: [graphOutboundNeighborEdges] :: SomeGraph e v -> !(Vector (Vector e))
+ Data.Graph.Types: [graphOutboundNeighborVertices] :: SomeGraph e v -> !(Vector (Vector Int))
+ Data.Graph.Types: [graphVertices] :: SomeGraph e v -> !(Vector v)
+ Data.Graph.Types: [mgraphCurrentId] :: MGraph g s e v -> !(MutVar s Int)
+ Data.Graph.Types: [mgraphEdges] :: MGraph g s e v -> !(HashTable s IntPair e)
+ Data.Graph.Types: [mgraphVertexIndex] :: MGraph g s e v -> !(HashTable s v Int)
+ Data.Graph.Types: data IntPair
+ Data.Graph.Types: data MGraph g s e v
+ Data.Graph.Types: data SomeGraph e v
+ Data.Graph.Types: instance Data.Hashable.Class.Hashable (Data.Graph.Types.Vertex g)
+ Data.Graph.Types: instance Data.Hashable.Class.Hashable Data.Graph.Types.IntPair
+ Data.Graph.Types: instance GHC.Base.Functor (Data.Graph.Types.Graph g e)
+ Data.Graph.Types: instance GHC.Base.Functor (Data.Graph.Types.SomeGraph e)
+ Data.Graph.Types: instance GHC.Base.Functor (Data.Graph.Types.Vertices g)
+ Data.Graph.Types: instance GHC.Classes.Eq (Data.Graph.Types.Vertex g)
+ Data.Graph.Types: instance GHC.Classes.Eq Data.Graph.Types.IntPair
+ Data.Graph.Types: instance GHC.Classes.Ord (Data.Graph.Types.Vertex g)
+ Data.Graph.Types: instance GHC.Classes.Ord Data.Graph.Types.IntPair
+ Data.Graph.Types: instance GHC.Generics.Generic Data.Graph.Types.IntPair
+ Data.Graph.Types: instance GHC.Read.Read Data.Graph.Types.IntPair
+ Data.Graph.Types: instance GHC.Show.Show Data.Graph.Types.IntPair
+ Data.Graph.Types: newtype Graph g e v
+ Data.Graph.Types: newtype MUVertices g s v
+ Data.Graph.Types: newtype MVertices g s v
+ Data.Graph.Types: newtype Size g
+ Data.Graph.Types: newtype Vertex g
+ Data.Graph.Types: newtype Vertices g v
- Data.HashMap.Mutable.Basic: mapM_ :: PrimMonad m => ((k, v) -> m b) -> HashTable (PrimState m) k v -> m ()
+ Data.HashMap.Mutable.Basic: mapM_ :: PrimMonad m => (k -> v -> m b) -> HashTable (PrimState m) k v -> m ()
- Data.Heap.Mutable.ModelC: bubbleDown :: (Ord p, PrimMonad m) => RawHeap (PrimState m) p -> Int -> m ()
+ Data.Heap.Mutable.ModelC: bubbleDown :: forall p m. (Ord p, PrimMonad m) => RawHeap (PrimState m) p -> Int -> m ()
- Data.Heap.Mutable.ModelC: unsafePush :: (Ord p, Monoid p, PrimMonad m) => p -> Int -> Int -> RawHeap (PrimState m) p -> m Int
+ Data.Heap.Mutable.ModelC: unsafePush :: forall m p k. (Ord p, Monoid p, PrimMonad m) => p -> Int -> Int -> RawHeap (PrimState m) p -> m Int
Files
- cbits/Makefile +14/−0
- cbits/check.c +185/−0
- cbits/common.c +83/−0
- cbits/default.c +203/−0
- cbits/defs.h +35/−0
- cbits/sse-42-check.c +38/−0
- cbits/sse-42.c +172/−0
- impure-containers.cabal +64/−5
- src/Data/ArrayList/Generic.hs +41/−0
- src/Data/Graph/Immutable.hs +202/−3
- src/Data/Graph/Immutable/Tagged.hs +0/−120
- src/Data/Graph/Mutable.hs +62/−0
- src/Data/Graph/Types.hs +49/−0
- src/Data/HashMap/Mutable/Basic.hs +2/−2
- src/Data/Heap/Mutable/ModelC.hs +1/−1
- src/Lib.hs +0/−6
- test/Spec.hs +82/−2
+ cbits/Makefile view
@@ -0,0 +1,14 @@+check: default.c common.c check.c sse-42.c+ @echo "Testing portable version..."+ @gcc -o check -O3 default.c common.c check.c+ @./check+ @rm check++ @echo+ @echo "Testing SSE 4.2 version..."+ @gcc -o check -O3 -msse4.2 sse-42.c common.c check.c sse-42-check.c+ @./check+ @rm check++clean:+ rm -f *.o check
+ cbits/check.c view
@@ -0,0 +1,185 @@+#include <stdlib.h>+#include <stdio.h>+#include "defs.h"++static const int NUMH = 64 / sizeof(small_hash_t);++static small_hash_t t_sevens[32] =+ { 7,7,7,7,7,7,7,7,+ 7,7,7,7,7,7,7,7,+ 7,7,7,7,7,7,7,7,+ 7,7,7,7,7,7,7,7 };++static small_hash_t t_zeroes[32] =+ { 0,0,0,0,0,0,0,0,+ 0,0,0,0,0,0,0,0,+ 0,0,0,0,0,0,0,0,+ 0,0,0,0,0,0,0,0 };++static small_hash_t t_mixed[32] =+ { 7,1,7,7,2,7,7,7,+ 7,7,3,7,7,7,7,7,+ 7,7,7,7,1,7,7,7,+ 7,7,7,7,3,7,7,9 };++static int num_tests = 0;+static int num_errors = 0;++void CHECK(int actual, int expected, char* what) {+ ++num_tests;+ if (actual != expected) {+ fprintf(stderr, "%s: expected %d, got %d\n", what, expected, actual);++ ++num_errors;+ }+}+++void check_forward_search_2() {+ /* forward_search_2 */+ /* - offset zero */+ CHECK(forward_search_2(t_sevens, 0, NUMH, 0, 7 ), 0, "fs2-sevens-ok-1" );+ CHECK(forward_search_2(t_sevens, 0, NUMH, 7, 0 ), 0, "fs2-sevens-ok-2" );+ CHECK(forward_search_2(t_sevens, 0, NUMH, 7, 7 ), 0, "fs2-sevens-ok-3" );+ CHECK(forward_search_2(t_sevens, 0, NUMH, 3, 0 ), -1, "fs2-sevens-fail-1");+ CHECK(forward_search_2(t_zeroes, 0, NUMH, 0, 1 ), 0, "fs2-zeroes-ok-1" );+ CHECK(forward_search_2(t_zeroes, 0, NUMH, 2, 0 ), 0, "fs2-zeroes-ok-2" );+ CHECK(forward_search_2(t_zeroes, 0, NUMH, 2, 0xf0), -1, "fs2-zeroes-fail-1");++ /* - offset 5 */+ CHECK(forward_search_2(t_sevens, 5, NUMH, 0, 7), 5, "fs2-o-sevens-ok-1" );+ CHECK(forward_search_2(t_sevens, 5, NUMH, 7, 0), 5, "fs2-o-sevens-ok-2" );+ CHECK(forward_search_2(t_sevens, 5, NUMH, 7, 7), 5, "fs2-o-sevens-ok-3" );+ CHECK(forward_search_2(t_sevens, 5, NUMH, 3, 0), -1, "fs2-o-sevens-fail-1");+ CHECK(forward_search_2(t_zeroes, 5, NUMH, 0, 1), 5, "fs2-o-zeroes-ok-1" );+ CHECK(forward_search_2(t_zeroes, 5, NUMH, 2, 0), 5, "fs2-o-zeroes-ok-2" );+ CHECK(forward_search_2(t_zeroes, 5, NUMH, 2, 0xf0), -1, "fs2-o-zeroes-fail-1");++ /* - mixed, offset zero */+ CHECK(forward_search_2(t_mixed, 0, NUMH, 2, 0xf0), 4, "fs2-mixed-ok-1" );+ CHECK(forward_search_2(t_mixed, 0, NUMH, 4, 0xf0), -1, "fs2-mixed-fail-1");+ CHECK(forward_search_2(t_mixed, 0, NUMH, 2, 1), 1, "fs2-mixed-ok-2" );+ CHECK(forward_search_2(t_mixed, 0, NUMH, 2, 7), 0, "fs2-mixed-ok-3" );+ CHECK(forward_search_2(t_mixed, 0, NUMH, 2, 3), 4, "fs2-mixed-ok-4" );+ CHECK(forward_search_2(t_mixed, 0, NUMH, 9, 3), 10, "fs2-mixed-ok-5" );+ CHECK(forward_search_2(t_mixed, 0, NUMH, 3, 9), 10, "fs2-mixed-ok-5" );+ CHECK(forward_search_2(t_mixed, 0, NUMH, 8, 9), 31, "fs2-mixed-ok-6" );++ /* - mixed, offset 16 */+ CHECK(forward_search_2(t_mixed, 16, NUMH, 2, 0xf0), 4, "fs2-o-mixed-ok-1" );+ CHECK(forward_search_2(t_mixed, 16, NUMH, 4, 0xf0), -1, "fs2-o-mixed-fail-1");+ CHECK(forward_search_2(t_mixed, 16, NUMH, 2, 1), 20, "fs2-o-mixed-ok-2" );+ CHECK(forward_search_2(t_mixed, 16, NUMH, 2, 7), 16, "fs2-o-mixed-ok-3" );+ CHECK(forward_search_2(t_mixed, 16, NUMH, 2, 3), 28, "fs2-o-mixed-ok-4" );+ CHECK(forward_search_2(t_mixed, 16, NUMH, 9, 3), 28, "fs2-o-mixed-ok-5" );+ CHECK(forward_search_2(t_mixed, 16, NUMH, 3, 9), 28, "fs2-o-mixed-ok-5" );+ CHECK(forward_search_2(t_mixed, 16, NUMH, 8, 9), 31, "fs2-o-mixed-ok-6" );+}++void check_forward_search_3() {+ /* forward_search_3 */+ /* - offset zero */+ CHECK(forward_search_3(t_sevens, 0, NUMH, 0, 7, 88), 0, "fs3-sevens-ok-1" );+ CHECK(forward_search_3(t_sevens, 0, NUMH, 7, 0, 88), 0, "fs3-sevens-ok-2" );+ CHECK(forward_search_3(t_sevens, 0, NUMH, 7, 7, 88), 0, "fs3-sevens-ok-3" );+ CHECK(forward_search_3(t_sevens, 0, NUMH, 3, 0, 88), -1, "fs3-sevens-fail-1");+ CHECK(forward_search_3(t_zeroes, 0, NUMH, 0, 1, 88), 0, "fs3-zeroes-ok-1" );+ CHECK(forward_search_3(t_zeroes, 0, NUMH, 2, 0, 88), 0, "fs3-zeroes-ok-2" );+ CHECK(forward_search_3(t_zeroes, 0, NUMH, 2, 11, 0 ), 0, "fs3-zeroes-ok-3" );+ CHECK(forward_search_3(t_zeroes, 0, NUMH, 2, 32, 88), -1, "fs3-zeroes-fail-1");++ /* - offset 5 */+ CHECK(forward_search_3(t_sevens, 5, NUMH, 0, 7, 7 ), 5, "fs3-o-sevens-ok-1" );+ CHECK(forward_search_3(t_sevens, 5, NUMH, 7, 0, 21), 5, "fs3-o-sevens-ok-2" );+ CHECK(forward_search_3(t_sevens, 5, NUMH, 7, 7, 21), 5, "fs3-o-sevens-ok-3" );+ CHECK(forward_search_3(t_sevens, 5, NUMH, 3, 0, 21), -1, "fs3-o-sevens-fail-1");+ CHECK(forward_search_3(t_zeroes, 5, NUMH, 0, 1, 21), 5, "fs3-o-zeroes-ok-1" );+ CHECK(forward_search_3(t_zeroes, 5, NUMH, 2, 0, 21), 5, "fs3-o-zeroes-ok-2" );+ CHECK(forward_search_3(t_zeroes, 5, NUMH, 2, 0xf0, 21), -1, "fs3-o-zeroes-fail-1");++ /* - mixed, offset zero */+ CHECK(forward_search_3(t_mixed, 0, NUMH, 2, 0xf0, -1), 4, "fs3-mixed-ok-1" );+ CHECK(forward_search_3(t_mixed, 0, NUMH, 4, 0xf0, -1), -1, "fs3-mixed-fail-1");+ CHECK(forward_search_3(t_mixed, 0, NUMH, 2, 1, -1), 1, "fs3-mixed-ok-2" );+ CHECK(forward_search_3(t_mixed, 0, NUMH, 2, 7, -1), 0, "fs3-mixed-ok-3" );+ CHECK(forward_search_3(t_mixed, 0, NUMH, 2, 3, -1), 4, "fs3-mixed-ok-4" );+ CHECK(forward_search_3(t_mixed, 0, NUMH, 9, 3, -1), 10, "fs3-mixed-ok-5" );+ CHECK(forward_search_3(t_mixed, 0, NUMH, 3, 9, -1), 10, "fs3-mixed-ok-5" );+ CHECK(forward_search_3(t_mixed, 0, NUMH, 8, 9, -1), 31, "fs3-mixed-ok-6" );++ /* - mixed, offset 16 */+ CHECK(forward_search_3(t_mixed, 16, NUMH, 2, 96, 33), 4, "fs3-o-mixed-ok-1" );+ CHECK(forward_search_3(t_mixed, 16, NUMH, 4, 96, 33), -1, "fs3-o-mixed-fail-1");+ CHECK(forward_search_3(t_mixed, 16, NUMH, 2, 1, 33), 20, "fs3-o-mixed-ok-2" );+ CHECK(forward_search_3(t_mixed, 16, NUMH, 2, 7, 33), 16, "fs3-o-mixed-ok-3" );+ CHECK(forward_search_3(t_mixed, 16, NUMH, 2, 3, 33), 28, "fs3-o-mixed-ok-4" );+ CHECK(forward_search_3(t_mixed, 16, NUMH, 9, 3, 33), 28, "fs3-o-mixed-ok-5" );+ CHECK(forward_search_3(t_mixed, 16, NUMH, 3, 9, 33), 28, "fs3-o-mixed-ok-5" );+ CHECK(forward_search_3(t_mixed, 16, NUMH, 8, 9, 33), 31, "fs3-o-mixed-ok-6" );+ CHECK(forward_search_3(t_mixed, 16, NUMH, 8, 33, 9 ), 31, "fs3-o-mixed-ok-7" );+}++void check_line_search() {+ CHECK(line_search(t_sevens, 0, 7), 0, "ls-7s-ok-1");+ CHECK(line_search(t_sevens, 5, 7), 5, "ls-7s-ok-2");+ CHECK(line_search(t_sevens, 31, 7), 31, "ls-7s-ok-3");+ CHECK(line_search(t_sevens, 0, 1), -1, "ls-7s-fail-1");+ CHECK(line_search(t_sevens, 31, 1), -1, "ls-7s-fail-2");++ CHECK(line_search(t_mixed, 0, 7), 0, "ls-m-ok-1");+ CHECK(line_search(t_mixed, 0, 1), 1, "ls-m-ok-2");+ CHECK(line_search(t_mixed, 1, 7), 2, "ls-m-ok-3");+ CHECK(line_search(t_mixed, 0, 9), 31, "ls-m-ok-4");+ CHECK(line_search(t_mixed, 0, 8), -1, "ls-m-fail-1");++ CHECK(line_search(t_mixed, 16, 1), 20, "ls-m-ok-5");+}++void check_line_search_2() {+ CHECK(line_search_2(t_sevens, 0, 7, 3), 0, "ls2-7s-ok-1");+ CHECK(line_search_2(t_sevens, 5, 7, 9), 5, "ls2-7s-ok-2");+ CHECK(line_search_2(t_sevens, 31, 0, 7), 31, "ls2-7s-ok-3");+ CHECK(line_search_2(t_sevens, 0, 1, 3), -1, "ls2-7s-fail-1");+ CHECK(line_search_2(t_sevens, 31, 6, 1), -1, "ls2-7s-fail-2");++ CHECK(line_search_2(t_mixed, 0, 7, 9), 0, "ls2-m-ok-1");+ CHECK(line_search_2(t_mixed, 0, 9, 1), 1, "ls2-m-ok-2");+ CHECK(line_search_2(t_mixed, 1, 7, 9), 2, "ls2-m-ok-3");+ CHECK(line_search_2(t_mixed, 0, 8, 9), 31, "ls2-m-ok-4");+ CHECK(line_search_2(t_mixed, 0, 8, 4), -1, "ls2-m-fail-1");++ CHECK(line_search_2(t_mixed, 16, 3, 1), 20, "ls2-m-ok-5");+}++void check_line_search_3() {+ CHECK(line_search_3(t_sevens, 0, 4, 7, 3), 0, "ls2-7s-ok-1");+ CHECK(line_search_3(t_sevens, 5, 7, 4, 9), 5, "ls2-7s-ok-2");+ CHECK(line_search_3(t_sevens, 31, 0, 7, 4), 31, "ls2-7s-ok-3");+ CHECK(line_search_3(t_sevens, 0, 1, 4, 3), -1, "ls2-7s-fail-1");+ CHECK(line_search_3(t_sevens, 31, 4, 6, 1), -1, "ls2-7s-fail-2");++ CHECK(line_search_3(t_mixed, 0, 4, 7, 9), 0, "ls2-m-ok-1");+ CHECK(line_search_3(t_mixed, 0, 9, 4, 1), 1, "ls2-m-ok-2");+ CHECK(line_search_3(t_mixed, 1, 7, 9, 4), 2, "ls2-m-ok-3");+ CHECK(line_search_3(t_mixed, 0, 8, 4, 9), 31, "ls2-m-ok-4");+ CHECK(line_search_3(t_mixed, 0, 8, 4, 6), -1, "ls2-m-fail-1");++ CHECK(line_search_3(t_mixed, 16, 3, 1, 6), 20, "ls2-m-ok-5");+}+++int main() {+ check_forward_search_2();+ check_forward_search_3();+ check_line_search();+ check_line_search_2();+ check_line_search_3();+ check_impl_specific();++ if (num_errors > 0) {+ printf("\n*** %d/%d tests failed.\n", num_errors, num_tests);+ } else {+ printf("All %d tests passed.\n", num_tests);+ }+ exit(num_errors < 255 ? num_errors : 255);+}
+ cbits/common.c view
@@ -0,0 +1,83 @@+#include "defs.h"++#ifdef WIN32+#include <windows.h>+#else+#include <signal.h>+#include <unistd.h>+#endif++#include <stdio.h>++void suicide(volatile int* check, int t) {+ int secs = (3*t + 999999) / 1000000;+ if (secs < 1) secs = 1;+#ifdef WIN32+ Sleep(secs * 1000);+#else+ sleep(secs);+#endif+ if (*check) {+ printf("timeout expired, dying!!\n");+#ifdef WIN32+ abort();+#else+ raise(SIGKILL);+#endif+ }+}++#if defined(__GNUC__)+#define PREFETCH_READ(x) (__builtin_prefetch(x, 0, 3))+#define PREFETCH_WRITE(x) (__builtin_prefetch(x, 1, 3))+#else+#define PREFETCH_READ(x)+#define PREFETCH_WRITE(x)+#endif++void prefetch_cacheline_read(small_hash_t* line, int start)+{+ PREFETCH_READ((void*)(&line[start]));+}++void prefetch_cacheline_write(small_hash_t* line, int start)+{+ PREFETCH_WRITE((void*)(&line[start]));+}++int forward_search_2(small_hash_t* array, int start, int end,+ small_hash_t x1, small_hash_t x2) {+ small_hash_t* ep = array + end;+ small_hash_t* p = array + start;+ int wrapped = 0;+ while (1) {+ if (p >= ep) {+ if (wrapped) return -1;+ ep = array + start;+ p = array;+ wrapped = 1;+ continue;+ }+ if (*p == x1 || *p == x2) return p - array;+ ++p;+ }+}++int forward_search_3(small_hash_t* array, int start, int end,+ small_hash_t x1, small_hash_t x2, small_hash_t x3) {+ small_hash_t* ep = array + end;+ small_hash_t* p = array + start;+ int wrapped = 0;+ while (1) {+ if (p >= ep) {+ if (wrapped) return -1;+ ep = array + start;+ p = array;+ wrapped = 1;+ continue;+ }+ if (*p == x1 || *p == x2 || *p == x3) return p - array;+ ++p;+ }+}+
+ cbits/default.c view
@@ -0,0 +1,203 @@+// Specialized i686 versions of the cache line search functions.++#include "defs.h"++static inline int32_t mask(int32_t a, int32_t b) { return -(a == b); }++#if defined(__GNUC__)+static inline int32_t first_bit_set(int32_t a) {+ return __builtin_ffs(a) - 1;+}+#else+static uint8_t de_bruijn_table[] = {+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9+};++static inline int32_t first_bit_set(int32_t a) {+ int32_t zero_case = mask(0, a);+ uint32_t x = (uint32_t) (a & -a);+ x *= 0x077CB531;+ x >>= 27;+ return zero_case | de_bruijn_table[x];+}+#endif++static inline uint32_t line_mask(small_hash_t* array, int start,+ small_hash_t x1) {+ small_hash_t* p = array + start;+ uint32_t m1 = 0;+ uint32_t m2 = 0;+ uint32_t m3 = 0;+ int offset = start & 0x1f;++#define M (mask(*p, x1))++ switch (offset) {+ case 0: m1 |= M & 0x1; ++p;+ case 1: m2 |= M & 0x2; ++p;+ case 2: m3 |= M & 0x4; ++p;+ case 3: m1 |= M & 0x8; ++p;+ case 4: m2 |= M & 0x10; ++p;+ case 5: m3 |= M & 0x20; ++p;+ case 6: m1 |= M & 0x40; ++p;+ case 7: m2 |= M & 0x80; ++p;+ case 8: m3 |= M & 0x100; ++p;+ case 9: m1 |= M & 0x200; ++p;+ case 10: m2 |= M & 0x400; ++p;+ case 11: m3 |= M & 0x800; ++p;+ case 12: m1 |= M & 0x1000; ++p;+ case 13: m2 |= M & 0x2000; ++p;+ case 14: m3 |= M & 0x4000; ++p;+ case 15: m1 |= M & 0x8000; ++p;+ case 16: m2 |= M & 0x10000; ++p;+ case 17: m3 |= M & 0x20000; ++p;+ case 18: m1 |= M & 0x40000; ++p;+ case 19: m2 |= M & 0x80000; ++p;+ case 20: m3 |= M & 0x100000; ++p;+ case 21: m1 |= M & 0x200000; ++p;+ case 22: m2 |= M & 0x400000; ++p;+ case 23: m3 |= M & 0x800000; ++p;+ case 24: m1 |= M & 0x1000000; ++p;+ case 25: m2 |= M & 0x2000000; ++p;+ case 26: m3 |= M & 0x4000000; ++p;+ case 27: m1 |= M & 0x8000000; ++p;+ case 28: m2 |= M & 0x10000000; ++p;+ case 29: m3 |= M & 0x20000000; ++p;+ case 30: m1 |= M & 0x40000000; ++p;+ case 31: m2 |= M & 0x80000000; ++p;+ }++#undef M++ return (m1 | m2 | m3) >> offset;+}++static inline uint32_t line_mask_2(small_hash_t* array, int start,+ small_hash_t x1, small_hash_t x2) {+ small_hash_t* p = array + start;+ uint32_t m1 = 0;+ uint32_t m2 = 0;+ uint32_t m3 = 0;+ int offset = start & 0x1f;++#define M (mask(*p, x1) | mask(*p, x2))++ switch (offset) {+ case 0: m1 |= M & 0x1; ++p;+ case 1: m2 |= M & 0x2; ++p;+ case 2: m3 |= M & 0x4; ++p;+ case 3: m1 |= M & 0x8; ++p;+ case 4: m2 |= M & 0x10; ++p;+ case 5: m3 |= M & 0x20; ++p;+ case 6: m1 |= M & 0x40; ++p;+ case 7: m2 |= M & 0x80; ++p;+ case 8: m3 |= M & 0x100; ++p;+ case 9: m1 |= M & 0x200; ++p;+ case 10: m2 |= M & 0x400; ++p;+ case 11: m3 |= M & 0x800; ++p;+ case 12: m1 |= M & 0x1000; ++p;+ case 13: m2 |= M & 0x2000; ++p;+ case 14: m3 |= M & 0x4000; ++p;+ case 15: m1 |= M & 0x8000; ++p;+ case 16: m2 |= M & 0x10000; ++p;+ case 17: m3 |= M & 0x20000; ++p;+ case 18: m1 |= M & 0x40000; ++p;+ case 19: m2 |= M & 0x80000; ++p;+ case 20: m3 |= M & 0x100000; ++p;+ case 21: m1 |= M & 0x200000; ++p;+ case 22: m2 |= M & 0x400000; ++p;+ case 23: m3 |= M & 0x800000; ++p;+ case 24: m1 |= M & 0x1000000; ++p;+ case 25: m2 |= M & 0x2000000; ++p;+ case 26: m3 |= M & 0x4000000; ++p;+ case 27: m1 |= M & 0x8000000; ++p;+ case 28: m2 |= M & 0x10000000; ++p;+ case 29: m3 |= M & 0x20000000; ++p;+ case 30: m1 |= M & 0x40000000; ++p;+ case 31: m2 |= M & 0x80000000; ++p;+ }++#undef M++ return (m1 | m2 | m3) >> offset;+}++static inline uint32_t line_mask_3(small_hash_t* array, int start,+ small_hash_t x1, small_hash_t x2,+ small_hash_t x3) {+ small_hash_t* p = array + start;+ uint32_t m1 = 0;+ uint32_t m2 = 0;+ uint32_t m3 = 0;+ int offset = start & 0x1f;++#define M (mask(*p, x1) | mask(*p, x2) | mask(*p, x3))++ switch (offset) {+ case 0: m1 |= M & 0x1; ++p;+ case 1: m2 |= M & 0x2; ++p;+ case 2: m3 |= M & 0x4; ++p;+ case 3: m1 |= M & 0x8; ++p;+ case 4: m2 |= M & 0x10; ++p;+ case 5: m3 |= M & 0x20; ++p;+ case 6: m1 |= M & 0x40; ++p;+ case 7: m2 |= M & 0x80; ++p;+ case 8: m3 |= M & 0x100; ++p;+ case 9: m1 |= M & 0x200; ++p;+ case 10: m2 |= M & 0x400; ++p;+ case 11: m3 |= M & 0x800; ++p;+ case 12: m1 |= M & 0x1000; ++p;+ case 13: m2 |= M & 0x2000; ++p;+ case 14: m3 |= M & 0x4000; ++p;+ case 15: m1 |= M & 0x8000; ++p;+ case 16: m2 |= M & 0x10000; ++p;+ case 17: m3 |= M & 0x20000; ++p;+ case 18: m1 |= M & 0x40000; ++p;+ case 19: m2 |= M & 0x80000; ++p;+ case 20: m3 |= M & 0x100000; ++p;+ case 21: m1 |= M & 0x200000; ++p;+ case 22: m2 |= M & 0x400000; ++p;+ case 23: m3 |= M & 0x800000; ++p;+ case 24: m1 |= M & 0x1000000; ++p;+ case 25: m2 |= M & 0x2000000; ++p;+ case 26: m3 |= M & 0x4000000; ++p;+ case 27: m1 |= M & 0x8000000; ++p;+ case 28: m2 |= M & 0x10000000; ++p;+ case 29: m3 |= M & 0x20000000; ++p;+ case 30: m1 |= M & 0x40000000; ++p;+ case 31: m2 |= M & 0x80000000; ++p;+ }+#undef M++ return (m1 | m2 | m3) >> offset;+}+++static inline int32_t line_result(uint32_t m, int start) {+ int32_t p = first_bit_set((int32_t) m);+ int32_t mm = mask(p, -1);+ return mm | (start + p);+}+++int line_search(small_hash_t* array, int start, small_hash_t x1) {+ uint32_t m = line_mask(array, start, x1);+ return line_result(m, start);+}++int line_search_2(small_hash_t* array, int start, small_hash_t x1,+ small_hash_t x2) {+ uint32_t m = line_mask_2(array, start, x1, x2);+ return line_result(m, start);+}++int line_search_3(small_hash_t* array, int start, small_hash_t x1,+ small_hash_t x2, small_hash_t x3) {+ uint32_t m = line_mask_3(array, start, x1, x2, x3);+ return line_result(m, start);+}++void check_impl_specific(int* num_tests, int* num_errors) {++}
+ cbits/defs.h view
@@ -0,0 +1,35 @@+#ifndef HASHTABLES_DEFS_H+#define HASHTABLES_DEFS_H++#include <stdint.h>+#include <strings.h>++typedef uintptr_t full_hash_t;+typedef uint16_t small_hash_t;++void prefetch_cacheline_write(small_hash_t* line, int start);+void prefetch_cacheline_read(small_hash_t* line, int start);++int forward_search_2(small_hash_t* array,+ int start,+ int end,+ small_hash_t x1,+ small_hash_t x2);+int forward_search_3(small_hash_t* array,+ int start,+ int end,+ small_hash_t x1,+ small_hash_t x2,+ small_hash_t x3);++int line_search(small_hash_t* array, int start, small_hash_t x1);+int line_search_2(small_hash_t* array, int start, small_hash_t x1,+ small_hash_t x2);+int line_search_3(small_hash_t* array, int start, small_hash_t x1,+ small_hash_t x2, small_hash_t x3);+void suicide(volatile int* check, int i);++void CHECK(int actual, int expected, char* what);+void check_impl_specific();++#endif /* HASHTABLES_DEFS_H */
+ cbits/sse-42-check.c view
@@ -0,0 +1,38 @@+#include "defs.h"++#include <smmintrin.h>+#include <stdio.h>++extern __m128i fill(small_hash_t v);++static void check_fill(small_hash_t v) {+ int i;+ char buf[256];+ small_hash_t v2;++ __m128i x = fill(v);++#define F(i) do { \+ v2 = _mm_extract_epi16(x, i); \+ sprintf(buf, "fill-%x-%d-of-8", (int) v, i+1); \+ CHECK(v2, v, buf); \+ } while(0);++ F(0);+ F(1);+ F(2);+ F(3);+ F(4);+ F(5);+ F(6);+ F(7);+#undef F+}++void check_impl_specific() {+ check_fill(0);+ check_fill((small_hash_t) (-1));+ check_fill((small_hash_t) (-5));+ check_fill(7);+ check_fill(0xff);+}
+ cbits/sse-42.c view
@@ -0,0 +1,172 @@+#include "defs.h"++#include <smmintrin.h>+#include <stdio.h>++/* Straight-line branchless SSE 4.2 code for searching an array of uint16_t+ hash codes. */++static inline int32_t mask(int32_t a, int32_t b) { return -(a == b); }++#if defined(__GNUC__)+static inline int32_t first_bit_set(int32_t a) {+ return __builtin_ffs(a) - 1;+}+#else+static uint8_t de_bruijn_table[] = {+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9+};++static inline int32_t first_bit_set(int32_t a) {+ int32_t zero_case = mask(0, a);+ uint32_t x = (uint32_t) (a & -a);+ x *= 0x077CB531;+ x >>= 27;+ return zero_case | de_bruijn_table[x];+}+#endif++static inline __m128i fill(small_hash_t v) {+ int32_t v1 = (((int)v) << 16) | v;+ __m128i x = _mm_cvtsi32_si128(0);+ x = _mm_insert_epi32(x, v1, 0);+ return _mm_shuffle_epi32(x, _MM_SHUFFLE(0,0,0,0));+}++#ifndef SIDD_UWORD_OPS+#define SIDD_UWORD_OPS _SIDD_UWORD_OPS+#endif++#ifndef SIDD_CMP_EQUAL_EACH+#define SIDD_CMP_EQUAL_EACH _SIDD_CMP_EQUAL_EACH+#endif++#ifndef SIDD_BIT_MASK+#define SIDD_BIT_MASK _SIDD_BIT_MASK+#endif++#define _MODE (SIDD_UWORD_OPS | SIDD_CMP_EQUAL_EACH)++static inline __m128i cmp_mask(__m128i a, __m128i b) {+ const int mode = SIDD_UWORD_OPS | SIDD_CMP_EQUAL_EACH | SIDD_BIT_MASK;+ return _mm_cmpistrm(a, b, mode);+}++static inline int32_t line_result(uint32_t m, int start) {+ int32_t p = first_bit_set((int32_t) m);+ int32_t mm = mask(p, -1);+ return mm | (start + p);+}++#define DUMP(xval) do { \+ uint16_t xval##_x0 = _mm_extract_epi16(xval, 0); \+ uint16_t xval##_x1 = _mm_extract_epi16(xval, 1); \+ uint16_t xval##_x2 = _mm_extract_epi16(xval, 2); \+ uint16_t xval##_x3 = _mm_extract_epi16(xval, 3); \+ uint16_t xval##_x4 = _mm_extract_epi16(xval, 4); \+ uint16_t xval##_x5 = _mm_extract_epi16(xval, 5); \+ uint16_t xval##_x6 = _mm_extract_epi16(xval, 6); \+ uint16_t xval##_x7 = _mm_extract_epi16(xval, 7); \+ printf(" % 10s: %04x-%04x-%04x-%04x-%04x-%04x-%04x-%04x\n", \+ #xval, xval##_x0, xval##_x1, xval##_x2, xval##_x3, \+ xval##_x4, xval##_x5, xval##_x6, xval##_x7); \+ } while(0);+++int line_search(small_hash_t* array, int start0, small_hash_t v1) {+ int offset = start0 & 31;+ int start = start0 & ~31;+ __m128i* p = (__m128i*) &array[start];+ __m128i x1, val1, val2, val3, val4;+ __m128i m1, m2, m3, m4, dmask;++ x1 = fill(v1);++ val1 = *p++;+ m1 = cmp_mask(x1, val1);+ val2 = *p++;+ m2 = _mm_slli_si128(cmp_mask(x1, val2), 1);+ val3 = *p++;+ m3 = _mm_slli_si128(cmp_mask(x1, val3), 2);+ val4 = *p;+ m4 = _mm_slli_si128(cmp_mask(x1, val4), 3);++ dmask = _mm_or_si128(_mm_or_si128(m1, m2),+ _mm_or_si128(m3, m4));+ uint32_t imask = _mm_extract_epi32(dmask, 0);++ const uint32_t p2 = 1 << offset;+ const uint32_t dest_mask = imask & ~(p2 - 1);++ return line_result(dest_mask, start);+}++int line_search_2(small_hash_t* array, int start0, small_hash_t v1,+ small_hash_t v2) {+ int offset = start0 & 31;+ int start = start0 & ~31;+ __m128i* p = (__m128i*) &array[start];+ __m128i x1, x2, val1, val2, val3, val4;+ __m128i m1, m2, m3, m4, dmask;++ x1 = fill(v1);+ x2 = fill(v2);++#define M(v) _mm_or_si128(cmp_mask(x1,(v)), \+ cmp_mask(x2,(v)))+ val1 = *p++;+ m1 = M(val1);+ val2 = *p++;+ m2 = _mm_slli_si128(M(val2), 1);+ val3 = *p++;+ m3 = _mm_slli_si128(M(val3), 2);+ val4 = *p;+ m4 = _mm_slli_si128(M(val4), 3);+#undef M++ dmask = _mm_or_si128(_mm_or_si128(m1, m2),+ _mm_or_si128(m3, m4));+ uint32_t imask = _mm_extract_epi32(dmask, 0);++ const uint32_t p2 = 1 << offset;+ const uint32_t dest_mask = imask & ~(p2 - 1);++ return line_result(dest_mask, start);+}++int line_search_3(small_hash_t* array, int start0, small_hash_t v1,+ small_hash_t v2, small_hash_t v3) {+ int offset = start0 & 31;+ int start = start0 & ~31;+ __m128i* p = (__m128i*) &array[start];+ __m128i x1, x2, x3, val1, val2, val3, val4;+ __m128i m1, m2, m3, m4, dmask;++ x1 = fill(v1);+ x2 = fill(v2);+ x3 = fill(v3);++#define M(v) _mm_or_si128( \+ cmp_mask(x1,(v)), \+ _mm_or_si128(cmp_mask(x2,(v)), \+ cmp_mask(x3,(v))))+ val1 = *p++;+ m1 = M(val1);+ val2 = *p++;+ m2 = _mm_slli_si128(M(val2), 1);+ val3 = *p++;+ m3 = _mm_slli_si128(M(val3), 2);+ val4 = *p;+ m4 = _mm_slli_si128(M(val4), 3);+#undef M++ dmask = _mm_or_si128(_mm_or_si128(m1, m2),+ _mm_or_si128(m3, m4));+ uint32_t imask = _mm_extract_epi32(dmask, 0);++ const uint32_t p2 = 1 << offset;+ const uint32_t dest_mask = imask & ~(p2 - 1);++ return line_result(dest_mask, start);+}
impure-containers.cabal view
@@ -1,6 +1,6 @@ name: impure-containers-version: 0.1.1-synopsis: Initial project template from stack+version: 0.2+synopsis: Mutable containers in haskell description: Please see README.md homepage: https://github.com/andrewthad/impure-containers#readme license: BSD3@@ -10,13 +10,16 @@ copyright: 2016 Andrew Martin category: web build-type: Simple--- extra-source-files: cabal-version: >=1.10+extra-source-files:+ cbits/Makefile+ , cbits/check.c+ , cbits/defs.h+ , cbits/sse-42-check.c library hs-source-dirs: src exposed-modules:- Lib Data.HashMap.Mutable.Basic -- Data.Heap.Mutable.ModelA -- Data.Heap.Mutable.ModelB@@ -24,7 +27,9 @@ Data.Heap.Mutable.ModelD -- Data.Vector.Unique Data.Graph.Immutable- Data.Graph.Immutable.Tagged+ Data.Graph.Mutable+ Data.ArrayList.Generic+ Data.Graph.Types other-modules: Data.HashMap.Mutable.Internal.Array Data.HashMap.Mutable.Internal.CacheLine@@ -42,6 +47,59 @@ , ghc-prim default-language: Haskell2010 + if flag(sse42) && !flag(portable)+ cc-options: -DUSE_SSE_4_2 -msse4.2+ cpp-options: -DUSE_SSE_4_2+ C-sources: cbits/sse-42.c++ if !flag(portable) && !flag(sse42)+ C-sources: cbits/default.c++ if !flag(portable)+ C-sources: cbits/common.c++ if flag(portable)+ cpp-options: -DNO_C_SEARCH -DPORTABLE++ if !flag(portable) && flag(unsafe-tricks) && impl(ghc)+ build-depends: ghc-prim+ cpp-options: -DUNSAFETRICKS++ if flag(debug)+ cpp-options: -DDEBUG++ if flag(bounds-checking)+ cpp-options: -DBOUNDS_CHECKING++ -- ghc-prof-options: -prof -auto-all++ if impl(ghc >= 6.12.0)+ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2+ -fno-warn-unused-do-bind+ else+ ghc-options: -Wall -fwarn-tabs -funbox-strict-fields -O2++Flag unsafe-tricks+ Description: turn on unsafe GHC tricks+ Default: True++Flag bounds-checking+ Description: if on, use bounds-checking array accesses+ Default: False++Flag debug+ Description: if on, spew debugging output to stdout+ Default: False++Flag sse42+ Description: if on, use SSE 4.2 extensions to search cache lines very+ efficiently. The portable flag forces this off.+ Default: False++Flag portable+ Description: if on, use only pure Haskell code and no GHC extensions.+ Default: False+ test-suite impure-containers-test type: exitcode-stdio-1.0 hs-source-dirs: test@@ -55,6 +113,7 @@ , QuickCheck , HUnit , test-framework-hunit+ , vector ghc-options: -threaded -rtsopts -with-rtsopts=-N default-language: Haskell2010
+ src/Data/ArrayList/Generic.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE BangPatterns #-}++module Data.ArrayList.Generic where++import Control.Monad.Primitive+import Data.Vector.Generic.Mutable (MVector)+import Data.Vector.Generic (Vector, Mutable)+import Data.Primitive.MutVar+import qualified Data.Vector.Generic.Mutable as GM+import qualified Data.Vector.Generic as GV++data ArrayList v s a = ArrayList+ { arrayListSize :: !(MutVar s Int)+ , arrayListVector :: !(MutVar s (v s a))+ }++new :: (PrimMonad m, MVector v a) => Int -> m (ArrayList v (PrimState m) a)+new len = ArrayList <$> newMutVar 0 <*> (newMutVar =<< GM.new len)++-- | Append an element to the end of the 'ArrayList'.+push :: (PrimMonad m, MVector v a) => ArrayList v (PrimState m) a -> a -> m ()+push (ArrayList sizeRef mvecRef) a = do+ !size <- readMutVar sizeRef+ !mvec <- readMutVar mvecRef+ let !newSize = size + 1+ vlen = GM.length mvec+ writeMutVar sizeRef newSize+ if size < vlen+ then GM.unsafeWrite mvec size a+ else do+ newMVec <- GM.unsafeGrow mvec size+ GM.unsafeWrite newMVec size a+ writeMutVar mvecRef newMVec++freeze :: (PrimMonad m, Vector v a) => ArrayList (Mutable v) (PrimState m) a -> m (v a)+freeze (ArrayList sizeRef mvecRef) = do+ !size <- readMutVar sizeRef+ !mvec <- readMutVar mvecRef+ let sizedMVec = GM.unsafeTake size mvec+ GV.freeze sizedMVec+
src/Data/Graph/Immutable.hs view
@@ -1,9 +1,208 @@-{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE RankNTypes #-} module Data.Graph.Immutable where -import Data.Graph.Immutable.Tagged+import Data.Graph.Types+import Control.Monad.Primitive+import Data.Vector (Vector)+import Data.Vector.Mutable (MVector)+import Control.Monad+import Data.Word+import Control.Monad.ST (runST)+import Data.Primitive.MutVar+import qualified Data.Graph.Mutable as Mutable+import qualified Data.ArrayList.Generic as ArrayList+import qualified Data.HashMap.Mutable.Basic as HashTable+import qualified Data.Heap.Mutable.ModelD as Heap+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as MV+import qualified Data.Vector.Unboxed as U+import qualified Data.Vector.Unboxed.Mutable as MU -data SomeGraph e v = forall g. SomeGraph { getSomeGraph :: Graph g e v }+mapVertices :: (v -> w) -> Graph g e v -> Graph g e w+mapVertices = fmap +dijkstra :: (Ord s, Monoid s)+ => (v -> v -> s -> e -> s)+ -> s -- ^ Weight to assign start vertex+ -> Vertex g -- ^ start+ -> Vertex g -- ^ end+ -> Graph g e v+ -> s+dijkstra f s start end g =+ verticesRead (dijkstraTraversal f s start g) end +-- | This is a generalization of Dijkstra\'s algorithm. This function could+-- be written without unsafely pattern matching on 'Vertex', but doing+-- so allows us to use a faster heap implementation.+dijkstraTraversal ::+ (Ord s, Monoid s)+ => (v -> v -> s -> e -> s) -- ^ Weight combining function+ -> s -- ^ Weight to assign start vertex+ -> Vertex g -- ^ Start vertex+ -> Graph g e v+ -> Vertices g s+dijkstraTraversal f s0 v0 g = runST $ do+ let theSize = size g+ oldVertices = vertices g+ newVertices <- Mutable.verticesReplicate theSize mempty+ Mutable.verticesWrite newVertices v0 s0+ visited <- Mutable.verticesUReplicate theSize False+ heap <- Heap.new (unSize theSize)+ -- Using getVertex casts Vertex to Int. This is safe to do,+ -- but going from Int to Vertex (done later) is normally unsafe.+ -- We know it's ok in this case because the min heap does not+ -- create Ints that we did not push onto it.+ Heap.unsafePush s0 (getVertexInternal v0) heap+ let go = do+ m <- Heap.pop heap+ case m of+ Nothing -> return True+ Just (s,unwrappedVertexIx) -> do+ -- Unsafe cast from Int to Vertex+ let vertex = Vertex unwrappedVertexIx+ value = verticesRead oldVertices vertex+ Mutable.verticesUWrite visited vertex True+ Mutable.verticesWrite newVertices vertex s+ traverseNeighbors_ (\theEdge neighborVertex neighborValue -> do+ alreadyVisited <- Mutable.verticesURead visited neighborVertex+ when (not alreadyVisited) $ Heap.unsafePush+ (f value neighborValue s theEdge)+ -- Casting from Vertex to Int+ (getVertexInternal neighborVertex)+ heap+ ) vertex g+ return False+ runMe = do+ isDone <- go+ if isDone then return () else runMe+ runMe+ newVerticesFrozen <- verticesFreeze newVertices+ return newVerticesFrozen++lookupVertex :: Eq v => v -> Graph g e v -> Maybe (Vertex g)+lookupVertex val (Graph g) = fmap Vertex (V.elemIndex val (graphVertices g))++traverseNeighbors_ :: Applicative m+ => (e -> Vertex g -> v -> m a)+ -> Vertex g+ -> Graph g e v+ -> m ()+traverseNeighbors_ f (Vertex x) (Graph g) =+ let allVertices = graphVertices g+ theVertices = graphOutboundNeighborVertices g V.! x+ edges = graphOutboundNeighborEdges g V.! x+ numNeighbors = U.length theVertices+ go !i = if i < numNeighbors+ then let vertexNum = theVertices U.! i+ vertexVal = allVertices V.! vertexNum+ edgeVal = edges V.! i+ in f edgeVal (Vertex vertexNum) vertexVal *> go (i + 1)+ else pure ()+ in go 0++lookupEdge :: Vertex g -> Vertex g -> Graph g e v -> Maybe e+lookupEdge (Vertex x) (Vertex y) (Graph (SomeGraph _ neighbors edges)) =+ case U.elemIndex y (V.unsafeIndex neighbors x) of+ Nothing -> Nothing+ Just ix -> Just (V.unsafeIndex (V.unsafeIndex edges x) ix)++mutableIForM_ :: PrimMonad m => MVector (PrimState m) a -> (Int -> a -> m b) -> m ()+mutableIForM_ m f = forM_ (take (MV.length m) (enumFrom 0)) $ \i -> do+ a <- MV.read m i+ f i a++mutableIFoldM' :: PrimMonad m => (a -> Int -> b -> m a) -> a -> MVector (PrimState m) b -> m a+mutableIFoldM' f x m = go 0 x where+ len = MV.length m+ go !i !a = if i < len+ then do+ b <- MV.read m i+ aNext <- f a i b+ go (i + 1) aNext+ else return x++vertices :: Graph g e v -> Vertices g v+vertices (Graph (SomeGraph v _ _)) = Vertices v++size :: Graph g e v -> Size g+size (Graph (SomeGraph v _ _)) = Size (V.length v)++unSize :: Size g -> Int+unSize (Size s) = s++vertexInt :: Vertex g -> Int+vertexInt (Vertex i) = i++verticesToVertexList :: Vertices g v -> [Vertex g]+verticesToVertexList (Vertices v) = map Vertex (take (V.length v) [0..])++verticesTraverse_ :: Monad m => (Vertex g -> v -> m a) -> Vertices g v -> m ()+verticesTraverse_ f (Vertices v) = V.imapM_ (\i -> f (Vertex i)) v++verticesToVector :: Vertices g v -> Vector v+verticesToVector (Vertices v) = v++verticesRead :: Vertices g v -> Vertex g -> v+verticesRead (Vertices v) (Vertex i) = V.unsafeIndex v i++verticesLength :: Vertices g v -> Int+verticesLength (Vertices v) = V.length v++verticesFreeze :: PrimMonad m => MVertices g (PrimState m) v -> m (Vertices g v)+verticesFreeze (MVertices mvec) = fmap Vertices (V.freeze mvec)++verticesThaw :: PrimMonad m => Vertices g v -> m (MVertices g (PrimState m) v)+verticesThaw (Vertices vec) = fmap MVertices (V.thaw vec)++freeze :: PrimMonad m => MGraph g (PrimState m) e v -> m (Graph g e v)+freeze (MGraph vertexIndex currentIdVar edges) = do+ let initialArrayListSize = 16+ numberOfVertices <- readMutVar currentIdVar+ mvec <- MV.new numberOfVertices+ mvecEdgeVals <- MV.replicateM numberOfVertices (ArrayList.new initialArrayListSize)+ mvecEdgeNeighbors <- MV.replicateM numberOfVertices (ArrayList.new initialArrayListSize)+ flip HashTable.mapM_ vertexIndex $ \vertexValue vertexId -> do+ MV.unsafeWrite mvec vertexId vertexValue+ flip HashTable.mapM_ edges $ \(IntPair fromVertexId toVertexId) edgeVal -> do+ -- This would be better if I used hybrid vectors.+ mvecEdgeVal <- MV.unsafeRead mvecEdgeVals fromVertexId+ ArrayList.push mvecEdgeVal edgeVal+ mvecEdgeNeighbor <- MV.unsafeRead mvecEdgeNeighbors fromVertexId+ ArrayList.push mvecEdgeNeighbor toVertexId+ vecEdgeVals1 <- V.unsafeFreeze mvecEdgeVals+ vecEdgeVals2 <- V.mapM ArrayList.freeze vecEdgeVals1+ vecEdgeNeighbors1 <- V.unsafeFreeze mvecEdgeNeighbors+ vecEdgeNeighbors2 <- V.mapM ArrayList.freeze vecEdgeNeighbors1+ vec <- V.unsafeFreeze mvec+ return (Graph $ SomeGraph vec vecEdgeNeighbors2 vecEdgeVals2)++-- | Takes a function that builds on an empty 'MGraph'. After the function+-- mutates the 'MGraph', it is frozen and becomes an immutable 'SomeGraph'.+create :: PrimMonad m => (forall g. MGraph g (PrimState m) e v -> m ()) -> m (SomeGraph e v)+create f = do+ mg <- MGraph+ <$> HashTable.new+ <*> newMutVar 0+ <*> HashTable.new+ f mg+ Graph g <- freeze mg+ return g++with :: SomeGraph e v -> (forall g. Graph g e v -> a) -> a+with sg f = f (Graph sg)++-- data Edge g = Edge+-- { edgeVertexA :: !Int+-- , edgeVertexB :: !Int+-- }++-- instance Functor (Graph g e) where+-- fmap f g = g { graphVertices = Vector.map (graphVertices g) }++-- visited,allowed,notAllowed :: Word8+-- visited = 2+-- allowed = 1+-- notAllowed = 0
− src/Data/Graph/Immutable/Tagged.hs
@@ -1,120 +0,0 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE DeriveFunctor #-}--module Data.Graph.Immutable.Tagged where--import Control.Monad.Primitive-import Data.Vector (Vector)-import Data.Vector.Mutable (MVector)-import Control.Monad-import Data.Word-import Control.Monad.ST (runST)-import qualified Data.Heap.Mutable.ModelD as Heap-import qualified Data.Vector as V-import qualified Data.Vector.Mutable as MV-import qualified Data.Vector.Unboxed as U-import qualified Data.Vector.Unboxed.Mutable as MU--newtype Vertex g = Vertex { getVertex :: Int }-newtype Vertices g v = Vertices { getVertices :: Vector v }- deriving (Functor)--data Edge g = Edge- { edgeVertexA :: !Int- , edgeVertexB :: !Int- }---- | The neighbor vertices and neighbor edges must have--- equal length.-data Graph g e v = Graph- { graphVertices :: !(Vector v)- , graphOutboundNeighborVertices :: !(Vector (U.Vector Int))- , graphOutboundNeighborEdges :: !(Vector (Vector e))- -- , graphEdges :: Int -> Int -> Maybe e- } deriving (Functor)---- instance Functor (Graph g e) where--- fmap f g = g { graphVertices = Vector.map (graphVertices g) }---- visited,allowed,notAllowed :: Word8--- visited = 2--- allowed = 1--- notAllowed = 0---- | This is a generalization of Dijkstra\'s algorithm.-breadthFirstBy :: (Ord s, Monoid s)- => (v -> v -> s -> e -> s)- -> Vertex g- -> Graph g e v- -> Vertices g s-breadthFirstBy f v0 g@(Graph vertices outNeighbors outEdges) = runST $ do- let vertexCount = V.length vertices- newVertices <- MV.new vertexCount- MV.set newVertices mempty- visited <- MU.new vertexCount- MU.set visited False- heap <- Heap.new vertexCount- Heap.unsafePush mempty (getVertex v0) heap- let keepGoing = do- m <- Heap.pop heap- case m of- Nothing -> return ()- Just (s,vertexIx) -> do- MU.write visited vertexIx True- MV.write newVertices vertexIx s- let neighborVertices = outNeighbors V.! vertexIx- neighborEdges = outEdges V.! vertexIx- v1 = vertices V.! vertexIx- runInsert neighborIx neighborVertexIx = do- let edgeVal = neighborEdges V.! neighborIx- v2 = vertices V.! neighborVertexIx- alreadyVisited <- MU.read visited neighborVertexIx- if alreadyVisited- then return ()- else Heap.push (f v1 v2 s edgeVal) neighborVertexIx heap- U.imapM_ runInsert neighborVertices- keepGoing- keepGoing- newVerticesFrozen <- V.freeze newVertices- return (Vertices newVerticesFrozen)- -- return (g {graphVertices = newVerticesFrozen})--lookupVertex :: Eq v => v -> Graph g e v -> Maybe (Vertex g)-lookupVertex val g = fmap Vertex (V.elemIndex val (graphVertices g))--traverseNeighbors_ :: Applicative m- => (e -> Vertex g -> v -> m a)- -> Vertex g- -> Graph g e v- -> m ()-traverseNeighbors_ f (Vertex x) g =- let allVertices = graphVertices g- vertices = graphOutboundNeighborVertices g V.! x- edges = graphOutboundNeighborEdges g V.! x- numNeighbors = U.length vertices- go !i = if i < numNeighbors- then let vertexNum = vertices U.! i- vertexVal = allVertices V.! vertexNum- edgeVal = edges V.! i- in f edgeVal (Vertex vertexNum) vertexVal *> go (i + 1)- else pure ()- in go 0---- lookupEdge :: Vertex g -> Vertex g -> Graph g e v -> Maybe (Edge g)--- lookupEdge (Vertex x) (Vertex y) g =--mutableIForM_ :: PrimMonad m => MVector (PrimState m) a -> (Int -> a -> m b) -> m ()-mutableIForM_ m f = forM_ (take (MV.length m) (enumFrom 0)) $ \i -> do- a <- MV.read m i- f i a--mutableIFoldM' :: PrimMonad m => (a -> Int -> b -> m a) -> a -> MVector (PrimState m) b -> m a-mutableIFoldM' f x m = go 0 x where- len = MV.length m- go !i !a = if i < len- then do- b <- MV.read m i- aNext <- f a i b- go (i + 1) aNext- else return x-
+ src/Data/Graph/Mutable.hs view
@@ -0,0 +1,62 @@+module Data.Graph.Mutable where++import Data.Graph.Types+import Control.Monad.Primitive+import qualified Data.Vector.Mutable as MV+import qualified Data.Vector.Unboxed.Mutable as MU+import Data.Vector.Unboxed (Unbox)+import Data.Primitive.MutVar+import Data.Hashable (Hashable)+import qualified Data.HashMap.Mutable.Basic as HashTable++verticesReplicate :: PrimMonad m => Size g -> v -> m (MVertices g (PrimState m) v)+verticesReplicate (Size i) v = fmap MVertices (MV.replicate i v)++verticesUReplicate :: (PrimMonad m, Unbox v) => Size g -> v -> m (MUVertices g (PrimState m) v)+verticesUReplicate (Size i) v = fmap MUVertices (MU.replicate i v)++verticesUWrite :: (PrimMonad m, Unbox v) => MUVertices g (PrimState m) v -> Vertex g -> v -> m ()+verticesUWrite (MUVertices mvec) (Vertex ix) v = MU.unsafeWrite mvec ix v++verticesWrite :: PrimMonad m => MVertices g (PrimState m) v -> Vertex g -> v -> m ()+verticesWrite (MVertices mvec) (Vertex ix) v = MV.unsafeWrite mvec ix v++verticesURead :: (PrimMonad m, Unbox v) => MUVertices g (PrimState m) v -> Vertex g -> m v+verticesURead (MUVertices mvec) (Vertex ix) = MU.unsafeRead mvec ix++verticesRead :: PrimMonad m => MVertices g (PrimState m) v -> Vertex g -> m v+verticesRead (MVertices mvec) (Vertex ix) = MV.unsafeRead mvec ix++-- | This does two things:+--+-- * Check to see if a vertex with the provided value already exists+-- * Create a new vertex if it does not exist+--+-- In either case, the vertex id is returned, regardless or whether it was+-- preexisting or newly created.+insertVertex :: (PrimMonad m, Hashable v, Eq v) => MGraph g (PrimState m) e v -> v -> m (Vertex g)+insertVertex (MGraph vertexIndex currentIdVar _) v = do+ m <- HashTable.lookup vertexIndex v+ case m of+ Nothing -> do+ currentId <- readMutVar currentIdVar+ writeMutVar currentIdVar (currentId + 1)+ HashTable.insert vertexIndex v currentId+ return (Vertex currentId)+ Just i -> return (Vertex i)++-- | This replaces the edge if it already exists. If you pass the same vertex+-- as the source and the destination, this function has no effect.+insertEdge :: PrimMonad m => MGraph g (PrimState m) e v -> Vertex g -> Vertex g -> e -> m ()+insertEdge (MGraph _ _ edges) (Vertex a) (Vertex b) e = do+ HashTable.insert edges (IntPair a b) e++-- | Insert edge with a function, combining the existing edge value and the old one.+insertEdgeWith :: PrimMonad m => MGraph g (PrimState m) e v -> (e -> e -> e) -> Vertex g -> Vertex g -> e -> m ()+insertEdgeWith (MGraph _ _ edges) combine (Vertex a) (Vertex b) e = do+ m <- HashTable.lookup edges (IntPair a b)+ case m of+ Nothing -> HashTable.insert edges (IntPair a b) e+ Just eOld -> HashTable.insert edges (IntPair a b) (combine eOld e)++
+ src/Data/Graph/Types.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE BangPatterns #-}+module Data.Graph.Types where++import Data.HashMap.Mutable.Basic (HashTable)+import Data.Vector (Vector,MVector)+import Data.Primitive.MutVar (MutVar)+import Data.Hashable (Hashable)+import GHC.Generics (Generic)+import qualified Data.Vector.Unboxed as U+import qualified Data.Vector.Unboxed.Mutable as MU++newtype Graph g e v = Graph { getGraphInternal :: SomeGraph e v }+ deriving (Functor)++-- | The neighbor vertices and neighbor edges must have+-- equal length.+--+-- TODO: enforce that the inner vectors for the neighbors are+-- ordered. This will make testing for neighbors easier and+-- will make an equality check easier.+data SomeGraph e v = SomeGraph+ { graphVertices :: !(Vector v)+ , graphOutboundNeighborVertices :: !(Vector (U.Vector Int))+ , graphOutboundNeighborEdges :: !(Vector (Vector e))+ } deriving (Functor)++newtype Size g = Size { getSizeInternal :: Int }++newtype Vertex g = Vertex { getVertexInternal :: Int }+ deriving (Eq,Ord,Hashable)+newtype Vertices g v = Vertices { getVerticesInternal :: Vector v }+ deriving (Functor)+newtype MVertices g s v = MVertices { getMVerticesInternal :: MVector s v }+newtype MUVertices g s v = MUVertices { getMUVerticesInternal :: MU.MVector s v }++data IntPair = IntPair !Int !Int+ deriving (Eq,Ord,Show,Read,Generic)++instance Hashable IntPair++data MGraph g s e v = MGraph+ { mgraphVertexIndex :: !(HashTable s v Int)+ , mgraphCurrentId :: !(MutVar s Int)+ , mgraphEdges :: !(HashTable s IntPair e)+ }+
src/Data/HashMap/Mutable/Basic.hs view
@@ -248,7 +248,7 @@ ------------------------------------------------------------------------------ -- | See the documentation for this function in -- "Data.HashTable.Class#v:mapM_".-mapM_ :: PrimMonad m => ((k,v) -> m b) -> HashTable (PrimState m) k v -> m ()+mapM_ :: PrimMonad m => (k -> v -> m b) -> HashTable (PrimState m) k v -> m () mapM_ f htRef = readRef htRef >>= work where work (HashTable sz _ hashes keys values) = go 0@@ -261,7 +261,7 @@ else do k <- readArray keys i v <- readArray values i- _ <- f (k, v)+ _ <- f k v go (i+1)
src/Data/Heap/Mutable/ModelC.hs view
@@ -32,7 +32,7 @@ -- causing the priority to increas, the heap becomes invalid (but not in a way that causes -- segfaults). ----- As a result of the third constraint, the 'Monoid' instance and 'Ord' instance of the priority type+-- As a result of the last constraint, the 'Monoid' instance and 'Ord' instance of the priority type -- must obey these additional laws: -- -- > mappend a b ≤ a
− src/Lib.hs
@@ -1,6 +0,0 @@-module Lib- ( someFunc- ) where--someFunc :: IO ()-someFunc = putStrLn "someFunc"
test/Spec.hs view
@@ -2,11 +2,15 @@ module Main (main) where -import Test.QuickCheck (Gen, Arbitrary(..), choose, shrinkIntegral)+import Test.QuickCheck (Gen, Arbitrary(..), choose, shrinkIntegral,+ listOf, vectorOf) import Test.Framework (defaultMain, testGroup, Test) import Test.Framework.Providers.QuickCheck2 (testProperty) import Test.Framework.Providers.HUnit (testCase) import Test.HUnit (Assertion,(@?=))+import Data.Monoid (All(..))+import Data.Traversable+import Control.Applicative import Data.Coerce import Data.Word@@ -19,7 +23,11 @@ import qualified Data.Map.Strict as Map import Debug.Trace +import qualified Data.Vector as V+import qualified Data.ArrayList.Generic as ArrayList import qualified Data.Heap.Mutable.ModelD as HeapD+import qualified Data.Graph.Mutable as MGraph+import qualified Data.Graph.Immutable as Graph main :: IO () main = defaultMain tests@@ -31,6 +39,13 @@ , testProperty "Model D Push Pop" heapPushPop , testProperty "Model D List" heapMatchesList ]+ , testGroup "ArrayList"+ [ testProperty "Insertion followed by freezing" arrayListWorks+ ]+ , testGroup "Graph"+ [ testProperty "Building only from vertices" graphBuildingVertices+ , testProperty "Trivial case for Dijkstras Algorithm" dijkstraEasyDistance+ ] ] testElements :: Int@@ -44,7 +59,7 @@ shrink (Min a) = fmap Min $ filter (>= 0) $ shrinkIntegral a instance Monoid Min where- mempty = Min 0+ mempty = Min maxBound mappend (Min a) (Min b) = Min (min a b) newtype MyElement = MyElement { getMyElement :: Int }@@ -54,6 +69,13 @@ arbitrary = fmap MyElement (choose (0,fromIntegral testElements - 1)) shrink (MyElement a) = fmap MyElement $ filter (>= 0) $ shrinkIntegral a -- fmap MyElement (enumFromTo 0 (a - 1)) +newtype TenElemsOrLessList a = TenElemsOrLessList [a]+ deriving (Read,Show,Eq,Ord)++instance Arbitrary a => Arbitrary (TenElemsOrLessList a) where+ arbitrary = fmap TenElemsOrLessList $ flip vectorOf arbitrary =<< choose (0 :: Int,10)+ shrink (TenElemsOrLessList a) = fmap TenElemsOrLessList $ shrink a+ multipush :: [(Min,MyElement)] -> Bool multipush xs = runST $ do h <- trace "Running Test" (HeapD.new testElements)@@ -82,4 +104,62 @@ heapResSet = map (\pairs@((p,_) : _) -> (p,Set.fromList $ map snd pairs)) $ groupBy (on (==) fst) heapRes in heapResSet == listRes++arrayListWorks :: [Int] -> Bool+arrayListWorks xs =+ let ys = runST $ do+ a <- ArrayList.new 1+ forM_ xs $ \x -> ArrayList.push a x+ ArrayList.freeze a+ in xs == V.toList ys++-- This makes sure that when you insert a bunch of vertices into+-- a graph, you get the same vertices back out. This does not+-- do anything to check for edges.+graphBuildingVertices :: [Int] -> Bool+graphBuildingVertices xs =+ let sg = runST $ Graph.create $ \mg -> do+ forM_ xs $ \x -> do+ MGraph.insertVertex mg x+ ys = Graph.with sg (Graph.verticesToVector . Graph.vertices)+ in List.nub (List.sort xs) == List.sort (V.toList ys)++graphBuildingEdgesEverywhere :: TenElemsOrLessList Int -> Bool+graphBuildingEdgesEverywhere (TenElemsOrLessList xs) =+ let onlyEdge = 77 :: Int+ sg = runST $ Graph.create $ \mg -> do+ vertices <- forM xs $ \x -> do+ MGraph.insertVertex mg x+ forM_ vertices $ \source -> do+ forM_ vertices $ \dest -> do+ MGraph.insertEdge mg source dest onlyEdge+ in getAll $ getConst $ Graph.with sg $ \g ->+ let v = Graph.vertices g -- Graph.vertices g Graph.verticesToVector . Graph.vertices)+ vlist = Graph.verticesToVertexList v+ in for vlist $ \va ->+ for vlist $ \vb ->+ Const (All $ Graph.lookupEdge va vb g == Just onlyEdge)++data Thing = Thing++-- Every node is connected to at most two other nodes. The end+-- nodes only have one neighbor. Go from one end node to the other.+dijkstraEasyDistance :: [Word32] -> Bool+dijkstraEasyDistance xs =+ let sg = runST $ Graph.create $ \mg -> do+ start <- MGraph.insertVertex mg (0 :: Int)+ let insertNext prevVertex zs i = case zs of+ [] -> return ()+ y : ys -> do+ vertex <- MGraph.insertVertex mg i+ MGraph.insertEdge mg prevVertex vertex y+ insertNext vertex ys (i + 1)+ insertNext start xs 1+ in Graph.with sg $ \g -> case (Graph.lookupVertex 0 g, Graph.lookupVertex (List.length xs) g) of+ (Nothing,Nothing) -> False+ (Nothing,Just _) -> False+ (Just _,Nothing) -> False+ (Just start, Just end) ->+ let expected = Min (sum xs)+ in expected == Graph.dijkstra (\_ _ (Min x) distance -> Min (x + distance)) (Min 0) start end g