interval-tree 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/exclusive-interval-tree.rb +117 -0
- data/lib/inclusive-interval-tree.rb +122 -0
- data/lib/interval-tree-node.rb +15 -0
- data/lib/interval-tree.rb +4 -0
- metadata +7 -3
@@ -0,0 +1,117 @@
|
|
1
|
+
#!/usr/local/bin/ruby-1.9
|
2
|
+
#
|
3
|
+
# Title:: the IntervalTree module using "augmented tree"
|
4
|
+
# Author:: MISHIMA, Hiroyuki ( https://github.com/misshie ), 2011
|
5
|
+
# Copyright:: The MIT/X11 license
|
6
|
+
#
|
7
|
+
# see also ....
|
8
|
+
# description in Wikipedia
|
9
|
+
# http://en.wikipedia.org/wiki/Interval_tree
|
10
|
+
# implementstion in Python by Tyler Kahn
|
11
|
+
# http://forrst.com/posts/Interval_Tree_implementation_in_python-e0K
|
12
|
+
#
|
13
|
+
# Usage:
|
14
|
+
# require "interval_tree"
|
15
|
+
# itv = [(0...3), (1...4), (3...5),]
|
16
|
+
# t = IntervalTree::Tree.new(itv)
|
17
|
+
# p t.search(2) => [0...3, 1...4]
|
18
|
+
# p t.search(1...3) => [0...3, 1...4, 3...5]
|
19
|
+
#
|
20
|
+
# note: result intervals are always returned
|
21
|
+
# in the "left-closed and right-open" style that can be expressed
|
22
|
+
# by three-dotted Range object literals (first...last)
|
23
|
+
#
|
24
|
+
|
25
|
+
require 'interval-tree-node'
|
26
|
+
|
27
|
+
module IntervalTree
|
28
|
+
class ExclusiveTree
|
29
|
+
def initialize(ranges)
|
30
|
+
ranges_excl = ensure_exclusive_end([ranges].flatten)
|
31
|
+
@top_node = divide_intervals(ranges_excl)
|
32
|
+
end
|
33
|
+
attr_reader :top_node
|
34
|
+
|
35
|
+
def divide_intervals(intervals)
|
36
|
+
return nil if intervals.empty?
|
37
|
+
x_center = center(intervals)
|
38
|
+
s_center = Array.new
|
39
|
+
s_left = Array.new
|
40
|
+
s_right = Array.new
|
41
|
+
|
42
|
+
intervals.each do |k|
|
43
|
+
case
|
44
|
+
when k.last < x_center
|
45
|
+
s_left << k
|
46
|
+
when x_center < k.first
|
47
|
+
s_right << k
|
48
|
+
else
|
49
|
+
s_center << k
|
50
|
+
end
|
51
|
+
end
|
52
|
+
Node.new(x_center, s_center,
|
53
|
+
divide_intervals(s_left), divide_intervals(s_right))
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
def search(interval)
|
58
|
+
if interval.respond_to?(:first)
|
59
|
+
first = interval.first
|
60
|
+
last = interval.last
|
61
|
+
else
|
62
|
+
first = interval
|
63
|
+
last = nil
|
64
|
+
end
|
65
|
+
|
66
|
+
if last
|
67
|
+
result = Array.new
|
68
|
+
(first...last).each do |j|
|
69
|
+
search(j).each{|k|result << k}
|
70
|
+
result.uniq!
|
71
|
+
end
|
72
|
+
result.sort_by{|x|[x.first, x.last]}
|
73
|
+
else
|
74
|
+
point_search(self.top_node, first, []).sort_by{|x|[x.first, x.last]}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def ensure_exclusive_end(ranges)
|
81
|
+
ranges.map do |range|
|
82
|
+
case
|
83
|
+
when !range.respond_to?(:exclude_end?)
|
84
|
+
range
|
85
|
+
when range.exclude_end?
|
86
|
+
range
|
87
|
+
else
|
88
|
+
(range.first ... range.end+1)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# augmented tree
|
94
|
+
# using a start point as resresentative value of the node
|
95
|
+
def center(intervals)
|
96
|
+
fs = intervals.sort_by{|x|x.first}
|
97
|
+
fs[fs.length/2].first
|
98
|
+
end
|
99
|
+
|
100
|
+
def point_search(node, point, result)
|
101
|
+
node.s_center.each do |k|
|
102
|
+
result << k if (k.first <= point) && (point < k.last)
|
103
|
+
end
|
104
|
+
if node.left_node && ( point < node.left_node.s_max )
|
105
|
+
point_search(node.left_node, point, []).each{|k|result << k}
|
106
|
+
end
|
107
|
+
if node.right_node && ( node.right_node.x_center <= point )
|
108
|
+
point_search(node.right_node, point, []).each{|k|result << k}
|
109
|
+
end
|
110
|
+
result.uniq
|
111
|
+
end
|
112
|
+
end # class Tree
|
113
|
+
end # module IntervalTree
|
114
|
+
|
115
|
+
if __FILE__ == $0
|
116
|
+
puts "Interval Tree Library"
|
117
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#!/usr/local/bin/ruby-1.9
|
2
|
+
# encoding: utf-8
|
3
|
+
#
|
4
|
+
# Title:: the InclusiveIntervalTree module using "augmented tree"
|
5
|
+
# Author:: MISHIMA, Hiroyuki ( https://github.com/misshie ), 2011
|
6
|
+
# Copyright:: The MIT/X11 license
|
7
|
+
#
|
8
|
+
# see also ....
|
9
|
+
# description in Wikipedia
|
10
|
+
# http://en.wikipedia.org/wiki/Interval_tree
|
11
|
+
# implementstion in Python by Tyler Kahn
|
12
|
+
# http://forrst.com/posts/Interval_Tree_implementation_in_python-e0K
|
13
|
+
#
|
14
|
+
# Usage:
|
15
|
+
# require "interval_tree"
|
16
|
+
# itv = [(0..2), (1..3), (3..4),]
|
17
|
+
# t = InclusiveIntervalTree::Tree.new(itv)
|
18
|
+
# p t.search(2) => [0..2, 1..3]
|
19
|
+
# p t.search(1..3) => [0..2, 1..3, 3..4]
|
20
|
+
#
|
21
|
+
# note: result intervals are always returned
|
22
|
+
# in the "left-closed and right-closed" style that can be expressed
|
23
|
+
# by two-dotted Range object literals (first..last)
|
24
|
+
#
|
25
|
+
|
26
|
+
require 'interval-tree-node'
|
27
|
+
|
28
|
+
module IntervalTree
|
29
|
+
class InclusiveTree
|
30
|
+
def initialize(ranges)
|
31
|
+
ranges_incl = ensure_inclusive_end([ranges].flatten)
|
32
|
+
@top_node = divide_intervals(ranges_incl)
|
33
|
+
end
|
34
|
+
attr_reader :top_node
|
35
|
+
|
36
|
+
def divide_intervals(intervals)
|
37
|
+
return nil if intervals.empty?
|
38
|
+
x_center = center(intervals)
|
39
|
+
|
40
|
+
s_center = Array.new
|
41
|
+
s_left = Array.new
|
42
|
+
s_right = Array.new
|
43
|
+
|
44
|
+
intervals.each do |k|
|
45
|
+
case
|
46
|
+
when k.last < x_center
|
47
|
+
s_left << k
|
48
|
+
when x_center < k.first
|
49
|
+
s_right << k
|
50
|
+
else
|
51
|
+
s_center << k
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
Node.new(x_center, s_center, divide_intervals(s_left), divide_intervals(s_right))
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def search(interval)
|
60
|
+
return [] unless self.top_node
|
61
|
+
ret = nil
|
62
|
+
if interval.respond_to?(:first)
|
63
|
+
first = interval.first
|
64
|
+
last = interval.last
|
65
|
+
else
|
66
|
+
first = interval
|
67
|
+
last = nil
|
68
|
+
end
|
69
|
+
|
70
|
+
if last
|
71
|
+
result = Array.new
|
72
|
+
(interval).each do |j|
|
73
|
+
search(j).each{|k|result << k}
|
74
|
+
result.uniq!
|
75
|
+
end
|
76
|
+
ret = result.sort_by{|x|[x.first, x.last]}
|
77
|
+
else
|
78
|
+
ret = point_search(self.top_node, first, []).sort_by{|x|[x.first, x.last]}
|
79
|
+
end
|
80
|
+
return ret
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def ensure_inclusive_end(ranges)
|
86
|
+
ret = []
|
87
|
+
ranges.each do |r|
|
88
|
+
if r.exclude_end?
|
89
|
+
ret << Range.new(r.first, r.last-1)
|
90
|
+
else
|
91
|
+
ret << r
|
92
|
+
end
|
93
|
+
end
|
94
|
+
ret
|
95
|
+
end
|
96
|
+
|
97
|
+
# augmented tree
|
98
|
+
# using a start point as resresentative value of the node
|
99
|
+
def center(intervals)
|
100
|
+
fs = intervals.sort_by{ |x| x.first}
|
101
|
+
fs[fs.length/2].first
|
102
|
+
end
|
103
|
+
|
104
|
+
def point_search(node, point, result)
|
105
|
+
raise "error" unless node;
|
106
|
+
node.s_center.each do |k|
|
107
|
+
result << k if (k.first <= point) && (point <= k.last)
|
108
|
+
end
|
109
|
+
if point <= node.x_center && node.left_node
|
110
|
+
point_search(node.left_node, point, []).each{ |k| result << k}
|
111
|
+
end
|
112
|
+
if point > node.x_center && node.right_node
|
113
|
+
point_search(node.right_node, point, []).each{ |k| result << k}
|
114
|
+
end
|
115
|
+
result.uniq
|
116
|
+
end
|
117
|
+
end # class Tree
|
118
|
+
end # module IntervalTree
|
119
|
+
|
120
|
+
if __FILE__ == $0
|
121
|
+
puts "Inclusive Interval Tree Library"
|
122
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
|
2
|
+
module IntervalTree
|
3
|
+
|
4
|
+
class Node
|
5
|
+
def initialize(x_center, s_center, left_node, right_node)
|
6
|
+
@x_center = x_center
|
7
|
+
@s_center = s_center.sort_by(&:first)
|
8
|
+
@s_max = s_center.map(&:last).max
|
9
|
+
@left_node = left_node
|
10
|
+
@right_node = right_node
|
11
|
+
end
|
12
|
+
attr_reader :x_center, :s_center, :s_max, :left_node, :right_node
|
13
|
+
end # class Node
|
14
|
+
|
15
|
+
end # module IntervalTree
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: interval-tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,14 +9,18 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-12 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: http://wikipedia.com/wiki/Interval_tree
|
15
15
|
email: gam3-pause@gam3.net
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
|
-
files:
|
19
|
+
files:
|
20
|
+
- lib/inclusive-interval-tree.rb
|
21
|
+
- lib/interval-tree-node.rb
|
22
|
+
- lib/interval-tree.rb
|
23
|
+
- lib/exclusive-interval-tree.rb
|
20
24
|
homepage: https://github.com/gam3/interval-tree
|
21
25
|
licenses: []
|
22
26
|
post_install_message:
|