Skip to content

Commit 31c2368

Browse files
Cleanup round
* Moved Empty and Leaf1 into the recursive part of the R-tree for performance; * Removed the .Strict qualifier from module names (since these trees cannot be lazy) and added .D2 to signify two-dimensionality; * Clarified time complexities; * Merged tree debugging into a single function; * Generalized tests; * Bumped version to 1.2.0;
1 parent 8387979 commit 31c2368

File tree

22 files changed

+2071
-2361
lines changed

22 files changed

+2071
-2361
lines changed

README.md

+3-13
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,5 @@
1-
R-Trees (and in the future also R*-Trees)
2-
====================
1+
data-r-tree
32

4-
R-Tree is a spatial data structure similar to Quadtrees or B-Trees.
3+
---
54

6-
An R-Tree is a balanced tree and optimized for lookups. This implemetation useses an R-Tree to privide
7-
a map to arbitrary values.
8-
9-
Some function names clash with "Prelude" names, therefore this module is usually
10-
imported ```qualified```, e.g.:
11-
12-
> import Data.RTree (RTree)
13-
> import qualified Data.RTree as RT
14-
15-
this implemetation is incomplete at the moment. Feel free to send comments, patches or merge requests.
5+
R/R\*-trees, currently only two-dimensional `Float` and `Double` varieties.

benchmark/space/Main.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
module Main where
44

5-
import qualified Data.RTree.Float.Strict as R
5+
import qualified Data.RTree.D2.Float as R
66

77
import Control.Monad
88
import Data.Foldable

benchmark/time/Main.hs

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
module Main where
66

7-
import Data.RTree.Double.Strict (RTree, MBR, Predicate)
8-
import qualified Data.RTree.Double.Strict as R
7+
import Data.RTree.D2.Double (RTree, MBR, Predicate)
8+
import qualified Data.RTree.D2.Double as R
99

1010
import Control.DeepSeq
1111
import Control.Monad
@@ -80,7 +80,7 @@ map cat from name pre =
8080
) $ \ ~(r, brs) ->
8181
bench (cat <> "/map/" <> name) $
8282
flip nf brs $
83-
fmap $ \x -> [R.mapRangeWithKey (pre x) (\_ -> (+) 1) r]
83+
fmap $ \x -> [R.adjustRangeWithKey (pre x) (\_ -> (+) 1) r]
8484

8585
traversal
8686
:: String -> ([(MBR, Int)] -> RTree Int)

changelog.md

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
## 1.1.0
1+
## 1.2.0
22

33
Proper rewrite of the library.
44
Additions are not listed, only the most important changes are.
@@ -19,32 +19,35 @@ Additions are not listed, only the most important changes are.
1919

2020
* `RTree`:
2121

22-
- `Data.RTree` is now called `Data.RTree.*.Strict`;
22+
- `Data.RTree` is now called `Data.RTree.D2.Double`;
2323

24-
- Internals are now exposed in `Data.RTree.*.Strict.Unsafe`;
24+
- Internals are now exposed in `Data.RTree.D2.Double.Unsafe`;
2525

2626
- `Binary`, `Generic`, `Monoid` and `Semigroup` instances were removed;
2727

2828
- `insertWith`, `union`, `unionWith` and `mapMaybe`,
2929
`fromList`, `toList`, `keys` and `values` were removed;
3030

31-
- `length` and `null` are now only accessible from the `Foldable` typeclass;
31+
- `length` is now named `size`;
3232

3333
- Conversions between lookup functions:
3434

35-
- `lookup` is `\ba -> getFirst . foldMap (equals ba) (First . Just)`;
35+
- `lookup` is `\ba -> foldrRangeWithKey (equals ba) (\_ x _ -> Just x) Nothing`;
3636

37-
- `intersect` is `\ba -> foldMap (intersects ba) pure`;
37+
- `intersect` is `\ba -> foldrRangeWithKey (intersects ba) (\_ -> (:)) []`;
3838

39-
- `intersectWithKey` is `\ba -> foldMapWithKey (intersects ba) pure`;
39+
- `intersectWithKey` is
40+
`\ba -> foldrRangeWithKey (intersects ba) (\bx x -> (:) (bx, x)) []`;
4041

41-
- `lookupRange` is `\ba -> foldMap (contains ba) pure`;
42+
- `lookupRange` is `\ba -> foldrRangeWithKey (containedBy ba) (\_ -> (:)) []`;
4243

43-
- `lookupRangeWithKey` is `\ba -> foldMapWithKey (contains ba) pure`;
44+
- `lookupRangeWithKey` is
45+
`\ba -> foldrRangeWithKey (containedBy ba) (\bx x -> (:) (bx, x)) []`;
4446

45-
- `lookupContainsRange` is `\ba -> foldMap (containedBy ba) pure`;
47+
- `lookupContainsRange` is `\ba -> foldrRangeWithKey (contains ba) (\_ -> (:)) []`;
4648

