diff options
Diffstat (limited to 'minmax-psq')
-rw-r--r-- | minmax-psq/CHANGELOG.md | 5 | ||||
-rw-r--r-- | minmax-psq/LICENSE | 30 | ||||
-rw-r--r-- | minmax-psq/Setup.hs | 2 | ||||
-rw-r--r-- | minmax-psq/minmax-psq.cabal | 24 | ||||
-rw-r--r-- | minmax-psq/src/Data/MinMaxPSQ.hs | 112 |
5 files changed, 173 insertions, 0 deletions
diff --git a/minmax-psq/CHANGELOG.md b/minmax-psq/CHANGELOG.md new file mode 100644 index 00000000..ba7d08da --- /dev/null +++ b/minmax-psq/CHANGELOG.md | |||
@@ -0,0 +1,5 @@ | |||
1 | # Revision history for minmax-psq | ||
2 | |||
3 | ## 0.1.0.0 -- YYYY-mm-dd | ||
4 | |||
5 | * First version. Released on an unsuspecting world. | ||
diff --git a/minmax-psq/LICENSE b/minmax-psq/LICENSE new file mode 100644 index 00000000..e8eaef49 --- /dev/null +++ b/minmax-psq/LICENSE | |||
@@ -0,0 +1,30 @@ | |||
1 | Copyright (c) 2019, James Crayne | ||
2 | |||
3 | All rights reserved. | ||
4 | |||
5 | Redistribution and use in source and binary forms, with or without | ||
6 | modification, are permitted provided that the following conditions are met: | ||
7 | |||
8 | * Redistributions of source code must retain the above copyright | ||
9 | notice, this list of conditions and the following disclaimer. | ||
10 | |||
11 | * Redistributions in binary form must reproduce the above | ||
12 | copyright notice, this list of conditions and the following | ||
13 | disclaimer in the documentation and/or other materials provided | ||
14 | with the distribution. | ||
15 | |||
16 | * Neither the name of James Crayne nor the names of other | ||
17 | contributors may be used to endorse or promote products derived | ||
18 | from this software without specific prior written permission. | ||
19 | |||
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
diff --git a/minmax-psq/Setup.hs b/minmax-psq/Setup.hs new file mode 100644 index 00000000..9a994af6 --- /dev/null +++ b/minmax-psq/Setup.hs | |||
@@ -0,0 +1,2 @@ | |||
1 | import Distribution.Simple | ||
2 | main = defaultMain | ||
diff --git a/minmax-psq/minmax-psq.cabal b/minmax-psq/minmax-psq.cabal new file mode 100644 index 00000000..ba04bd45 --- /dev/null +++ b/minmax-psq/minmax-psq.cabal | |||
@@ -0,0 +1,24 @@ | |||
1 | -- Initial minmax-psq.cabal generated by cabal init. For further | ||
2 | -- documentation, see http://haskell.org/cabal/users-guide/ | ||
3 | |||
4 | name: minmax-psq | ||
5 | version: 0.1.0.0 | ||
6 | -- synopsis: | ||
7 | -- description: | ||
8 | license: BSD3 | ||
9 | license-file: LICENSE | ||
10 | author: James Crayne | ||
11 | maintainer: jim.crayne@gmail.com | ||
12 | -- copyright: | ||
13 | -- category: | ||
14 | build-type: Simple | ||
15 | extra-source-files: CHANGELOG.md | ||
16 | cabal-version: >=1.10 | ||
17 | |||
18 | library | ||
19 | exposed-modules: Data.MinMaxPSQ | ||
20 | -- other-modules: | ||
21 | other-extensions: BangPatterns, PatternSynonyms | ||
22 | build-depends: base, psq-wrap | ||
23 | hs-source-dirs: src | ||
24 | default-language: Haskell2010 | ||
diff --git a/minmax-psq/src/Data/MinMaxPSQ.hs b/minmax-psq/src/Data/MinMaxPSQ.hs new file mode 100644 index 00000000..e7d7c760 --- /dev/null +++ b/minmax-psq/src/Data/MinMaxPSQ.hs | |||
@@ -0,0 +1,112 @@ | |||
1 | {-# LANGUAGE BangPatterns, PatternSynonyms #-} | ||
2 | module Data.MinMaxPSQ | ||
3 | ( module Data.MinMaxPSQ | ||
4 | , Binding' | ||
5 | , pattern Binding | ||
6 | ) where | ||
7 | |||
8 | import Data.Ord | ||
9 | import qualified Data.Wrapper.PSQ as PSQ | ||
10 | ;import Data.Wrapper.PSQ as PSQ hiding (insert, insert', null, size) | ||
11 | import Prelude hiding (null, take) | ||
12 | |||
13 | data MinMaxPSQ' k p v = MinMaxPSQ !Int !(PSQ' k p v) !(PSQ' k (Down p) v) | ||
14 | type MinMaxPSQ k p = MinMaxPSQ' k p () | ||
15 | |||
16 | empty :: MinMaxPSQ' k p v | ||
17 | empty = MinMaxPSQ 0 PSQ.empty PSQ.empty | ||
18 | |||
19 | singleton' :: (PSQKey k, Ord p) => k -> v -> p -> MinMaxPSQ' k p v | ||
20 | singleton' k v p = MinMaxPSQ 1 (PSQ.singleton' k v p) (PSQ.singleton' k v (Down p)) | ||
21 | |||
22 | null :: MinMaxPSQ' k p v -> Bool | ||
23 | null (MinMaxPSQ sz _ _) = sz==0 | ||
24 | {-# INLINE null #-} | ||
25 | |||
26 | size :: MinMaxPSQ' k p v -> Int | ||
27 | size (MinMaxPSQ sz _ _) = sz | ||
28 | {-# INLINE size #-} | ||
29 | |||
30 | toList :: (PSQKey k, Ord p) => MinMaxPSQ' k p v -> [Binding' k p v] | ||
31 | toList (MinMaxPSQ _ nq xq) = PSQ.toList nq | ||
32 | |||
33 | fromList :: (PSQKey k, Ord p) => [Binding' k p v] -> MinMaxPSQ' k p v | ||
34 | fromList kps = let nq = PSQ.fromList kps | ||
35 | xq = PSQ.fromList $ map (\(Binding k v p) -> Binding k v (Down p)) kps | ||
36 | in MinMaxPSQ (PSQ.size nq) nq xq | ||
37 | |||
38 | findMin :: (PSQKey k, Ord p) => MinMaxPSQ' k p v -> Maybe (Binding' k p v) | ||
39 | findMin (MinMaxPSQ _ nq xq) = PSQ.findMin nq | ||
40 | |||
41 | findMax :: (PSQKey k, Ord p) => MinMaxPSQ' k p v -> Maybe (Binding' k p v) | ||
42 | findMax (MinMaxPSQ _ nq xq) = fmap (\(Binding k v (Down p)) -> Binding k v p) $ PSQ.findMin xq | ||
43 | |||
44 | insert :: (PSQKey k, Ord p) => k -> p -> MinMaxPSQ k p -> MinMaxPSQ k p | ||
45 | insert k p (MinMaxPSQ sz nq xq) = case PSQ.insertView k p () nq of | ||
46 | (Just _ ,nq') -> MinMaxPSQ sz nq' (PSQ.insert k (Down p) xq) | ||
47 | (Nothing,nq') -> MinMaxPSQ (sz+1) nq' (PSQ.insert k (Down p) xq) | ||
48 | |||
49 | insert' :: (PSQKey k, Ord p) => k -> v -> p -> MinMaxPSQ' k p v -> MinMaxPSQ' k p v | ||
50 | insert' k v p (MinMaxPSQ sz nq xq) = case PSQ.insertView k p v nq of | ||
51 | (Just _ ,nq') -> MinMaxPSQ sz nq' (PSQ.insert' k v (Down p) xq) | ||
52 | (Nothing,nq') -> MinMaxPSQ (sz+1) nq' (PSQ.insert' k v (Down p) xq) | ||
53 | |||
54 | delete :: (PSQKey k, Ord p) => k -> MinMaxPSQ' k p v -> MinMaxPSQ' k p v | ||
55 | delete k q@(MinMaxPSQ sz nq xq) = case PSQ.deleteView k nq of | ||
56 | Just (_,_,nq') -> MinMaxPSQ (sz - 1) nq' (PSQ.delete k xq) | ||
57 | Nothing -> q | ||
58 | |||
59 | deleteMin :: (PSQKey k, Ord p) => MinMaxPSQ' k p v -> MinMaxPSQ' k p v | ||
60 | deleteMin q@(MinMaxPSQ sz nq xq) = case PSQ.minView nq of | ||
61 | Just (Binding k _ _, nq') -> MinMaxPSQ (sz - 1) nq' (PSQ.delete k xq) | ||
62 | Nothing -> q | ||
63 | |||
64 | deleteMax :: (PSQKey k, Ord p) => MinMaxPSQ' k p v -> MinMaxPSQ' k p v | ||
65 | deleteMax q@(MinMaxPSQ sz nq xq) = case PSQ.minView xq of | ||
66 | Just (Binding k _ _, xq') -> MinMaxPSQ (sz - 1) (PSQ.delete k nq) xq' | ||
67 | Nothing -> q | ||
68 | |||
69 | minView :: (PSQKey k, Ord p) => MinMaxPSQ' k p v -> Maybe (Binding' k p v, MinMaxPSQ' k p v) | ||
70 | minView (MinMaxPSQ sz nq xq) = fmap (\(Binding k v p, nq') -> (Binding k v p, MinMaxPSQ (sz-1) nq' (PSQ.delete k xq))) | ||
71 | $ PSQ.minView nq | ||
72 | |||
73 | maxView :: (PSQKey k, Ord p) => MinMaxPSQ' k p v -> Maybe (Binding' k p v, MinMaxPSQ' k p v) | ||
74 | maxView (MinMaxPSQ sz nq xq) = fmap (\(Binding k v (Down p), xq') -> (Binding k v p, MinMaxPSQ (sz-1) (PSQ.delete k nq) xq')) | ||
75 | $ PSQ.minView xq | ||
76 | |||
77 | -- | Maintains a bounded 'MinMaxPSQ' by deleting the maximum element if the | ||
78 | -- insertion would cause the queue to have too many elements. | ||
79 | insertTake :: (PSQKey k, Ord p) => Int -> k -> p -> MinMaxPSQ k p -> MinMaxPSQ k p | ||
80 | insertTake n k p q | ||
81 | | size q < n = insert k p q | ||
82 | | size q == n = insert k p $ deleteMax q | ||
83 | | otherwise = take n $ insert k p q | ||
84 | |||
85 | -- | Maintains a bounded 'MinMaxPSQ\'' by deleting the maximum element if the | ||
86 | -- insertion would cause the queue to have too many elements. | ||
87 | insertTake' :: (PSQKey k, Ord p) => Int -> k -> v -> p -> MinMaxPSQ' k p v -> MinMaxPSQ' k p v | ||
88 | insertTake' n k v p q | ||
89 | | size q < n = insert' k v p q | ||
90 | | size q == n = insert' k v p $ deleteMax q | ||
91 | | otherwise = take n $ insert' k v p q | ||
92 | |||
93 | |||
94 | -- | Truncate the 'MinMaxPSQ' to the given number of lowest priority elements. | ||
95 | take :: (PSQKey k, Ord p) => Int -> MinMaxPSQ' k p v -> MinMaxPSQ' k p v | ||
96 | take !n !q | (size q <= n) = q | ||
97 | | null q = q | ||
98 | | otherwise = take n $ deleteMax q | ||
99 | |||
100 | -- | Like 'take', except it provides a list deleted bindings. | ||
101 | takeView :: (PSQKey k, Ord p) => Int -> MinMaxPSQ' k p v -> ( [Binding' k p v], MinMaxPSQ' k p v ) | ||
102 | takeView !n !q | (size q <= n) = ([], q) | ||
103 | | null q = ([], q) | ||
104 | | otherwise = let Just (x,q') = maxView q | ||
105 | (xs,q'') = takeView n q' | ||
106 | ys = x:xs | ||
107 | in (ys, ys `seq` q'') | ||
108 | |||
109 | |||
110 | |||
111 | lookup' :: (PSQKey k, Ord p) => k -> MinMaxPSQ' k p v -> Maybe (p, v) | ||
112 | lookup' k (MinMaxPSQ _ q _) = PSQ.lookup k q | ||