borel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,6 @@
1
+ Borel
2
+ =====
3
+
4
+ Borelian sets are sets formed by the enumerable union and intersection, or the complement, of intervals in the Real line.
5
+
6
+ **Borel** aims to make it really easy to make union and intersection operations of interval in any ordered set.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ task_file_pattern = File.expand_path("../tasks/**/*.rb", __FILE__)
2
+ Dir[task_file_pattern].each do |task_file|
3
+ require File.expand_path(task_file)
4
+ end
5
+
6
+ task :default => [ :rspec ]
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,3 @@
1
+ require 'borel/interval'
2
+ require 'borel/range'
3
+ require 'borel/numeric'
@@ -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
@@ -0,0 +1,5 @@
1
+ class Numeric
2
+ def to_interval
3
+ Interval[self]
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ class Range
2
+ def to_interval
3
+ Interval[first,
4
+ if exclude_end?
5
+ (last - 1).succ - 1
6
+ else
7
+ last
8
+ end]
9
+ rescue NoMethodError
10
+ raise Borel::OpenRight, self if exclude_end? && !last.respond_to?(:succ)
11
+ raise
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Borel
2
+ MAJOR = 0
3
+ MINOR = 0
4
+ TINY = 1
5
+
6
+ VERSION = [MAJOR, MINOR, TINY].join('.')
7
+
8
+ def self.version
9
+ VERSION
10
+ end
11
+ end
@@ -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
@@ -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
@@ -0,0 +1,4 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ desc "Run specifications"
4
+ RSpec::Core::RakeTask.new(:rspec)
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: []