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 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