borel 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/MIT-LICENSE +18 -0
- data/README.md +6 -0
- data/Rakefile +6 -0
- data/borel.gemspec +17 -0
- data/lib/borel.rb +3 -0
- data/lib/borel/interval.rb +226 -0
- data/lib/borel/numeric.rb +5 -0
- data/lib/borel/range.rb +13 -0
- data/lib/borel/version.rb +11 -0
- data/spec/interval_spec.rb +116 -0
- data/spec/range_spec.rb +30 -0
- data/tasks/gem.rb +28 -0
- data/tasks/rspec.rb +4 -0
- metadata +61 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Copyright (c) 2012 Amadeus Folego
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to
|
5
|
+
deal in the Software without restriction, including without limitation the
|
6
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
7
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
18
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
data/borel.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'borel/version.rb'
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "borel"
|
5
|
+
s.version = Borel.version
|
6
|
+
s.platform = Gem::Platform::RUBY
|
7
|
+
s.authors = ["Amadeus Folego"]
|
8
|
+
s.email = ["amadeusfolego@gmail.com"]
|
9
|
+
s.homepage = "http://github.com/amadeusfolego/borel"
|
10
|
+
s.summary = "Generic ordered set's operations"
|
11
|
+
s.description = "Borel sets are made of enumerable union and intersection of intervals. Borel performs regular set operations on any interval of a Comparable class."
|
12
|
+
s.rubyforge_project = s.name
|
13
|
+
s.required_ruby_version = ">= 1.9.3"
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.require_path = 'lib'
|
17
|
+
end
|
data/lib/borel.rb
ADDED
@@ -0,0 +1,226 @@
|
|
1
|
+
Infinity = 1/0.0
|
2
|
+
|
3
|
+
class Interval
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def Interval.[](*array)
|
7
|
+
union(*
|
8
|
+
if array.empty?
|
9
|
+
[]
|
10
|
+
elsif array.first.kind_of?(Array)
|
11
|
+
array.select{|x| !x.empty?}.map{|x| Simple.new(*x)}
|
12
|
+
else
|
13
|
+
[Simple.new(*array)]
|
14
|
+
end
|
15
|
+
)
|
16
|
+
rescue
|
17
|
+
unless
|
18
|
+
array.size <= 2 || array.all?{|x| Array === x && x.size <= 2}
|
19
|
+
raise Exception::Construction, array
|
20
|
+
end
|
21
|
+
raise
|
22
|
+
end
|
23
|
+
|
24
|
+
def Interval.union(*array)
|
25
|
+
l = []
|
26
|
+
array.map(&:components).flatten.sort_by(&:inf).each{|x|
|
27
|
+
if x.sup < x.inf
|
28
|
+
# skip it
|
29
|
+
elsif l.empty? || x.inf > l.last.sup
|
30
|
+
l <<= x
|
31
|
+
elsif x.sup > l.last.sup
|
32
|
+
l[-1] = Simple.new(l.last.inf, x.sup)
|
33
|
+
end
|
34
|
+
}
|
35
|
+
if l.size == 1
|
36
|
+
l.first
|
37
|
+
else
|
38
|
+
Multiple.new(l)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def construction
|
43
|
+
map{|x| x.extrema.uniq}
|
44
|
+
end
|
45
|
+
|
46
|
+
def simple?
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
def inspect
|
51
|
+
"Interval" + construction.inspect
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
inspect
|
56
|
+
end
|
57
|
+
|
58
|
+
def ==(other)
|
59
|
+
self.components == other.components
|
60
|
+
end
|
61
|
+
|
62
|
+
def include?(x)
|
63
|
+
any?{|i| i.include? x}
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_interval
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
def coerce(other)
|
71
|
+
[other.to_interval, self]
|
72
|
+
end
|
73
|
+
|
74
|
+
def +(other)
|
75
|
+
self | other
|
76
|
+
end
|
77
|
+
|
78
|
+
def ^(other)
|
79
|
+
self & other
|
80
|
+
end
|
81
|
+
|
82
|
+
def |(other)
|
83
|
+
Interval.union(other.to_interval, self)
|
84
|
+
end
|
85
|
+
|
86
|
+
def empty?
|
87
|
+
components.empty?
|
88
|
+
end
|
89
|
+
|
90
|
+
def degenerate?
|
91
|
+
all? {|x| x.degenerate?}
|
92
|
+
end
|
93
|
+
|
94
|
+
def hull
|
95
|
+
if empty?
|
96
|
+
Interval[]
|
97
|
+
else
|
98
|
+
Interval[components.first.inf, components.last.sup]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
[[:&, :intersect]].each do |op, meth|
|
103
|
+
define_method(op) {|other|
|
104
|
+
(other.to_interval.map{|y| map{|x| x.send(meth,y)}}.flatten).reduce(:|)
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
[[:~, :complement]].each do |op, meth|
|
109
|
+
define_method(op) {
|
110
|
+
map{|x| x.to_interval.map(&meth).reduce(:&)}.flatten.reduce(:|)
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
[[:-, :minus]].each do |op, meth|
|
115
|
+
define_method(op) {|other|
|
116
|
+
map{|x| other.to_interval.map{|y| x.send(meth,y)}.reduce(:&)}.flatten.reduce(:|)
|
117
|
+
}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Interval::Simple < Interval
|
122
|
+
include Enumerable
|
123
|
+
|
124
|
+
attr :inf
|
125
|
+
attr :sup
|
126
|
+
|
127
|
+
def each
|
128
|
+
yield(self)
|
129
|
+
self
|
130
|
+
end
|
131
|
+
|
132
|
+
def components
|
133
|
+
[self]
|
134
|
+
end
|
135
|
+
|
136
|
+
def initialize (a, b = a)
|
137
|
+
if (a.respond_to?(:nan?) && a.nan? ) || (b.respond_to?(:nan?) && b.nan?)
|
138
|
+
@inf, @sup = -Infinity, Infinity
|
139
|
+
else
|
140
|
+
@inf, @sup = a, b
|
141
|
+
end
|
142
|
+
freeze
|
143
|
+
end
|
144
|
+
|
145
|
+
def ==(other)
|
146
|
+
[inf, sup] == [other.inf, other.sup]
|
147
|
+
end
|
148
|
+
|
149
|
+
def intersect(other)
|
150
|
+
Interval[[inf, other.inf].max, [sup, other.sup].min]
|
151
|
+
end
|
152
|
+
|
153
|
+
def complement
|
154
|
+
Interval[-Infinity,inf] | Interval[sup,Infinity]
|
155
|
+
end
|
156
|
+
|
157
|
+
def minus (other)
|
158
|
+
self & ~other
|
159
|
+
end
|
160
|
+
|
161
|
+
def construction
|
162
|
+
extrema.uniq
|
163
|
+
end
|
164
|
+
|
165
|
+
def simple?
|
166
|
+
true
|
167
|
+
end
|
168
|
+
|
169
|
+
def include?(x)
|
170
|
+
inf <= x && x <= sup
|
171
|
+
end
|
172
|
+
|
173
|
+
def extrema
|
174
|
+
[inf, sup]
|
175
|
+
end
|
176
|
+
|
177
|
+
def degenerate?
|
178
|
+
inf == sup
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class Interval::Multiple < Interval
|
183
|
+
|
184
|
+
attr :components
|
185
|
+
|
186
|
+
def initialize(array)
|
187
|
+
@components = array
|
188
|
+
freeze
|
189
|
+
end
|
190
|
+
|
191
|
+
def each
|
192
|
+
components.each{|o| yield(o)}
|
193
|
+
self
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
module Borel
|
198
|
+
class Construction < ArgumentError
|
199
|
+
def initialize(array)
|
200
|
+
super(
|
201
|
+
"An interval can only be constructed either from at most two " \
|
202
|
+
"numbers or from a sequence of arrays of at most two numbers: " +
|
203
|
+
array.inspect)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class NonDegenerate < ArgumentError
|
208
|
+
def initialize(i)
|
209
|
+
super("#{i.inspect} is not degenerate.")
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
class NonSimple < ArgumentError
|
214
|
+
def initialize(i)
|
215
|
+
super("#{i.inspect} is not simple.")
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class OpenRight < ArgumentError
|
220
|
+
def initialize(range)
|
221
|
+
super(
|
222
|
+
"Cannot construct an interval from a three-dot range " \
|
223
|
+
"with end-value #{range.last.inspect}.")
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
data/lib/borel/range.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'borel/interval'
|
2
|
+
|
3
|
+
describe Interval do
|
4
|
+
context '#intersection' do
|
5
|
+
|
6
|
+
it "[]^[0,3] = []" do
|
7
|
+
pending
|
8
|
+
(Interval[] ^ Interval[0,3]).should eq Interval[]
|
9
|
+
end
|
10
|
+
|
11
|
+
it "[0,3]^[] = []" do
|
12
|
+
pending
|
13
|
+
(Interval[0,3] ^ Interval[]).should eq Interval[]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "[0,2]^[1] = [1]" do
|
17
|
+
(Interval[0,2] ^ Interval[1]).should eq Interval[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "[-infty, infty]^[0,1] = [0,1]" do
|
21
|
+
(Interval[-Infinity, Infinity] ^ Interval[0,1]).should eq Interval[0,1]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "[0,3]^[1,2] = [1,2]" do
|
25
|
+
(Interval[0,3] ^ Interval[1,2]).should eq Interval[1,2]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "[[-2,-1],[1,2]]^[[0,3],[4,5]] = [1,2]" do
|
29
|
+
(Interval[[-2,-1],[1,2]] ^ Interval[[0,3],[4,5]]).should eq Interval[1,2]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context '#union' do
|
34
|
+
it "[0,3]U[1,2] = [0,3]" do
|
35
|
+
(Interval[0,3] | Interval[1,2]).should eq Interval[0,3]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "[1,2]U[0,3] = [0,3]" do
|
39
|
+
(Interval[1,2] | Interval[0,3]).should eq Interval[0,3]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "[1,2]U[1,2] = [1,2]" do
|
43
|
+
(Interval[1,2] | Interval[1,2]).should eq Interval[1,2]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "[1,2]U[2,3] = [1,3]" do
|
47
|
+
(Interval[1,2] | Interval[2,3]).should eq Interval[1,3]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "[1,2]U[3,4] = [[1,2],[3,4]]" do
|
51
|
+
(Interval[1,2] | Interval[3,4]).should eq Interval[[1,2],[3,4]]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context '#minus' do
|
56
|
+
it "[2,3]-(0,1) = [2,3]" do
|
57
|
+
(Interval[2,3] - Interval[0,1]).should eq Interval[2,3]
|
58
|
+
end
|
59
|
+
|
60
|
+
it '[0,1]-(2,3) = [0,1]' do
|
61
|
+
(Interval[0,1] - Interval[2,3]).should eq Interval[0,1]
|
62
|
+
end
|
63
|
+
|
64
|
+
it '[1,2]-(0,3) = []' do
|
65
|
+
(Interval[1,2] - Interval[0,3]).should be_empty
|
66
|
+
end
|
67
|
+
|
68
|
+
it '[0,3]-(1,2) = [0,1]U[2,3]' do
|
69
|
+
(Interval[0,3] - Interval[1,2]).should eq Interval[[0,1],[2,3]]
|
70
|
+
end
|
71
|
+
|
72
|
+
it '[0,1]-(0,1) = [0]U[1]' do
|
73
|
+
(Interval[0,1] - Interval[0,1]).should eq Interval[0] | Interval[1]
|
74
|
+
end
|
75
|
+
|
76
|
+
it '[1,2]-(2,3) = [1,2]' do
|
77
|
+
(Interval[1,2] - Interval[2,3]).should eq Interval[1,2]
|
78
|
+
end
|
79
|
+
|
80
|
+
it '[2,3]-(1,2) = [2,3]' do
|
81
|
+
(Interval[2,3] - Interval[1,2]).should eq Interval[2,3]
|
82
|
+
end
|
83
|
+
|
84
|
+
it '[1,4]-(0,3) = [3,4]' do
|
85
|
+
(Interval[1,4] - Interval[0,3]).should eq Interval[3,4]
|
86
|
+
end
|
87
|
+
|
88
|
+
it '[1,3]-(2,4) = [1,2]' do
|
89
|
+
(Interval[1,3] - Interval[2,4]).should eq Interval[1,2]
|
90
|
+
end
|
91
|
+
|
92
|
+
it '[1,4]-(1,3) = [1]U[3,4]' do
|
93
|
+
(Interval[1,4] - Interval[1,3]).should eq Interval[3,4] | Interval[1]
|
94
|
+
end
|
95
|
+
|
96
|
+
it '[1,4]-(1,5) = [1]' do
|
97
|
+
(Interval[1,4] - Interval[1,5]).should eq Interval[1]
|
98
|
+
end
|
99
|
+
|
100
|
+
it '[1,3]-(2,3) = [1,2]U[3]' do
|
101
|
+
(Interval[1,3] - Interval[2,3]).should eq Interval[1,2] | Interval[3]
|
102
|
+
end
|
103
|
+
|
104
|
+
it '[1,3]-(0,3) = [3]' do
|
105
|
+
(Interval[1,3] - Interval[0,3]).should eq Interval[3]
|
106
|
+
end
|
107
|
+
|
108
|
+
it '[-infty,infty]-[0,1] = [-infty,0]U[1,infty]' do
|
109
|
+
(Interval[-Infinity,Infinity] - Interval[0,1]).should eq Interval[-Infinity,0]|Interval[1,Infinity]
|
110
|
+
end
|
111
|
+
|
112
|
+
it '[0,1]-[-infty,infty] = []' do
|
113
|
+
(Interval[0,1] - Interval[-Infinity,Infinity]).should eq Interval[]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/spec/range_spec.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'borel/interval'
|
2
|
+
require 'borel/range'
|
3
|
+
|
4
|
+
describe Range do
|
5
|
+
context '#to_interval' do
|
6
|
+
it '(1..3) should be [1,3]' do
|
7
|
+
(1..3).to_interval.should eq Interval[1,3]
|
8
|
+
end
|
9
|
+
|
10
|
+
it '(1...3) should be [1,2]' do
|
11
|
+
(1...3).to_interval.should eq Interval[1,2]
|
12
|
+
end
|
13
|
+
|
14
|
+
it '(1..Infinity) should be [1,infty]' do
|
15
|
+
(1..Infinity).to_interval.should eq Interval[1,Infinity]
|
16
|
+
end
|
17
|
+
|
18
|
+
it '(1...Infinity) should raise OpenRight' do
|
19
|
+
expect{(1...Infinity).to_interval}.to raise_error Borel::OpenRight
|
20
|
+
end
|
21
|
+
|
22
|
+
it '(-Infinity..1) should be [-infty,1]' do
|
23
|
+
(-Infinity..1).to_interval.should eq Interval[-Infinity,1]
|
24
|
+
end
|
25
|
+
|
26
|
+
it '(-Infinity..Infinity) should be [-infty,infty]' do
|
27
|
+
(-Infinity..Infinity).to_interval.should eq Interval[-Infinity,Infinity]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/tasks/gem.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
gemspec = eval(File.read("borel.gemspec"))
|
2
|
+
|
3
|
+
desc "Validate the gemspec"
|
4
|
+
task :gemspec do
|
5
|
+
gemspec.validate
|
6
|
+
end
|
7
|
+
|
8
|
+
desc "Build gem locally"
|
9
|
+
task :build => :gemspec do
|
10
|
+
system "gem build #{gemspec.name}.gemspec"
|
11
|
+
FileUtils.mkdir_p "pkg"
|
12
|
+
FileUtils.mv "#{gemspec.name}-#{gemspec.version}.gem", "pkg"
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Install gem locally"
|
16
|
+
task :install => :build do
|
17
|
+
system "gem install pkg/#{gemspec.name}-#{gemspec.version}"
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Launches interactive console with borel"
|
21
|
+
task :console => :install do
|
22
|
+
system "irb -r #{gemspec.name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Clean automatically generated files"
|
26
|
+
task :clean do
|
27
|
+
FileUtils.rm_rf "pkg"
|
28
|
+
end
|
data/tasks/rspec.rb
ADDED
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: borel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Amadeus Folego
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-12 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Borel sets are made of enumerable union and intersection of intervals.
|
15
|
+
Borel performs regular set operations on any interval of a Comparable class.
|
16
|
+
email:
|
17
|
+
- amadeusfolego@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gitignore
|
23
|
+
- .rspec
|
24
|
+
- MIT-LICENSE
|
25
|
+
- README.md
|
26
|
+
- Rakefile
|
27
|
+
- borel.gemspec
|
28
|
+
- lib/borel.rb
|
29
|
+
- lib/borel/interval.rb
|
30
|
+
- lib/borel/numeric.rb
|
31
|
+
- lib/borel/range.rb
|
32
|
+
- lib/borel/version.rb
|
33
|
+
- spec/interval_spec.rb
|
34
|
+
- spec/range_spec.rb
|
35
|
+
- tasks/gem.rb
|
36
|
+
- tasks/rspec.rb
|
37
|
+
homepage: http://github.com/amadeusfolego/borel
|
38
|
+
licenses: []
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 1.9.3
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.3.6
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project: borel
|
57
|
+
rubygems_version: 1.8.11
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: Generic ordered set's operations
|
61
|
+
test_files: []
|