47-
- `lookupContainsRangeWithKey` is `\ba -> foldMapWithKey (containedBy ba) pure`;
49+
- `lookupContainsRangeWithKey` is
50+
`\ba -> foldrRangeWithKey (contains ba) (\bx x -> (:) (bx, x)) []`;
4851

4952
## 0.6.0
5053

data-r-tree.cabal

+11-12
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
cabal-version: 2.2
22

33
name: data-r-tree
4-
version: 1.1.0
5-
synopsis: Two-dimensional R-trees.
6-
description: Two-dimensional spatial trees utilizing R-tree and R*-tree
7-
algorithms.
4+
version: 1.2.0
5+
synopsis: R/R*-trees.
6+
description: Spatial trees utilizing R-tree and R*-tree algorithms.
87

98
license: MIT
109
license-file: LICENSE
@@ -32,15 +31,15 @@ library
3231

3332
hs-source-dirs: src
3433

35-
exposed-modules: Data.RTree.Double.Strict
36-
Data.RTree.Double.Strict.Debug
37-
Data.RTree.Double.Strict.Unsafe
38-
Data.RTree.Float.Strict
39-
Data.RTree.Float.Strict.Debug
40-
Data.RTree.Float.Strict.Unsafe
34+
exposed-modules: Data.RTree.D2.Double
35+
Data.RTree.D2.Double.Debug
36+
Data.RTree.D2.Double.Unsafe
37+
Data.RTree.D2.Float
38+
Data.RTree.D2.Float.Debug
39+
Data.RTree.D2.Float.Unsafe
4140

42-
other-modules: Data.RTree.Double.Strict.Internal
43-
Data.RTree.Float.Strict.Internal
41+
other-modules: Data.RTree.D2.Double.Internal
42+
Data.RTree.D2.Float.Internal
4443

4544
ghc-options: -Wall
4645

no/Data/NoTree/Strict.hs renamed to no/No/Tree/D2.hs

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
Every fold/map is \(O (n)\).
77
-}
88

9-
module Data.NoTree.Strict where
9+
module No.Tree.D2 where
1010

11-
import Data.RTree.Double.Strict.Unsafe (MBR (..), Predicate (..))
11+
import Data.RTree.D2.Double.Unsafe (MBR (..), Predicate (..))
1212

1313
import Control.DeepSeq
1414
import qualified Data.Foldable as Fold
@@ -70,8 +70,8 @@ delete ba no = let (xs, ys) = break ((== ba) . fst) $ toList no
7070
mapWithKey :: (MBR -> a -> b) -> NoTree a -> NoTree b
7171
mapWithKey f = NoTree . fmap (\ ~(ba, a) -> (ba, f ba a) ) . toList
7272

