borel 0.3.2 → 0.3.3
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/Gemfile +1 -0
- data/Guardfile +0 -1
- data/borel.gemspec +3 -3
- data/lib/borel/array.rb +4 -0
- data/lib/borel/errors.rb +7 -0
- data/lib/borel/interval.rb +24 -13
- data/lib/borel/interval_multiple.rb +9 -0
- data/lib/borel/interval_simple.rb +14 -1
- data/lib/borel/math_extensions/interval_arithmetic.rb +4 -2
- data/lib/borel/math_extensions/randomizable.rb +7 -5
- data/lib/borel/nil_class.rb +4 -0
- data/lib/borel/numeric.rb +3 -0
- data/lib/borel/range.rb +3 -0
- data/lib/borel/version.rb +8 -1
- data/tasks/rspec.rb +1 -3
- metadata +6 -7
- data/.rspec +0 -1
data/Gemfile
CHANGED
data/Guardfile
CHANGED
data/borel.gemspec
CHANGED
@@ -7,12 +7,12 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.authors = ["Amadeus Folego"]
|
8
8
|
s.email = ["amadeusfolego@gmail.com"]
|
9
9
|
s.homepage = "http://github.com/badosu/borel"
|
10
|
-
s.summary = "
|
10
|
+
s.summary = "Interval operation on Comparable classes"
|
11
11
|
s.description = "Borel sets are made of enumerable union and intersection of
|
12
|
-
intervals. Borel performs regular operations on
|
12
|
+
intervals. Borel performs regular operations on intervals of any
|
13
13
|
Comparable class."
|
14
14
|
s.rubyforge_project = s.name
|
15
|
-
s.required_ruby_version = ">= 1.9.
|
15
|
+
s.required_ruby_version = ">= 1.9.2"
|
16
16
|
s.required_rubygems_version = ">= 1.3.6"
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.require_path = 'lib'
|
data/lib/borel/array.rb
CHANGED
data/lib/borel/errors.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Borel
|
2
|
+
# Raised when an interval is not properly initialized
|
2
3
|
class Construction < ArgumentError
|
3
4
|
def initialize(array)
|
4
5
|
super(
|
@@ -8,24 +9,30 @@ module Borel
|
|
8
9
|
end
|
9
10
|
end
|
10
11
|
|
12
|
+
# Raised when a non-degenerate interval calls a method supported only for
|
13
|
+
# degenerate intervals
|
11
14
|
class NonDegenerate < ArgumentError
|
12
15
|
def initialize(i)
|
13
16
|
super("#{i.inspect} is not degenerate.")
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
20
|
+
# Raised when a non simple interval calls a method supported only for simple
|
21
|
+
# intervals
|
17
22
|
class NonSimple < ArgumentError
|
18
23
|
def initialize(i)
|
19
24
|
super("#{i.inspect} is not simple.")
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
28
|
+
# Raised when a method is not supported for empty intervals
|
23
29
|
class EmptyInterval < ArgumentError
|
24
30
|
def initialize
|
25
31
|
super("The interval is empty.")
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
35
|
+
# Raised when the {Range#to_interval} is not called properly
|
29
36
|
class OpenRight < ArgumentError
|
30
37
|
def initialize(range)
|
31
38
|
super(
|
data/lib/borel/interval.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'borel/errors'
|
2
2
|
|
3
|
+
# Exposes infinity for initializing unbounded intervals
|
3
4
|
Infinity = 1/0.0
|
4
5
|
|
6
|
+
# Retains all non-specific Interval logic
|
5
7
|
class Interval
|
6
8
|
include Enumerable
|
7
9
|
|
10
|
+
# @return [Interval]
|
8
11
|
def self.[](*array)
|
9
12
|
union(*
|
10
13
|
if array.empty?
|
@@ -22,39 +25,45 @@ class Interval
|
|
22
25
|
raise
|
23
26
|
end
|
24
27
|
|
28
|
+
# @return [Interval]
|
25
29
|
def self.union(*array)
|
26
|
-
|
27
|
-
array.map(&:components).flatten.sort_by(&:inf).each do |
|
28
|
-
if
|
30
|
+
intervals = []
|
31
|
+
array.map(&:components).flatten.sort_by(&:inf).each do |component|
|
32
|
+
if component.sup < component.inf
|
29
33
|
next
|
30
|
-
elsif
|
31
|
-
|
32
|
-
elsif
|
33
|
-
|
34
|
+
elsif intervals.empty? || component.inf > intervals.last.sup
|
35
|
+
intervals <<= component
|
36
|
+
elsif component.sup > intervals.last.sup
|
37
|
+
intervals[-1] = Simple.new(intervals.last.inf, component.sup)
|
34
38
|
end
|
35
39
|
end
|
36
|
-
|
40
|
+
intervals.size == 1 ? intervals.first : Multiple.new(intervals)
|
37
41
|
end
|
38
42
|
|
43
|
+
# @return [Interval]
|
39
44
|
def union(other)
|
40
45
|
Interval.union(other.to_interval, self)
|
41
46
|
end
|
42
47
|
|
48
|
+
# @return [Interval]
|
43
49
|
def intersect(other)
|
44
50
|
other.to_interval.map{|y| map{|x| x.intersect(y)}}.
|
45
51
|
flatten.reduce(:union) || Interval[]
|
46
52
|
end
|
47
53
|
|
54
|
+
# @return [Interval]
|
48
55
|
def complement
|
49
56
|
map{|x| x.to_interval.map(&:complement).reduce(:intersect)}.
|
50
57
|
flatten.reduce(:union)
|
51
58
|
end
|
52
59
|
|
60
|
+
# @return [Interval]
|
53
61
|
def intersect(other)
|
54
62
|
other.to_interval.map{|y| map{|x| x.intersect(y)}}.
|
55
63
|
flatten.reduce(:union) || Interval[]
|
56
64
|
end
|
57
65
|
|
66
|
+
# @return [Interval]
|
58
67
|
def minus(other)
|
59
68
|
if other.empty?
|
60
69
|
self
|
@@ -64,32 +73,34 @@ class Interval
|
|
64
73
|
end
|
65
74
|
end
|
66
75
|
|
76
|
+
# @return [Boolean]
|
67
77
|
def ==(other)
|
68
78
|
construction == other.construction
|
69
79
|
end
|
70
80
|
|
81
|
+
# @return [Boolean]
|
71
82
|
def empty?
|
72
83
|
components.empty?
|
73
84
|
end
|
74
85
|
|
86
|
+
# @return [Interval]
|
75
87
|
def to_interval
|
76
88
|
self
|
77
89
|
end
|
78
90
|
|
91
|
+
# @return [String]
|
79
92
|
def inspect
|
80
93
|
"Interval" + construction.inspect
|
81
94
|
end
|
82
95
|
|
96
|
+
# @return [String]
|
83
97
|
def to_s
|
84
98
|
inspect
|
85
99
|
end
|
86
100
|
|
101
|
+
# @return [Interval]
|
87
102
|
def hull
|
88
|
-
if empty?
|
89
|
-
Interval[]
|
90
|
-
else
|
91
|
-
Interval[inf, sup]
|
92
|
-
end
|
103
|
+
if empty? then Interval[] else Interval[inf, sup] end
|
93
104
|
end
|
94
105
|
|
95
106
|
alias_method :+, :union
|
@@ -1,36 +1,45 @@
|
|
1
|
+
# Retains the logic specific for intervals with multiple components
|
1
2
|
class Interval::Multiple < Interval
|
2
3
|
attr :components
|
3
4
|
|
5
|
+
# @return [Interval]
|
4
6
|
def initialize(array)
|
5
7
|
@components = array
|
6
8
|
freeze
|
7
9
|
end
|
8
10
|
|
11
|
+
# @return [Interval]
|
9
12
|
def each
|
10
13
|
components.each{|o| yield(o)}
|
11
14
|
self
|
12
15
|
end
|
13
16
|
|
17
|
+
# @return [Object]
|
14
18
|
def inf
|
15
19
|
components.first.inf
|
16
20
|
end
|
17
21
|
|
22
|
+
# @return [Object]
|
18
23
|
def sup
|
19
24
|
components.last.sup
|
20
25
|
end
|
21
26
|
|
27
|
+
# @return [Array]
|
22
28
|
def construction
|
23
29
|
map &:construction
|
24
30
|
end
|
25
31
|
|
32
|
+
# @return [Boolean]
|
26
33
|
def include?(x)
|
27
34
|
any?{|i| i.include? x}
|
28
35
|
end
|
29
36
|
|
37
|
+
# @return [Boolean]
|
30
38
|
def degenerate?
|
31
39
|
all? &:degenerate?
|
32
40
|
end
|
33
41
|
|
42
|
+
# @return [Boolean]
|
34
43
|
def simple?
|
35
44
|
false
|
36
45
|
end
|
@@ -1,5 +1,8 @@
|
|
1
|
+
# Retains the logic specific for intervals with a single component
|
2
|
+
# in the form [inf,sup]
|
1
3
|
class Interval::Simple < Interval
|
2
|
-
attr :inf
|
4
|
+
attr :inf
|
5
|
+
attr :sup
|
3
6
|
|
4
7
|
def initialize (a, b = a)
|
5
8
|
if (a.respond_to?(:nan?) && a.nan?) || (b.respond_to?(:nan?) && b.nan?)
|
@@ -10,43 +13,53 @@ class Interval::Simple < Interval
|
|
10
13
|
freeze
|
11
14
|
end
|
12
15
|
|
16
|
+
# @return [Simple]
|
13
17
|
def each
|
14
18
|
yield(self)
|
15
19
|
self
|
16
20
|
end
|
17
21
|
|
22
|
+
# @return [Interval]
|
18
23
|
def intersect(other)
|
19
24
|
Interval[[inf, other.inf].max, [sup, other.sup].min]
|
20
25
|
end
|
21
26
|
|
27
|
+
# @return [Interval::Multiple]
|
22
28
|
def complement
|
23
29
|
Interval[[-Infinity, inf], [sup, Infinity]]
|
24
30
|
end
|
25
31
|
|
32
|
+
# @return [Interval]
|
26
33
|
def minus(other)
|
27
34
|
other.complement.intersect self
|
28
35
|
end
|
29
36
|
|
37
|
+
# @return [Array<Interval>]
|
30
38
|
def components
|
31
39
|
[self]
|
32
40
|
end
|
33
41
|
|
42
|
+
# @return [Array]
|
34
43
|
def extrema
|
35
44
|
[inf, sup]
|
36
45
|
end
|
37
46
|
|
47
|
+
# @return [Array]
|
38
48
|
def construction
|
39
49
|
extrema.uniq
|
40
50
|
end
|
41
51
|
|
52
|
+
# @return [Boolean]
|
42
53
|
def include?(x)
|
43
54
|
inf <= x && x <= sup
|
44
55
|
end
|
45
56
|
|
57
|
+
# @return [Boolean]
|
46
58
|
def degenerate?
|
47
59
|
inf == sup
|
48
60
|
end
|
49
61
|
|
62
|
+
# @return [Boolean]
|
50
63
|
def simple?
|
51
64
|
true
|
52
65
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'borel'
|
2
2
|
|
3
3
|
module Borel
|
4
|
+
# Includes numeric intervals related methods
|
4
5
|
module IntervalArithmetic
|
6
|
+
# @return [Number] the width of the interval
|
5
7
|
def width
|
6
|
-
raise NonSimple, self unless
|
7
|
-
|
8
|
+
raise NonSimple, self unless respond_to?(:simple?) and simple?
|
9
|
+
extrema.last - extrema.first
|
8
10
|
end
|
9
11
|
|
10
12
|
Interval.send(:include, self)
|
@@ -1,16 +1,18 @@
|
|
1
1
|
require 'borel/math_extensions/interval_arithmetic'
|
2
2
|
|
3
3
|
module Borel
|
4
|
+
# Includes methods for picking random elements on intervals
|
4
5
|
module Randomizable
|
6
|
+
# @return [Object] a random element of the interval
|
5
7
|
def rand
|
6
|
-
raise EmptyInterval if
|
8
|
+
raise EmptyInterval if respond_to?(:empty?) and empty?
|
7
9
|
|
8
|
-
if
|
9
|
-
Random.new.rand Range.new *
|
10
|
+
if simple?
|
11
|
+
Random.new.rand Range.new *extrema
|
10
12
|
else
|
11
|
-
total_weight =
|
13
|
+
total_weight = map(&:width).reduce(:+)
|
12
14
|
selected_weight = Random.new.rand 0..total_weight
|
13
|
-
rand_interval =
|
15
|
+
rand_interval = find{|c| (selected_weight -= c.width) <= 0}
|
14
16
|
Random.new.rand Range.new *rand_interval.extrema
|
15
17
|
end
|
16
18
|
end
|
data/lib/borel/nil_class.rb
CHANGED
data/lib/borel/numeric.rb
CHANGED
data/lib/borel/range.rb
CHANGED
data/lib/borel/version.rb
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
+
# Namespace for all interval related classes
|
1
2
|
module Borel
|
3
|
+
# Major version number
|
2
4
|
MAJOR = 0
|
5
|
+
# Minor version number
|
3
6
|
MINOR = 3
|
4
|
-
|
7
|
+
# Tiny version number
|
8
|
+
TINY = 3
|
5
9
|
|
10
|
+
# Joins the version numbers
|
6
11
|
VERSION = [MAJOR, MINOR, TINY].join('.')
|
7
12
|
|
13
|
+
# Returns {VERSION}
|
14
|
+
# @return [String]
|
8
15
|
def self.version
|
9
16
|
VERSION
|
10
17
|
end
|
data/tasks/rspec.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: borel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-13 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'Borel sets are made of enumerable union and intersection of
|
15
15
|
|
16
|
-
intervals. Borel performs regular operations on
|
16
|
+
intervals. Borel performs regular operations on intervals of any
|
17
17
|
|
18
18
|
Comparable class.'
|
19
19
|
email:
|
@@ -23,7 +23,6 @@ extensions: []
|
|
23
23
|
extra_rdoc_files: []
|
24
24
|
files:
|
25
25
|
- .gitignore
|
26
|
-
- .rspec
|
27
26
|
- Gemfile
|
28
27
|
- Guardfile
|
29
28
|
- LICENSE
|
@@ -65,7 +64,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
64
|
requirements:
|
66
65
|
- - ! '>='
|
67
66
|
- !ruby/object:Gem::Version
|
68
|
-
version: 1.9.
|
67
|
+
version: 1.9.2
|
69
68
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
69
|
none: false
|
71
70
|
requirements:
|
@@ -74,9 +73,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
73
|
version: 1.3.6
|
75
74
|
requirements: []
|
76
75
|
rubyforge_project: borel
|
77
|
-
rubygems_version: 1.8.
|
76
|
+
rubygems_version: 1.8.21
|
78
77
|
signing_key:
|
79
78
|
specification_version: 3
|
80
|
-
summary:
|
79
|
+
summary: Interval operation on Comparable classes
|
81
80
|
test_files: []
|
82
81
|
has_rdoc:
|
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--colour
|