more_math 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/CHANGES +6 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/more_math.rb +2 -0
- data/lib/more_math/cantor_pairing_function.rb +2 -2
- data/lib/more_math/distributions.rb +2 -2
- data/lib/more_math/functions.rb +1 -1
- data/lib/more_math/permutation.rb +257 -0
- data/lib/more_math/ranking_common.rb +93 -0
- data/lib/more_math/subset.rb +46 -0
- data/lib/more_math/version.rb +1 -1
- data/more_math.gemspec +8 -8
- data/tests/test_permutation.rb +254 -0
- data/tests/{test_analysis.rb → test_sequence.rb} +0 -0
- data/tests/test_subset.rb +21 -0
- metadata +19 -9
data/.gitignore
CHANGED
data/CHANGES
CHANGED
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ GemHadar do
|
|
10
10
|
summary 'Library that provides more mathematics.'
|
11
11
|
description 'Library that provides more mathematical functions/algorithms than standard Ruby.'
|
12
12
|
test_dir 'tests'
|
13
|
-
ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock'
|
13
|
+
ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', 'coverage', '.rvmrc'
|
14
14
|
readme 'README.rdoc'
|
15
15
|
title "#{name.camelize} -- More Math in Ruby"
|
16
16
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/lib/more_math.rb
CHANGED
@@ -4,7 +4,7 @@ module MoreMath
|
|
4
4
|
module CantorPairingFunction
|
5
5
|
|
6
6
|
module_function
|
7
|
-
|
7
|
+
|
8
8
|
def cantor_pairing(*xs)
|
9
9
|
if xs.size == 1 and xs.first.respond_to?(:to_ary)
|
10
10
|
xs = xs.first.to_ary
|
@@ -31,7 +31,7 @@ module MoreMath
|
|
31
31
|
end
|
32
32
|
v - 1
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def cantor_pairing_inv(c, n = 2)
|
36
36
|
raise ArgumentError, "n is required to be >= 2" unless n >= 2
|
37
37
|
result = []
|
@@ -111,7 +111,7 @@ module MoreMath
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
# Returns the inverse cumulative probability (t-value) of the TDistribution
|
116
116
|
# for the probability +p+.
|
117
117
|
def inverse_probability(p)
|
@@ -120,7 +120,7 @@ module MoreMath
|
|
120
120
|
-1 / 0.0
|
121
121
|
when p >= 1
|
122
122
|
1 / 0.0
|
123
|
-
else
|
123
|
+
else
|
124
124
|
begin
|
125
125
|
bisect = NewtonBisection.new { |x| probability(x) - p }
|
126
126
|
range = bisect.bracket(-10..10)
|
data/lib/more_math/functions.rb
CHANGED
@@ -60,7 +60,7 @@ module MoreMath
|
|
60
60
|
-((a + m) * (a + b + m) * x) / ((a + 2 * m) * (a + 2 * m + 1))
|
61
61
|
end
|
62
62
|
end
|
63
|
-
exp(a * log(x) + b * log(1.0 - x) - log(a) - log_beta(a, b)) /
|
63
|
+
exp(a * log(x) + b * log(1.0 - x) - log(a) - log_beta(a, b)) /
|
64
64
|
fraction[x, epsilon, max_iterations]
|
65
65
|
end
|
66
66
|
rescue Errno::ERANGE, Errno::EDOM
|
@@ -0,0 +1,257 @@
|
|
1
|
+
require 'more_math/ranking_common'
|
2
|
+
|
3
|
+
module MoreMath
|
4
|
+
class Permutation
|
5
|
+
include Enumerable
|
6
|
+
include Comparable
|
7
|
+
include RankingCommon
|
8
|
+
|
9
|
+
# Creates a new Permutation instance of <code>size</code>
|
10
|
+
# (and ranked with <code>rank</code>).
|
11
|
+
def initialize(size, rank = 0)
|
12
|
+
@size, self.rank = size, rank
|
13
|
+
@last = factorial(size) - 1
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a new Permutation instance from the Array
|
17
|
+
# <code>indices</code>, that should consist of a permutation of Fixnums
|
18
|
+
# in the range of <code>0</code> and <code>indices.size - 1</code>. This is
|
19
|
+
# for example the result of a call to the Permutation#value method.
|
20
|
+
def self.from_value(indices)
|
21
|
+
obj = new(indices.size)
|
22
|
+
obj.instance_eval do
|
23
|
+
self.rank = rank_indices(indices)
|
24
|
+
end
|
25
|
+
obj
|
26
|
+
end
|
27
|
+
|
28
|
+
# Creates a new Permutation instance from the Array of Arrays
|
29
|
+
# <code>cycles</code>. This is for example the result of a
|
30
|
+
# call to the Permutation#cycles method .
|
31
|
+
def self.from_cycles(cycles, max = 0)
|
32
|
+
indices = Array.new(max)
|
33
|
+
cycles.each do |cycle|
|
34
|
+
cycle.empty? and next
|
35
|
+
for i in 0...cycle.size
|
36
|
+
indices[ cycle[i - 1] ] = cycle[i]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
indices.each_with_index { |r, i| r or indices[i] = i }
|
40
|
+
from_value(indices)
|
41
|
+
end
|
42
|
+
|
43
|
+
# A permutation instance of size collection.size is created with
|
44
|
+
# collection as the default Permutation#project data object. A
|
45
|
+
# collection should respond to size, [], and []=. The Permutation
|
46
|
+
# instance will default to rank 0 if none is given.
|
47
|
+
def self.for(collection, rank = 0)
|
48
|
+
perm = new(collection.size, rank)
|
49
|
+
perm.instance_variable_set(:@collection, collection)
|
50
|
+
perm
|
51
|
+
end
|
52
|
+
|
53
|
+
# Assigns <code>m</code> to the rank attribute of this Permutation
|
54
|
+
# instance. That implies that the indices produced by a call to the
|
55
|
+
# Permutation#value method of this instance is the permutation ranked with
|
56
|
+
# this new <code>rank</code>.
|
57
|
+
def rank=(m)
|
58
|
+
@rank = m % factorial(size)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the indices in the range of 0 to Permutation#size - 1
|
62
|
+
# of this permutation that is ranked with Permutation#rank.
|
63
|
+
#
|
64
|
+
# <b>Example:</b>
|
65
|
+
# perm = Permutation.new(6, 312)
|
66
|
+
# # => #<Permutation:0x6ae34 @last=719, @rank=312, @size=6>
|
67
|
+
# perm.value
|
68
|
+
# # => [2, 4, 0, 1, 3, 5]
|
69
|
+
def value
|
70
|
+
unrank_indices(@rank)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the projection of this instance's Permutation#value
|
74
|
+
# into the <code>data</code> object that should respond to
|
75
|
+
# the #[] method. If this Permutation inbstance was created
|
76
|
+
# with Permutation.for the collection used to create
|
77
|
+
# it is used as a data object.
|
78
|
+
#
|
79
|
+
# <b>Example:</b>
|
80
|
+
# perm = Permutation.new(6, 312)
|
81
|
+
# # => #<Permutation:0x6ae34 @last=719, @rank=312, @size=6>
|
82
|
+
# perm.project("abcdef")
|
83
|
+
# # => "ceabdf"
|
84
|
+
def project(data = @collection)
|
85
|
+
data or raise ArgumentError, "a collection is required to project"
|
86
|
+
raise ArgumentError, "data size is != #{size}!" if data.size != size
|
87
|
+
projection = data.clone
|
88
|
+
value.each_with_index { |i, j| projection[j] = data[i] }
|
89
|
+
projection
|
90
|
+
end
|
91
|
+
|
92
|
+
# Compares to Permutation instances according to their Permutation#size
|
93
|
+
# and the Permutation#rank.
|
94
|
+
#
|
95
|
+
# The mixed in methods from the Comparable module rely on this method.
|
96
|
+
def <=>(other)
|
97
|
+
size <=> other.size.zero? || rank <=> other.rank
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns true if this Permutation instance and the other have the same
|
101
|
+
# value, that is both Permutation instances have the same Permutation#size
|
102
|
+
# and the same Permutation#rank.
|
103
|
+
def eql?(other)
|
104
|
+
self.class == other.class && size == other.size && rank == other.rank
|
105
|
+
end
|
106
|
+
|
107
|
+
alias == eql?
|
108
|
+
|
109
|
+
# Computes a unique hash value for this Permutation instance.
|
110
|
+
def hash
|
111
|
+
size.hash ^ rank.hash
|
112
|
+
end
|
113
|
+
|
114
|
+
# Switchtes this Permutation instance to the inverted permutation.
|
115
|
+
# (See Permutation#compose for an example.)
|
116
|
+
def invert!
|
117
|
+
indices = unrank_indices(rank)
|
118
|
+
inverted = Array.new(size)
|
119
|
+
for i in 0...size
|
120
|
+
inverted[indices[i]] = i
|
121
|
+
end
|
122
|
+
self.rank = rank_indices(inverted)
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns the inverted Permutation of this Permutation instance.
|
127
|
+
# (See Permutation#compose for an example.)
|
128
|
+
def invert
|
129
|
+
clone.invert!
|
130
|
+
end
|
131
|
+
|
132
|
+
alias -@ invert
|
133
|
+
|
134
|
+
# Compose this Permutation instance and the other to
|
135
|
+
# a new Permutation. Note that a permutation
|
136
|
+
# composed with it's inverted permutation yields
|
137
|
+
# the identity permutation, the permutation with rank 0.
|
138
|
+
#
|
139
|
+
# <b>Example:</b>
|
140
|
+
# p1 = Permutation.new(5, 42)
|
141
|
+
# # => #<Permutation:0x75370 @last=119, @rank=42, @size=5>
|
142
|
+
# p2 = p1.invert
|
143
|
+
# # => #<Permutation:0x653d0 @last=119, @rank=51, @size=5>
|
144
|
+
# p1.compose(p2)
|
145
|
+
# => #<Permutation:0x639a4 @last=119, @rank=0, @size=5>
|
146
|
+
# Or a little nicer to look at:
|
147
|
+
# p1 * -p1
|
148
|
+
# # => #<Permutation:0x62004 @last=119, @rank=0, @size=5>
|
149
|
+
def compose(other)
|
150
|
+
size == other.size or raise ArgumentError,
|
151
|
+
"permutations of unequal sizes cannot be composed!"
|
152
|
+
indices = self.value
|
153
|
+
composed = other.value.map { |i| indices[i] }
|
154
|
+
klon = clone
|
155
|
+
klon.rank = rank_indices(composed)
|
156
|
+
klon
|
157
|
+
end
|
158
|
+
|
159
|
+
alias * compose
|
160
|
+
|
161
|
+
# Returns the cycles representation of this Permutation instance.
|
162
|
+
# The return value of this method can be used to create a
|
163
|
+
# new Permutation instance with the Permutation.from_cycles method.
|
164
|
+
#
|
165
|
+
# <b>Example:</b>
|
166
|
+
# perm = Permutation.new(7, 23)
|
167
|
+
# # => #<Permutation:0x58541c @last=5039, @rank=23, @size=7>
|
168
|
+
# perm.cycles
|
169
|
+
# # => [[3, 6], [4, 5]]
|
170
|
+
def cycles
|
171
|
+
perm = value
|
172
|
+
result = [[]]
|
173
|
+
seen = {}
|
174
|
+
current = nil
|
175
|
+
loop do
|
176
|
+
current or current = perm.find { |x| !seen[x] }
|
177
|
+
break unless current
|
178
|
+
if seen[current]
|
179
|
+
current = nil
|
180
|
+
result << []
|
181
|
+
else
|
182
|
+
seen[current] = true
|
183
|
+
result[-1] << current
|
184
|
+
current = perm[current]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
result.pop
|
188
|
+
result.select { |c| c.size > 1 }.map do |c|
|
189
|
+
min_index = c.index(c.min)
|
190
|
+
c[min_index..-1] + c[0...min_index]
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Returns the signum of this Permutation instance.
|
195
|
+
# It's -1 if this permutation is odd and 1 if it's
|
196
|
+
# an even permutation.
|
197
|
+
#
|
198
|
+
# A permutation is odd if it can be represented by an odd number of
|
199
|
+
# transpositions (cycles of length 2), or even if it can be represented of
|
200
|
+
# an even number of transpositions.
|
201
|
+
def signum
|
202
|
+
s = 1
|
203
|
+
cycles.each do |c|
|
204
|
+
c.size % 2 == 0 and s *= -1
|
205
|
+
end
|
206
|
+
s
|
207
|
+
end
|
208
|
+
|
209
|
+
alias sgn signum
|
210
|
+
|
211
|
+
# Returns true if this permutation is even, false otherwise.
|
212
|
+
def even?
|
213
|
+
signum == 1
|
214
|
+
end
|
215
|
+
|
216
|
+
# Returns true if this permutation is odd, false otherwise.
|
217
|
+
def odd?
|
218
|
+
signum == -1
|
219
|
+
end
|
220
|
+
|
221
|
+
private
|
222
|
+
|
223
|
+
@@fcache = [ 1 ]
|
224
|
+
|
225
|
+
def factorial(n)
|
226
|
+
@@fcache.size.upto(n) { |i| @@fcache[i] = i * @@fcache[i - 1] }
|
227
|
+
@@fcache[n]
|
228
|
+
end
|
229
|
+
|
230
|
+
def rank_indices(p)
|
231
|
+
result = 0
|
232
|
+
for i in 0...size
|
233
|
+
result += p[i] * factorial(size - i - 1)
|
234
|
+
for j in (i + 1)...size
|
235
|
+
p[j] -= 1 if p[j] > p[i]
|
236
|
+
end
|
237
|
+
end
|
238
|
+
result
|
239
|
+
end
|
240
|
+
|
241
|
+
def unrank_indices(m)
|
242
|
+
result = Array.new(size, 0)
|
243
|
+
for i in 0...size
|
244
|
+
f = factorial(i)
|
245
|
+
x = m % (f * (i + 1))
|
246
|
+
m -= x
|
247
|
+
x /= f
|
248
|
+
result[size - i - 1] = x
|
249
|
+
x -= 1
|
250
|
+
for j in (size - i)...size
|
251
|
+
result[j] += 1 if result[j] > x
|
252
|
+
end
|
253
|
+
end
|
254
|
+
result
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module MoreMath
|
2
|
+
module RankingCommon
|
3
|
+
# Returns the size of this instance's collection, a Fixnum.
|
4
|
+
attr_reader :size
|
5
|
+
|
6
|
+
# Returns the rank of this instance, a Fixnum in the range
|
7
|
+
# of 0 and #last.
|
8
|
+
attr_reader :rank
|
9
|
+
|
10
|
+
# Returns the rank of the last ranked instance.
|
11
|
+
attr_reader :last
|
12
|
+
|
13
|
+
# Returns the collection the #rank applies to if any was set, otherwise
|
14
|
+
# retrurns nil.
|
15
|
+
attr_reader :collection
|
16
|
+
|
17
|
+
# Switches this instance to the next ranked instance. If this was the #last
|
18
|
+
# instance it wraps around the first (<code>rank == 0</code>) instance.
|
19
|
+
def next!
|
20
|
+
self.rank += 1
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
alias succ! next!
|
25
|
+
|
26
|
+
# Returns the next ranked instance. If this instance is the #last instance
|
27
|
+
# it returns the first (<code>rank == 0</code>) instance again.
|
28
|
+
def next
|
29
|
+
clone.next!
|
30
|
+
end
|
31
|
+
|
32
|
+
alias succ next
|
33
|
+
|
34
|
+
# Switches this instance to the previously ranked instance. If this was the
|
35
|
+
# first instance it returns the last (<code>rank == #last</code>) instance.
|
36
|
+
def pred!
|
37
|
+
self.rank -= 1
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the previously ranked instance. If this was the first instance it
|
42
|
+
# returns the last (<code>rank == #last</code>) instance.
|
43
|
+
def pred
|
44
|
+
clone.pred!
|
45
|
+
end
|
46
|
+
|
47
|
+
# Switches this instance to a randomly ranked instance.
|
48
|
+
def random!
|
49
|
+
new_rank = rand(last + 1).to_i
|
50
|
+
self.rank = new_rank
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns a randomly ranked instance.
|
55
|
+
def random
|
56
|
+
clone.random!
|
57
|
+
end
|
58
|
+
|
59
|
+
# Iterates over all instances starting with the
|
60
|
+
# first (<code>rank == 0</code>) ranked instance and ending with the
|
61
|
+
# last (<code>rank == #last</code>) ranked instance while
|
62
|
+
# yielding to a freshly created instance for every iteration
|
63
|
+
# step.
|
64
|
+
#
|
65
|
+
# The mixed in methods from the Enumerable module rely on this method.
|
66
|
+
def each # :yields: perm
|
67
|
+
0.upto(last) do |r|
|
68
|
+
klon = clone
|
69
|
+
klon.rank = r
|
70
|
+
yield klon
|
71
|
+
end
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
# Does something similar to #each. It doesn't create new
|
76
|
+
# instances (less overhead) for every iteration step, but yields to a
|
77
|
+
# modified self instead. This is useful if one only wants to call a
|
78
|
+
# method on the yielded value and work with the result of this call. It's
|
79
|
+
# not a good idea to put the yielded values in a data structure because all
|
80
|
+
# of them will reference the same (this!) instance. If you want to do this
|
81
|
+
# use #each.
|
82
|
+
def each!
|
83
|
+
old_rank = rank
|
84
|
+
0.upto(last) do |r|
|
85
|
+
self.rank = r
|
86
|
+
yield self
|
87
|
+
end
|
88
|
+
self
|
89
|
+
ensure
|
90
|
+
self.rank = old_rank
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'more_math/ranking_common'
|
2
|
+
|
3
|
+
module MoreMath
|
4
|
+
class Subset
|
5
|
+
include Enumerable
|
6
|
+
include RankingCommon
|
7
|
+
|
8
|
+
# Returns a Subset instance for a collection of size +size+ with the rank
|
9
|
+
# +rank+.
|
10
|
+
def initialize(size, rank = 0)
|
11
|
+
@size, self.rank = size, rank
|
12
|
+
@last = (1 << size) - 1
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the subset of the collection +collection+ for the rank +rank+.
|
16
|
+
def self.for(collection, rank = 0)
|
17
|
+
subset = new(collection.size, rank)
|
18
|
+
subset.instance_variable_set(:@collection, collection)
|
19
|
+
subset
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the power set of the collection +collection+.
|
23
|
+
def self.power_set(collection)
|
24
|
+
self.for(collection).map(&:value)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Assigns <code>m</code> to the rank attribute of this object.
|
28
|
+
def rank=(m)
|
29
|
+
@rank = m % (1 << size)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the subset for rank #rank and #collection. (If no collection was
|
33
|
+
# set it applies to the array [ 0, 1, ..., size - 1 ] instead.)
|
34
|
+
def value
|
35
|
+
result = []
|
36
|
+
c = @collection || (0...size).to_a
|
37
|
+
r = @rank
|
38
|
+
0.upto(size) do |i|
|
39
|
+
r[i] == 1 and result << c[i]
|
40
|
+
end
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
# TODO project
|
45
|
+
end
|
46
|
+
end
|
data/lib/more_math/version.rb
CHANGED
data/more_math.gemspec
CHANGED
@@ -2,34 +2,34 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "more_math"
|
5
|
-
s.version = "0.0.
|
5
|
+
s.version = "0.0.3"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Florian Frank"]
|
9
|
-
s.date = "2011-
|
9
|
+
s.date = "2011-10-27"
|
10
10
|
s.description = "Library that provides more mathematical functions/algorithms than standard Ruby."
|
11
11
|
s.email = "flori@ping.de"
|
12
|
-
s.extra_rdoc_files = ["README.rdoc", "lib/more_math/cantor_pairing_function.rb", "lib/more_math/version.rb", "lib/more_math/functions.rb", "lib/more_math/sequence.rb", "lib/more_math/linear_regression.rb", "lib/more_math/string_numeral.rb", "lib/more_math/histogram.rb", "lib/more_math/constants/functions_constants.rb", "lib/more_math/numberify_string_function.rb", "lib/more_math/distributions.rb", "lib/more_math/exceptions.rb", "lib/more_math/newton_bisection.rb", "lib/more_math/continued_fraction.rb", "lib/more_math.rb"]
|
13
|
-
s.files = [".gitignore", ".travis.yml", "CHANGES", "Gemfile", "LICENSE", "README.rdoc", "Rakefile", "VERSION", "lib/more_math.rb", "lib/more_math/cantor_pairing_function.rb", "lib/more_math/constants/functions_constants.rb", "lib/more_math/continued_fraction.rb", "lib/more_math/distributions.rb", "lib/more_math/exceptions.rb", "lib/more_math/functions.rb", "lib/more_math/histogram.rb", "lib/more_math/linear_regression.rb", "lib/more_math/newton_bisection.rb", "lib/more_math/numberify_string_function.rb", "lib/more_math/
|
12
|
+
s.extra_rdoc_files = ["README.rdoc", "lib/more_math/cantor_pairing_function.rb", "lib/more_math/version.rb", "lib/more_math/functions.rb", "lib/more_math/sequence.rb", "lib/more_math/linear_regression.rb", "lib/more_math/string_numeral.rb", "lib/more_math/ranking_common.rb", "lib/more_math/subset.rb", "lib/more_math/histogram.rb", "lib/more_math/constants/functions_constants.rb", "lib/more_math/numberify_string_function.rb", "lib/more_math/distributions.rb", "lib/more_math/exceptions.rb", "lib/more_math/newton_bisection.rb", "lib/more_math/permutation.rb", "lib/more_math/continued_fraction.rb", "lib/more_math.rb"]
|
13
|
+
s.files = [".gitignore", ".travis.yml", "CHANGES", "Gemfile", "LICENSE", "README.rdoc", "Rakefile", "VERSION", "lib/more_math.rb", "lib/more_math/cantor_pairing_function.rb", "lib/more_math/constants/functions_constants.rb", "lib/more_math/continued_fraction.rb", "lib/more_math/distributions.rb", "lib/more_math/exceptions.rb", "lib/more_math/functions.rb", "lib/more_math/histogram.rb", "lib/more_math/linear_regression.rb", "lib/more_math/newton_bisection.rb", "lib/more_math/numberify_string_function.rb", "lib/more_math/permutation.rb", "lib/more_math/ranking_common.rb", "lib/more_math/sequence.rb", "lib/more_math/string_numeral.rb", "lib/more_math/subset.rb", "lib/more_math/version.rb", "more_math.gemspec", "tests/test_cantor_pairing_function.rb", "tests/test_continued_fraction.rb", "tests/test_distribution.rb", "tests/test_functions.rb", "tests/test_histogram.rb", "tests/test_newton_bisection.rb", "tests/test_numberify_string_function.rb", "tests/test_permutation.rb", "tests/test_sequence.rb", "tests/test_subset.rb"]
|
14
14
|
s.homepage = "http://flori.github.com/more_math"
|
15
15
|
s.rdoc_options = ["--title", "MoreMath -- More Math in Ruby", "--main", "README.rdoc"]
|
16
16
|
s.require_paths = ["lib"]
|
17
17
|
s.rubygems_version = "1.8.10"
|
18
18
|
s.summary = "Library that provides more mathematics."
|
19
|
-
s.test_files = ["tests/test_cantor_pairing_function.rb", "tests/test_continued_fraction.rb", "tests/test_newton_bisection.rb", "tests/
|
19
|
+
s.test_files = ["tests/test_subset.rb", "tests/test_permutation.rb", "tests/test_cantor_pairing_function.rb", "tests/test_continued_fraction.rb", "tests/test_newton_bisection.rb", "tests/test_functions.rb", "tests/test_distribution.rb", "tests/test_sequence.rb", "tests/test_histogram.rb", "tests/test_numberify_string_function.rb"]
|
20
20
|
|
21
21
|
if s.respond_to? :specification_version then
|
22
22
|
s.specification_version = 3
|
23
23
|
|
24
24
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
25
|
-
s.add_development_dependency(%q<gem_hadar>, ["~> 0.1.
|
25
|
+
s.add_development_dependency(%q<gem_hadar>, ["~> 0.1.1"])
|
26
26
|
s.add_runtime_dependency(%q<tins>, ["~> 0.3"])
|
27
27
|
else
|
28
|
-
s.add_dependency(%q<gem_hadar>, ["~> 0.1.
|
28
|
+
s.add_dependency(%q<gem_hadar>, ["~> 0.1.1"])
|
29
29
|
s.add_dependency(%q<tins>, ["~> 0.3"])
|
30
30
|
end
|
31
31
|
else
|
32
|
-
s.add_dependency(%q<gem_hadar>, ["~> 0.1.
|
32
|
+
s.add_dependency(%q<gem_hadar>, ["~> 0.1.1"])
|
33
33
|
s.add_dependency(%q<tins>, ["~> 0.3"])
|
34
34
|
end
|
35
35
|
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'more_math'
|
5
|
+
|
6
|
+
class TestPermutation < Test::Unit::TestCase
|
7
|
+
include MoreMath
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@perms = (0..4).map { |i| Permutation.new(i) }
|
11
|
+
@perms_collections = [ "", "a", "ab", "abc", "abcd" ].map do |c|
|
12
|
+
Permutation.for(c)
|
13
|
+
end
|
14
|
+
@perms_each = [
|
15
|
+
[[]],
|
16
|
+
[[0]],
|
17
|
+
[[0, 1], [1, 0]],
|
18
|
+
[[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]],
|
19
|
+
[[0, 1, 2, 3], [0, 1, 3, 2], [0, 2, 1, 3], [0, 2, 3, 1],
|
20
|
+
[0, 3, 1, 2], [0, 3, 2, 1], [1, 0, 2, 3], [1, 0, 3, 2],
|
21
|
+
[1, 2, 0, 3], [1, 2, 3, 0], [1, 3, 0, 2], [1, 3, 2, 0],
|
22
|
+
[2, 0, 1, 3], [2, 0, 3, 1], [2, 1, 0, 3], [2, 1, 3, 0],
|
23
|
+
[2, 3, 0, 1], [2, 3, 1, 0], [3, 0, 1, 2], [3, 0, 2, 1],
|
24
|
+
[3, 1, 0, 2], [3, 1, 2, 0], [3, 2, 0, 1], [3, 2, 1, 0]]
|
25
|
+
]
|
26
|
+
@next_pred = [
|
27
|
+
[ [], [] ],
|
28
|
+
[ [ 0 ], [ 0 ] ],
|
29
|
+
[ [ 0, 1 ], [ 1, 0 ] ],
|
30
|
+
[ [ 1, 0 ], [ 0, 1 ] ],
|
31
|
+
[ [ 0, 1, 2 ], [ 0, 2, 1 ] ],
|
32
|
+
[ [ 0, 2, 1 ], [ 1, 0, 2 ] ],
|
33
|
+
[ [ 1, 0, 2 ], [ 1, 2, 0 ] ],
|
34
|
+
[ [ 1, 2, 0 ], [ 2, 0, 1 ] ],
|
35
|
+
[ [ 2, 0, 1 ], [ 2, 1, 0 ] ],
|
36
|
+
[ [ 2, 1, 0 ], [ 0, 1, 2 ] ],
|
37
|
+
]
|
38
|
+
@projected = [
|
39
|
+
[ "" ],
|
40
|
+
[ "a" ],
|
41
|
+
[ "ab", "ba", ],
|
42
|
+
[ "abc", "acb", "bac", "bca", "cab", "cba" ],
|
43
|
+
[ "abcd", "abdc", "acbd", "acdb", "adbc", "adcb", "bacd",
|
44
|
+
"badc", "bcad", "bcda", "bdac", "bdca", "cabd", "cadb",
|
45
|
+
"cbad", "cbda", "cdab", "cdba", "dabc", "dacb", "dbac",
|
46
|
+
"dbca", "dcab", "dcba"]
|
47
|
+
]
|
48
|
+
@products = [
|
49
|
+
{[0, 0]=>[]},
|
50
|
+
{[0, 0]=>[0]},
|
51
|
+
{[0, 0]=>[0, 1], [1, 1]=>[0, 1], [1, 0]=>[1, 0], [0, 1]=>[1, 0]},
|
52
|
+
{[2, 4]=>[2, 1, 0], [1, 2]=>[2, 0, 1], [0, 0]=>[0, 1, 2],
|
53
|
+
[5, 4]=>[0, 2, 1], [3, 3]=>[2, 0, 1], [2, 1]=>[1, 2, 0],
|
54
|
+
[0, 5]=>[2, 1, 0], [3, 5]=>[0, 2, 1], [1, 1]=>[0, 1, 2],
|
55
|
+
[0, 3]=>[1, 2, 0], [5, 3]=>[1, 0, 2], [4, 1]=>[2, 1, 0],
|
56
|
+
[3, 2]=>[2, 1, 0], [2, 0]=>[1, 0, 2], [0, 4]=>[2, 0, 1],
|
57
|
+
[3, 4]=>[0, 1, 2], [1, 0]=>[0, 2, 1], [0, 2]=>[1, 0, 2],
|
58
|
+
[5, 2]=>[1, 2, 0], [4, 0]=>[2, 0, 1], [3, 1]=>[1, 0, 2],
|
59
|
+
[2, 3]=>[0, 2, 1], [1, 5]=>[1, 2, 0], [4, 5]=>[1, 0, 2],
|
60
|
+
[5, 1]=>[2, 0, 1], [4, 3]=>[0, 1, 2], [3, 0]=>[1, 2, 0],
|
61
|
+
[2, 2]=>[0, 1, 2], [1, 4]=>[1, 0, 2], [4, 4]=>[1, 2, 0],
|
62
|
+
[5, 0]=>[2, 1, 0], [4, 2]=>[0, 2, 1], [2, 5]=>[2, 0, 1],
|
63
|
+
[1, 3]=>[2, 1, 0], [0, 1]=>[0, 2, 1], [5, 5]=>[0, 1, 2]}
|
64
|
+
]
|
65
|
+
@cycles = [
|
66
|
+
[[]],
|
67
|
+
[[]],
|
68
|
+
[[], [[0, 1]]],
|
69
|
+
[[], [[1, 2]], [[0, 1]], [[0, 1, 2]], [[0, 2, 1]], [[0, 2]]],
|
70
|
+
[[], [[2, 3]], [[1, 2]], [[1, 2, 3]], [[1, 3, 2]], [[1, 3]],
|
71
|
+
[[0, 1]], [[0, 1], [2, 3]], [[0, 1, 2]], [[0, 1, 2, 3]],
|
72
|
+
[[0, 1, 3, 2]], [[0, 1, 3]], [[0, 2, 1]], [[0, 2, 3, 1]],
|
73
|
+
[[0, 2]], [[0, 2, 3]], [[0, 2], [1, 3]], [[0, 2, 1, 3]],
|
74
|
+
[[0, 3, 2, 1]], [[0, 3, 1]], [[0, 3, 2]], [[0, 3]],
|
75
|
+
[[0, 3, 1, 2]], [[0, 3], [1, 2]]]
|
76
|
+
]
|
77
|
+
@signum = [
|
78
|
+
[1],
|
79
|
+
[1],
|
80
|
+
[1, -1],
|
81
|
+
[1, -1, -1, 1, 1, -1],
|
82
|
+
[1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1,
|
83
|
+
-1, 1, 1, -1, -1, 1]
|
84
|
+
]
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_created
|
88
|
+
factorial = 1
|
89
|
+
@perms.each_with_index do |p, i|
|
90
|
+
assert_equal(i, p.size)
|
91
|
+
assert_equal(factorial - 1, p.last)
|
92
|
+
factorial *= (i + 1)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_rank_assign
|
97
|
+
perm = Permutation.new(3)
|
98
|
+
perms = [
|
99
|
+
[0, 1, 2],
|
100
|
+
[0, 2, 1],
|
101
|
+
[1, 0, 2],
|
102
|
+
[1, 2, 0],
|
103
|
+
[2, 0, 1],
|
104
|
+
[2, 1, 0],
|
105
|
+
[0, 1, 2],
|
106
|
+
]
|
107
|
+
(-12...-6).each do |i|
|
108
|
+
perm.rank = i
|
109
|
+
assert_equal(perms[i + 12], perm.value)
|
110
|
+
end
|
111
|
+
(-6...0).each do |i|
|
112
|
+
perm.rank = i
|
113
|
+
assert_equal(perms[i + 6], perm.value)
|
114
|
+
end
|
115
|
+
(0..6).each do |i|
|
116
|
+
perm.rank = i
|
117
|
+
assert_equal(perms[i], perm.value)
|
118
|
+
end
|
119
|
+
(6..12).each do |i|
|
120
|
+
perm.rank = i
|
121
|
+
assert_equal(perms[i - 6], perm.value)
|
122
|
+
end
|
123
|
+
(12..17).each do |i|
|
124
|
+
perm.rank = i
|
125
|
+
assert_equal(perms[i - 12], perm.value)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_compare
|
130
|
+
perm1 = Permutation.new(3)
|
131
|
+
perm2 = Permutation.new(3)
|
132
|
+
perm3 = perm1.dup
|
133
|
+
perm4 = Permutation.new(3, 1)
|
134
|
+
assert(!perm1.equal?(perm2))
|
135
|
+
assert(perm1 == perm2)
|
136
|
+
assert(perm1.eql?(perm2))
|
137
|
+
assert_equal(0, perm1 <=> perm2)
|
138
|
+
assert_equal(perm1.hash, perm2.hash)
|
139
|
+
assert(!perm1.equal?(perm3))
|
140
|
+
assert(perm1 == perm3)
|
141
|
+
assert(perm1.eql?(perm3))
|
142
|
+
assert_equal(0, perm1 <=> perm3)
|
143
|
+
assert_equal(perm1.hash, perm3.hash)
|
144
|
+
assert(!perm1.equal?(perm4))
|
145
|
+
assert(perm1 != perm4)
|
146
|
+
assert(!perm1.eql?(perm4))
|
147
|
+
assert_equal(-1, perm1 <=> perm4)
|
148
|
+
assert_equal(1, perm4 <=> perm1)
|
149
|
+
assert(perm1 < perm4)
|
150
|
+
assert(perm4 > perm1)
|
151
|
+
assert(perm1.hash != perm4.hash)
|
152
|
+
perms = perm1.to_a
|
153
|
+
perms[1..-1].each_with_index do |p, i|
|
154
|
+
assert(p > perms[i])
|
155
|
+
assert_equal(1, p <=> perms[i])
|
156
|
+
assert(perms[i] < p)
|
157
|
+
assert_equal(-1, perms[i] <=> p)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_random
|
162
|
+
@perms_each.each_with_index do |perms, i|
|
163
|
+
perm = Permutation.new(i)
|
164
|
+
until perms.empty?
|
165
|
+
deleted = perms.delete perm.random.value
|
166
|
+
deleted and assert true
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_enumerable
|
172
|
+
@perms.each_with_index do |perm, i|
|
173
|
+
assert_equal(@perms_each[i], perm.map { |x| x.value })
|
174
|
+
end
|
175
|
+
@perms.each_with_index do |perm, i|
|
176
|
+
ary = []
|
177
|
+
old_rank = perm.rank
|
178
|
+
perm.each! { |x| ary << x.value }
|
179
|
+
assert_equal(@perms_each[i], ary)
|
180
|
+
assert_equal(old_rank, perm.rank)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_next
|
185
|
+
@next_pred.each do |before, after|
|
186
|
+
beforep = Permutation.from_value(before)
|
187
|
+
afterp = Permutation.from_value(after)
|
188
|
+
assert_equal(afterp, beforep.next)
|
189
|
+
assert_equal(beforep, afterp.pred)
|
190
|
+
assert_equal(afterp, beforep.succ)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def test_project
|
195
|
+
too_big = Array.new(10)
|
196
|
+
@perms.each_with_index do |perms, i|
|
197
|
+
assert_equal(@projected[i],
|
198
|
+
perms.map { |p| p.project(@projected[i][0]) })
|
199
|
+
assert_raises(ArgumentError) { perms.project }
|
200
|
+
assert_raises(ArgumentError) { perms.project(too_big) }
|
201
|
+
end
|
202
|
+
@perms_collections.each_with_index do |perms, i|
|
203
|
+
assert_equal(@projected[i], perms.map { |p| p.project })
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_compose
|
208
|
+
too_big = Permutation.new(10)
|
209
|
+
@perms[0..3].each do |perm|
|
210
|
+
elements = perm.to_a
|
211
|
+
for i in 0...elements.size
|
212
|
+
for j in 0...elements.size
|
213
|
+
assert_equal(@products[perm.size][[i, j]],
|
214
|
+
(elements[i].compose(elements[j])).value)
|
215
|
+
assert_equal(@products[perm.size][[i, j]],
|
216
|
+
(elements[i] * elements[j]).value)
|
217
|
+
end
|
218
|
+
assert_raises(ArgumentError) { elements[i] * too_big }
|
219
|
+
assert_raises(ArgumentError) { elements[i].compose(too_big) }
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_invert
|
225
|
+
@perms.each do |perm|
|
226
|
+
id = perm
|
227
|
+
perm.each do |p|
|
228
|
+
assert_equal(id.value, (p * p.invert).value)
|
229
|
+
assert_equal(id, p * p.invert)
|
230
|
+
assert_equal(id.value, (p * -p).value)
|
231
|
+
assert_equal(id, p * -p)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_cycles
|
237
|
+
@perms.each_with_index do |perm, i|
|
238
|
+
assert_equal(@cycles[i], perm.map { |p| p.cycles })
|
239
|
+
assert_equal(perm.to_a,
|
240
|
+
@cycles[i].map { |c| Permutation.from_cycles(c, i) })
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_signum
|
245
|
+
@perms.each_with_index do |perm, i|
|
246
|
+
assert_equal(@signum[i], perm.map { |p| p.signum })
|
247
|
+
assert_equal(@signum[i], perm.map { |p| p.sgn })
|
248
|
+
assert_equal(@signum[i].map { |x| x == 1 },
|
249
|
+
perm.map { |p| p.even? })
|
250
|
+
assert_equal(@signum[i].map { |x| x == -1 },
|
251
|
+
perm.map { |p| p.odd? })
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
File without changes
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'more_math'
|
5
|
+
|
6
|
+
class TestSubset < Test::Unit::TestCase
|
7
|
+
include MoreMath
|
8
|
+
|
9
|
+
def test_empty_set
|
10
|
+
assert_equal [[]], Subset.for([]).map(&:value)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_one_element_set
|
14
|
+
assert_equal [[], [1]], Subset.for([1]).map(&:value)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_three_element_set
|
18
|
+
assert_equal [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]],
|
19
|
+
Subset.for([1, 2, 3]).map(&:value)
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: more_math
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-10-27 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gem_hadar
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156570840 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.1.
|
21
|
+
version: 0.1.1
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156570840
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: tins
|
27
|
-
requirement: &
|
27
|
+
requirement: &2156570220 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0.3'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2156570220
|
36
36
|
description: Library that provides more mathematical functions/algorithms than standard
|
37
37
|
Ruby.
|
38
38
|
email: flori@ping.de
|
@@ -46,12 +46,15 @@ extra_rdoc_files:
|
|
46
46
|
- lib/more_math/sequence.rb
|
47
47
|
- lib/more_math/linear_regression.rb
|
48
48
|
- lib/more_math/string_numeral.rb
|
49
|
+
- lib/more_math/ranking_common.rb
|
50
|
+
- lib/more_math/subset.rb
|
49
51
|
- lib/more_math/histogram.rb
|
50
52
|
- lib/more_math/constants/functions_constants.rb
|
51
53
|
- lib/more_math/numberify_string_function.rb
|
52
54
|
- lib/more_math/distributions.rb
|
53
55
|
- lib/more_math/exceptions.rb
|
54
56
|
- lib/more_math/newton_bisection.rb
|
57
|
+
- lib/more_math/permutation.rb
|
55
58
|
- lib/more_math/continued_fraction.rb
|
56
59
|
- lib/more_math.rb
|
57
60
|
files:
|
@@ -74,11 +77,13 @@ files:
|
|
74
77
|
- lib/more_math/linear_regression.rb
|
75
78
|
- lib/more_math/newton_bisection.rb
|
76
79
|
- lib/more_math/numberify_string_function.rb
|
80
|
+
- lib/more_math/permutation.rb
|
81
|
+
- lib/more_math/ranking_common.rb
|
77
82
|
- lib/more_math/sequence.rb
|
78
83
|
- lib/more_math/string_numeral.rb
|
84
|
+
- lib/more_math/subset.rb
|
79
85
|
- lib/more_math/version.rb
|
80
86
|
- more_math.gemspec
|
81
|
-
- tests/test_analysis.rb
|
82
87
|
- tests/test_cantor_pairing_function.rb
|
83
88
|
- tests/test_continued_fraction.rb
|
84
89
|
- tests/test_distribution.rb
|
@@ -86,6 +91,9 @@ files:
|
|
86
91
|
- tests/test_histogram.rb
|
87
92
|
- tests/test_newton_bisection.rb
|
88
93
|
- tests/test_numberify_string_function.rb
|
94
|
+
- tests/test_permutation.rb
|
95
|
+
- tests/test_sequence.rb
|
96
|
+
- tests/test_subset.rb
|
89
97
|
homepage: http://flori.github.com/more_math
|
90
98
|
licenses: []
|
91
99
|
post_install_message:
|
@@ -115,11 +123,13 @@ signing_key:
|
|
115
123
|
specification_version: 3
|
116
124
|
summary: Library that provides more mathematics.
|
117
125
|
test_files:
|
126
|
+
- tests/test_subset.rb
|
127
|
+
- tests/test_permutation.rb
|
118
128
|
- tests/test_cantor_pairing_function.rb
|
119
129
|
- tests/test_continued_fraction.rb
|
120
130
|
- tests/test_newton_bisection.rb
|
121
|
-
- tests/test_analysis.rb
|
122
131
|
- tests/test_functions.rb
|
123
132
|
- tests/test_distribution.rb
|
133
|
+
- tests/test_sequence.rb
|
124
134
|
- tests/test_histogram.rb
|
125
135
|
- tests/test_numberify_string_function.rb
|