73-
mapRangeWithKey :: Predicate -> (MBR -> a -> a) -> NoTree a -> NoTree a
74-
mapRangeWithKey (Predicate _ checkLeaf) f =
73+
adjustRangeWithKey :: Predicate -> (MBR -> a -> a) -> NoTree a -> NoTree a
74+
adjustRangeWithKey (Predicate _ checkLeaf) f =
7575
NoTree . fmap (\(ba, a) -> (ba, opt ba a)) . toList
7676
where
7777
opt ba a | checkLeaf ba = f ba a
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
{-# LANGUAGE PatternSynonyms #-}
2+
13
{- |
2-
Module : Data.RTree.Double.Strict
4+
Module : Data.RTree.D2.Double
35
Copyright : Copyright (c) 2015, Birte Wagner, Sebastian Philipp
46
Copyright (c) 2022, Oleksii Divak
57
License : MIT
@@ -8,7 +10,7 @@
810
Stability : experimental
911
Portability: not portable
1012
11-
@'RTree' a@ represents a two-dimensional spatial tree
13+
@'RTree' a@ is a spine-strict two-dimensional spatial tree
1214
from bounding rectangles of type 'Double' to values of type @a@.
1315
1416
R-trees have no notion of element order, as such:
@@ -23,15 +25,22 @@
2325
2426
== Laziness
2527
26-
Evaluating the root of the tree (i.e. @(_ :: 'RTree' a)@) to WHNF evaluates the entire
27-
spine of the tree to normal form. This does not apply to values however, as such
28-
care must be taken to evaluate values properly before inserting them.
28+
Evaluating the root of the tree (i.e. @(_ :: 'RTree' a)@) to WHNF
29+
evaluates the entire spine of the tree to normal form.
30+
31+
Functions do not perform any additional evaluations unless
32+
their documentation directly specifies so.
2933
3034
== Performance
3135
32-
Unless noted otherwise, operation complexity specified is worst-case.
36+
Each function's time complexity is provided in the documentation.
37+
3338
\(n\) refers to the total number of entries in the tree.
3439
40+
\(r\) refers to the time complexity of the chosen 'Predicate' lookup,
41+
ranging from \(\mathcal{O}(\log n)\) (well-balanced)
42+
to \(\mathcal{O}(n)\) (worst-case) depending on tree quality.
43+
3544
== Implementation
3645
3746
The implementation is heavily specialized for constants
@@ -53,46 +62,27 @@
5362
<https://ia800900.us.archive.org/27/items/nasa_techdoc_19970016975/19970016975.pdf>
5463
-}
5564

56-
module Data.RTree.Double.Strict
65+
module Data.RTree.D2.Double
5766
( MBR (MBR)
5867
, RTree
5968

60-
-- * Construction
69+
-- * Construct
6170
, empty
6271
, singleton
6372

64-
-- * Queries
65-
-- ** Value-only
66-
-- *** Map
67-
, Data.RTree.Double.Strict.Internal.map
68-
, map'
69-
70-
-- *** Fold
71-
, Data.RTree.Double.Strict.Internal.foldl
72-
, Data.RTree.Double.Strict.Internal.foldr
73-
, Data.RTree.Double.Strict.Internal.foldMap
74-
, Data.RTree.Double.Strict.Internal.foldl'
75-
, Data.RTree.Double.Strict.Internal.foldr'
76-
77-
-- *** Traversal
78-
, Data.RTree.Double.Strict.Internal.traverse
79-
80-
-- ** MBR/value
81-
-- *** Map
82-
, mapWithKey
83-
, mapWithKey'
73+
-- ** Bulk-loading
74+
, bulkSTR
8475

85-
-- *** Fold
86-
, foldlWithKey
87-
, foldrWithKey
88-
, foldMapWithKey
89-
, foldlWithKey'
90-
, foldrWithKey'
76+
-- * Single-key
77+
-- ** Insert
78+
, insert
79+
, insertGut
9180

92-
-- *** Traversal
93-
, traverseWithKey
81+
-- ** Delete
82+
, delete
9483

95-
-- ** Range
84+
-- * Range
85+
-- | NOTE: both 'Predicate's and functions using them inline heavily.
9686
, Predicate
9787
, equals
9888
, intersects
@@ -102,39 +92,63 @@ module Data.RTree.Double.Strict
10292
, containedBy
10393
, containedBy'
10494

105-
-- *** Map
106-
, mapRangeWithKey
107-
, mapRangeWithKey'
95+
-- ** Map
96+
, adjustRangeWithKey
97+
, adjustRangeWithKey'
10898

109-
-- *** Fold
99+
-- ** Fold
110100
, foldlRangeWithKey
111101
, foldrRangeWithKey
112102
, foldMapRangeWithKey
113103
, foldlRangeWithKey'
114104
, foldrRangeWithKey'
115105

116-
-- *** Traversal
106+
-- ** Traverse
117107
, traverseRangeWithKey
118108

119-
-- * Insertion
120-
, insert
121-
, insertGut
109+
-- * Full tree
110+
-- ** Size
111+
, Data.RTree.D2.Double.Internal.null
112+
, size
122113

123-
-- * Deletion
124-
, delete
114+
-- ** Map
115+
, Data.RTree.D2.Double.Internal.map
116+
, map'
117+
, mapWithKey
118+
, mapWithKey'
125119

126-
-- * Bulk-loading
127-
, bulkSTR
120+
-- ** Fold
121+
-- | === Left-to-right
122+
, Data.RTree.D2.Double.Internal.foldl
123+
, Data.RTree.D2.Double.Internal.foldl'
124+
, foldlWithKey
125+
, foldlWithKey'
126+
127+
-- | === Right-to-left
128+
, Data.RTree.D2.Double.Internal.foldr
129+
, Data.RTree.D2.Double.Internal.foldr'
130+
, foldrWithKey
131+
, foldrWithKey'
132+
133+
-- | === Monoid
134+
, Data.RTree.D2.Double.Internal.foldMap
135+
, foldMapWithKey
136+
137+
-- ** Traverse
138+
, Data.RTree.D2.Double.Internal.traverse
139+
, traverseWithKey
128140
) where
129141

130-
import Data.RTree.Double.Strict.Internal
142+
import Data.RTree.D2.Double.Internal
131143

132144

133145

134-
-- | \(\mathcal{O}(1)\). Empty R-tree.
146+
-- | \(\mathcal{O}(1)\).
147+
-- Empty tree.
135148
empty :: RTree a
136149
empty = Empty
137150

138-
-- | \(\mathcal{O}(1)\). R-tree with a single entry.
151+
-- | \(\mathcal{O}(1)\).
152+
-- Tree with a single entry.
139153
singleton :: MBR -> a -> RTree a
140154
singleton = Leaf1

0 commit comments

Comments
 (0)