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 CHANGED
@@ -1,3 +1,5 @@
1
1
  .*.sw[pon]
2
+ .rvmrc
2
3
  Gemfile.lock
4
+ coverage
3
5
  pkg
data/CHANGES CHANGED
@@ -1,2 +1,8 @@
1
+ 2011-10-08 (0.0.3)
2
+ * Add permutation and subset implementations
3
+ 2011-09-26 (0.0.2)
4
+ * Depend on tins library
5
+ 2011-07-17 (0.0.1)
6
+ * Use gem_hadar
1
7
  2010-11-01 (0.0.0)
2
8
  * Initial Version
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.2
1
+ 0.0.3
@@ -15,5 +15,7 @@ module MoreMath
15
15
  require 'more_math/numberify_string_function'
16
16
  require 'more_math/sequence'
17
17
  require 'more_math/string_numeral'
18
+ require 'more_math/permutation'
19
+ require 'more_math/subset'
18
20
  require 'more_math/version'
19
21
  end
@@ -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)
@@ -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
@@ -1,6 +1,6 @@
1
1
  module MoreMath
2
2
  # MoreMath version
3
- VERSION = '0.0.2'
3
+ VERSION = '0.0.3'
4
4
  VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
@@ -2,34 +2,34 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "more_math"
5
- s.version = "0.0.2"
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-09-25"
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/sequence.rb", "lib/more_math/string_numeral.rb", "lib/more_math/version.rb", "more_math.gemspec", "tests/test_analysis.rb", "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"]
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/test_analysis.rb", "tests/test_functions.rb", "tests/test_distribution.rb", "tests/test_histogram.rb", "tests/test_numberify_string_function.rb"]
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.0"])
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.0"])
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.0"])
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
@@ -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.2
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-09-25 00:00:00.000000000Z
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: &2160789860 !ruby/object:Gem::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.0
21
+ version: 0.1.1
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *2160789860
24
+ version_requirements: *2156570840
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: tins
27
- requirement: &2160789420 !ruby/object:Gem::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: *2160789420
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