more_math 0.0.2 → 0.0.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/.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
|