permutation 0.1.5 → 0.1.6
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/CHANGES +6 -0
- data/GPL +0 -0
- data/README.en +0 -0
- data/Rakefile +7 -0
- data/VERSION +1 -1
- data/install.rb +0 -0
- data/lib/permutation.rb +315 -317
- data/lib/permutation/version.rb +1 -1
- data/test/test.rb +0 -0
- metadata +51 -44
data/CHANGES
CHANGED
data/GPL
CHANGED
File without changes
|
data/README.en
CHANGED
File without changes
|
data/Rakefile
CHANGED
@@ -23,6 +23,11 @@ task :test do
|
|
23
23
|
ruby %{-Ilib test/test.rb}
|
24
24
|
end
|
25
25
|
|
26
|
+
desc "Testing library (with coverage)"
|
27
|
+
task :coverage do
|
28
|
+
sh %{rcov -Ilib test/test.rb}
|
29
|
+
end
|
30
|
+
|
26
31
|
spec = Gem::Specification.new do |s|
|
27
32
|
s.name = 'permutation'
|
28
33
|
s.version = PKG_VERSION
|
@@ -66,5 +71,7 @@ EOT
|
|
66
71
|
end
|
67
72
|
end
|
68
73
|
|
74
|
+
CLEAN.include 'doc'
|
75
|
+
|
69
76
|
task :release => [ :clean, :version, :package ]
|
70
77
|
# vim: set et sw=2 ts=2:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.6
|
data/install.rb
CHANGED
File without changes
|
data/lib/permutation.rb
CHANGED
@@ -47,7 +47,7 @@
|
|
47
47
|
# # => [:r, :g, :b]
|
48
48
|
# perm.map { |p| p.project(colors) }
|
49
49
|
# # => [[:r, :g, :b], [:r, :b, :g], [:g, :r, :b], [:g, :b, :r], [:b, :r, :g],
|
50
|
-
# #
|
50
|
+
# # [:b, :g, :r]]
|
51
51
|
# string = "abc"# => "abc"
|
52
52
|
# perm.map { |p| p.project(string) }
|
53
53
|
# # => ["abc", "acb", "bac", "bca", "cab", "cba"]
|
@@ -120,42 +120,42 @@
|
|
120
120
|
#
|
121
121
|
|
122
122
|
class Permutation
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
123
|
+
include Enumerable
|
124
|
+
include Comparable
|
125
|
+
|
126
|
+
# Creates a new Permutation instance of <code>size</code>
|
127
|
+
# (and ranked with <code>rank</code>).
|
128
|
+
def initialize(size, rank = 0)
|
129
|
+
@size, @rank = size, rank
|
130
|
+
@last = factorial(size) - 1
|
131
|
+
end
|
132
|
+
|
133
|
+
# Creates a new Permutation instance from the Array
|
134
|
+
# <code>indices</code>, that should consist of a permutation of Fixnums
|
135
|
+
# in the range of <code>0</code> and <code>indices.size - 1</code>. This is
|
136
|
+
# for example the result of a call to the Permutation#value method.
|
137
|
+
def self.from_value(indices)
|
138
|
+
obj = new(indices.size)
|
139
|
+
obj.instance_eval do
|
140
|
+
self.rank = rank_indices(indices)
|
131
141
|
end
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
# Creates a new Permutation instance from the Array of Arrays
|
146
|
-
# <code>cycles</code>. This is for example the result of a
|
147
|
-
# call to the Permutation#cycles method .
|
148
|
-
def self.from_cycles(cycles, max = 0)
|
149
|
-
indices = Array.new(max)
|
150
|
-
cycles.each do |cycle|
|
151
|
-
cycle.empty? and next
|
152
|
-
for i in 0...cycle.size
|
153
|
-
indices[ cycle[i - 1] ] = cycle[i]
|
154
|
-
end
|
155
|
-
end
|
156
|
-
indices.each_with_index { |r, i| r or indices[i] = i }
|
157
|
-
from_value(indices)
|
142
|
+
obj
|
143
|
+
end
|
144
|
+
|
145
|
+
# Creates a new Permutation instance from the Array of Arrays
|
146
|
+
# <code>cycles</code>. This is for example the result of a
|
147
|
+
# call to the Permutation#cycles method .
|
148
|
+
def self.from_cycles(cycles, max = 0)
|
149
|
+
indices = Array.new(max)
|
150
|
+
cycles.each do |cycle|
|
151
|
+
cycle.empty? and next
|
152
|
+
for i in 0...cycle.size
|
153
|
+
indices[ cycle[i - 1] ] = cycle[i]
|
154
|
+
end
|
158
155
|
end
|
156
|
+
indices.each_with_index { |r, i| r or indices[i] = i }
|
157
|
+
from_value(indices)
|
158
|
+
end
|
159
159
|
|
160
160
|
# A permutation instance of size collection.size is created with
|
161
161
|
# collection as the default Permutation#project data object. A
|
@@ -167,301 +167,299 @@ class Permutation
|
|
167
167
|
perm
|
168
168
|
end
|
169
169
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
klon.rank = r
|
282
|
-
yield klon
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
# Does something similar to Permutation#each. It doesn't create new
|
287
|
-
# instances (less overhead) for every iteration step, but yields to a
|
288
|
-
# modified self instead. This is useful if one only wants to call a
|
289
|
-
# method on the yielded value and work with the result of this call. It's
|
290
|
-
# not a good idea to put the yielded values in a data structure because the
|
291
|
-
# will all reference the same (this!) instance. If you want to do this
|
292
|
-
# use Permutation#each.
|
293
|
-
def each!
|
294
|
-
old_rank = rank
|
295
|
-
0.upto(last) do |r|
|
296
|
-
self.rank = r
|
297
|
-
yield self
|
298
|
-
end
|
299
|
-
self.rank = old_rank
|
300
|
-
end
|
301
|
-
|
302
|
-
# Compares to Permutation instances according to their Permutation#size
|
303
|
-
# and the Permutation#rank.
|
304
|
-
#
|
305
|
-
# The mixed in methods from the Comparable module rely on this method.
|
306
|
-
def <=>(other)
|
307
|
-
size <=> other.size.zero? || rank <=> other.rank
|
308
|
-
end
|
309
|
-
|
310
|
-
# Returns true if this Permutation instance and the other have the same
|
311
|
-
# value, that is both Permutation instances have the same Permutation#size
|
312
|
-
# and the same Permutation#rank.
|
313
|
-
def eql?(other)
|
314
|
-
self.class == other.class && size == other.size && rank == other.rank
|
170
|
+
# Returns the size of this permutation, a Fixnum.
|
171
|
+
attr_reader :size
|
172
|
+
|
173
|
+
# Returns the size of this permutation, a Fixnum in the range
|
174
|
+
# of 0 and Permutation#last.
|
175
|
+
attr_reader :rank
|
176
|
+
|
177
|
+
# Returns the rank of the last ranked Permutation of size
|
178
|
+
# Permutation#size .
|
179
|
+
attr_reader :last
|
180
|
+
|
181
|
+
# Assigns <code>m</code> to the rank attribute of this Permutation
|
182
|
+
# instance. That implies that the indices produced by a call to the
|
183
|
+
# Permutation#value method of this instance is the permutation ranked with
|
184
|
+
# this new <code>rank</code>.
|
185
|
+
def rank=(m)
|
186
|
+
@rank = m % factorial(size)
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns the indices in the range of 0 to Permutation#size - 1
|
190
|
+
# of this permutation that is ranked with Permutation#rank.
|
191
|
+
#
|
192
|
+
# <b>Example:</b>
|
193
|
+
# perm = Permutation.new(6, 312)
|
194
|
+
# # => #<Permutation:0x6ae34 @last=719, @rank=312, @size=6>
|
195
|
+
# perm.value
|
196
|
+
# # => [2, 4, 0, 1, 3, 5]
|
197
|
+
def value
|
198
|
+
unrank_indices(@rank)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Returns the projection of this instance's Permutation#value
|
202
|
+
# into the <code>data</code> object that should respond to
|
203
|
+
# the #[] method. If this Permutation inbstance was created
|
204
|
+
# with Permutation.for the collection used to create
|
205
|
+
# it is used as a data object.
|
206
|
+
#
|
207
|
+
# <b>Example:</b>
|
208
|
+
# perm = Permutation.new(6, 312)
|
209
|
+
# # => #<Permutation:0x6ae34 @last=719, @rank=312, @size=6>
|
210
|
+
# perm.project("abcdef")
|
211
|
+
# # => "ceabdf"
|
212
|
+
def project(data = @collection)
|
213
|
+
data or raise ArgumentError, "a collection is required to project"
|
214
|
+
raise ArgumentError, "data size is != #{size}!" if data.size != size
|
215
|
+
projection = data.clone
|
216
|
+
value.each_with_index { |i, j| projection[j] = data[i] }
|
217
|
+
projection
|
218
|
+
end
|
219
|
+
|
220
|
+
# Switches this instances to the next ranked Permutation.
|
221
|
+
# If this was the Permutation#last permutation it wraps around
|
222
|
+
# the first (<code>rank == 0</code>) permutation.
|
223
|
+
def next!
|
224
|
+
@rank += 1
|
225
|
+
@rank = 0 if @rank > last
|
226
|
+
self
|
227
|
+
end
|
228
|
+
|
229
|
+
alias succ! next!
|
230
|
+
|
231
|
+
# Returns the next ranked Permutation instance.
|
232
|
+
# If this instance is the Permutation#last permutation it returns the first
|
233
|
+
# (<code>rank == 0</code>) permutation.
|
234
|
+
def next
|
235
|
+
clone.next!
|
236
|
+
end
|
237
|
+
|
238
|
+
alias succ next
|
239
|
+
|
240
|
+
# Switches this instances to the previously ranked Permutation.
|
241
|
+
# If this was the first permutation it returns the last (<code>rank ==
|
242
|
+
# Permutation#last</code>) permutation.
|
243
|
+
def pred!
|
244
|
+
@rank -= 1
|
245
|
+
@rank = last if @rank < 0
|
246
|
+
self
|
247
|
+
end
|
248
|
+
|
249
|
+
# Returns the previously ranked Permutation. If this was the first
|
250
|
+
# permutation it returns the last (<code>rank == Permutation#last</code>)
|
251
|
+
# permutation.
|
252
|
+
def pred
|
253
|
+
clone.pred!
|
254
|
+
end
|
255
|
+
|
256
|
+
# Switches this Permutation instance to random permutation
|
257
|
+
# of size Permutation#size.
|
258
|
+
def random!
|
259
|
+
new_rank = rand(last + 1).to_i
|
260
|
+
self.rank = new_rank
|
261
|
+
self
|
262
|
+
end
|
263
|
+
|
264
|
+
# Returns a random Permutation instance # of size Permutation#size.
|
265
|
+
def random
|
266
|
+
clone.random!
|
267
|
+
end
|
268
|
+
|
269
|
+
# Iterates over all permutations of size Permutation#size starting with the
|
270
|
+
# first (<code>rank == 0</code>) ranked permutation and ending with the
|
271
|
+
# last (<code>rank == Permutation#last</code>) ranked permutation while
|
272
|
+
# yielding to a freshly created Permutation instance for every iteration
|
273
|
+
# step.
|
274
|
+
#
|
275
|
+
# The mixed in methods from the Enumerable module rely on this method.
|
276
|
+
def each # :yields: perm
|
277
|
+
0.upto(last) do |r|
|
278
|
+
klon = clone
|
279
|
+
klon.rank = r
|
280
|
+
yield klon
|
315
281
|
end
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
282
|
+
end
|
283
|
+
|
284
|
+
# Does something similar to Permutation#each. It doesn't create new
|
285
|
+
# instances (less overhead) for every iteration step, but yields to a
|
286
|
+
# modified self instead. This is useful if one only wants to call a
|
287
|
+
# method on the yielded value and work with the result of this call. It's
|
288
|
+
# not a good idea to put the yielded values in a data structure because the
|
289
|
+
# will all reference the same (this!) instance. If you want to do this
|
290
|
+
# use Permutation#each.
|
291
|
+
def each!
|
292
|
+
old_rank = rank
|
293
|
+
0.upto(last) do |r|
|
294
|
+
self.rank = r
|
295
|
+
yield self
|
322
296
|
end
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
297
|
+
self.rank = old_rank
|
298
|
+
end
|
299
|
+
|
300
|
+
# Compares to Permutation instances according to their Permutation#size
|
301
|
+
# and the Permutation#rank.
|
302
|
+
#
|
303
|
+
# The mixed in methods from the Comparable module rely on this method.
|
304
|
+
def <=>(other)
|
305
|
+
size <=> other.size.zero? || rank <=> other.rank
|
306
|
+
end
|
307
|
+
|
308
|
+
# Returns true if this Permutation instance and the other have the same
|
309
|
+
# value, that is both Permutation instances have the same Permutation#size
|
310
|
+
# and the same Permutation#rank.
|
311
|
+
def eql?(other)
|
312
|
+
self.class == other.class && size == other.size && rank == other.rank
|
313
|
+
end
|
314
|
+
|
315
|
+
alias == eql?
|
316
|
+
|
317
|
+
# Computes a unique hash value for this Permutation instance.
|
318
|
+
def hash
|
319
|
+
size.hash ^ rank.hash
|
320
|
+
end
|
321
|
+
|
322
|
+
# Switchtes this Permutation instance to the inverted permutation.
|
323
|
+
# (See Permutation#compose for an example.)
|
324
|
+
def invert!
|
325
|
+
indices = unrank_indices(rank)
|
326
|
+
inverted = Array.new(size)
|
327
|
+
for i in 0...size
|
328
|
+
inverted[indices[i]] = i
|
334
329
|
end
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
330
|
+
self.rank = rank_indices(inverted)
|
331
|
+
self
|
332
|
+
end
|
333
|
+
|
334
|
+
# Returns the inverted Permutation of this Permutation instance.
|
335
|
+
# (See Permutation#compose for an example.)
|
336
|
+
def invert
|
337
|
+
clone.invert!
|
338
|
+
end
|
339
|
+
|
340
|
+
alias -@ invert
|
341
|
+
|
342
|
+
# Compose this Permutation instance and the other to
|
343
|
+
# a new Permutation. Note that a permutation
|
344
|
+
# composed with it's inverted permutation yields
|
345
|
+
# the identity permutation, the permutation with rank 0.
|
346
|
+
#
|
347
|
+
# <b>Example:</b>
|
348
|
+
# p1 = Permutation.new(5, 42)
|
349
|
+
# # => #<Permutation:0x75370 @last=119, @rank=42, @size=5>
|
350
|
+
# p2 = p1.invert
|
351
|
+
# # => #<Permutation:0x653d0 @last=119, @rank=51, @size=5>
|
352
|
+
# p1.compose(p2)
|
353
|
+
# => #<Permutation:0x639a4 @last=119, @rank=0, @size=5>
|
354
|
+
# Or a little nicer to look at:
|
355
|
+
# p1 * -p1
|
356
|
+
# # => #<Permutation:0x62004 @last=119, @rank=0, @size=5>
|
357
|
+
def compose(other)
|
358
|
+
size == other.size or raise ArgumentError,
|
359
|
+
"permutations of unequal sizes cannot be composed!"
|
360
|
+
indices = self.value
|
361
|
+
composed = other.value.map { |i| indices[i] }
|
362
|
+
klon = clone
|
363
|
+
klon.rank = rank_indices(composed)
|
364
|
+
klon
|
365
|
+
end
|
366
|
+
|
367
|
+
alias * compose
|
368
|
+
|
369
|
+
# Returns the cycles representation of this Permutation instance.
|
370
|
+
# The return value of this method can be used to create a
|
371
|
+
# new Permutation instance with the Permutation.from_cycles method.
|
372
|
+
#
|
373
|
+
# <b>Example:</b>
|
374
|
+
# perm = Permutation.new(7, 23)
|
375
|
+
# # => #<Permutation:0x58541c @last=5039, @rank=23, @size=7>
|
376
|
+
# perm.cycles
|
377
|
+
# # => [[3, 6], [4, 5]]
|
378
|
+
def cycles
|
379
|
+
perm = value
|
380
|
+
result = [[]]
|
381
|
+
seen = {}
|
382
|
+
current = nil
|
383
|
+
until seen == perm.size
|
384
|
+
current or current = perm.find { |x| !seen[x] }
|
385
|
+
break unless current
|
386
|
+
if seen[current]
|
384
387
|
current = nil
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
else
|
392
|
-
seen[current] = true
|
393
|
-
result[-1] << current
|
394
|
-
current = perm[current]
|
395
|
-
end
|
396
|
-
end
|
397
|
-
result.pop
|
398
|
-
result.select { |c| c.size > 1 }.map do |c|
|
399
|
-
min_index = c.index(c.min)
|
400
|
-
c[min_index..-1] + c[0...min_index]
|
401
|
-
end
|
388
|
+
result << []
|
389
|
+
else
|
390
|
+
seen[current] = true
|
391
|
+
result[-1] << current
|
392
|
+
current = perm[current]
|
393
|
+
end
|
402
394
|
end
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
#
|
408
|
-
# A permutation is odd if it can be represented by an odd number of
|
409
|
-
# transpositions (cycles of length 2), or even if it can be represented of
|
410
|
-
# an even number of transpositions.
|
411
|
-
def signum
|
412
|
-
s = 1
|
413
|
-
cycles.each do |c|
|
414
|
-
c.size % 2 == 0 and s *= -1
|
415
|
-
end
|
416
|
-
s
|
395
|
+
result.pop
|
396
|
+
result.select { |c| c.size > 1 }.map do |c|
|
397
|
+
min_index = c.index(c.min)
|
398
|
+
c[min_index..-1] + c[0...min_index]
|
417
399
|
end
|
400
|
+
end
|
401
|
+
|
402
|
+
# Returns the signum of this Permutation instance.
|
403
|
+
# It's -1 if this permutation is odd and 1 if it's
|
404
|
+
# an even permutation.
|
405
|
+
#
|
406
|
+
# A permutation is odd if it can be represented by an odd number of
|
407
|
+
# transpositions (cycles of length 2), or even if it can be represented of
|
408
|
+
# an even number of transpositions.
|
409
|
+
def signum
|
410
|
+
s = 1
|
411
|
+
cycles.each do |c|
|
412
|
+
c.size % 2 == 0 and s *= -1
|
413
|
+
end
|
414
|
+
s
|
415
|
+
end
|
418
416
|
|
419
|
-
|
417
|
+
alias sgn signum
|
420
418
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
419
|
+
# Returns true if this permutation is even, false otherwise.
|
420
|
+
def even?
|
421
|
+
signum == 1
|
422
|
+
end
|
425
423
|
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
424
|
+
# Returns true if this permutation is odd, false otherwise.
|
425
|
+
def odd?
|
426
|
+
signum == -1
|
427
|
+
end
|
430
428
|
|
431
|
-
|
429
|
+
private
|
432
430
|
|
433
|
-
|
431
|
+
@@fcache = [ 1 ]
|
434
432
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
433
|
+
def factorial(n)
|
434
|
+
@@fcache.size.upto(n) { |i| @@fcache[i] = i * @@fcache[i - 1] }
|
435
|
+
@@fcache[n]
|
436
|
+
end
|
439
437
|
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
end
|
448
|
-
result
|
438
|
+
def rank_indices(p)
|
439
|
+
result = 0
|
440
|
+
for i in 0...size
|
441
|
+
result += p[i] * factorial(size - i - 1)
|
442
|
+
for j in (i + 1)...size
|
443
|
+
p[j] -= 1 if p[j] > p[i]
|
444
|
+
end
|
449
445
|
end
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
446
|
+
result
|
447
|
+
end
|
448
|
+
|
449
|
+
def unrank_indices(m)
|
450
|
+
result = Array.new(size, 0)
|
451
|
+
for i in 0...size
|
452
|
+
f = factorial(i)
|
453
|
+
x = m % (f * (i + 1))
|
454
|
+
m -= x
|
455
|
+
x /= f
|
456
|
+
result[size - i - 1] = x
|
457
|
+
x -= 1
|
458
|
+
for j in (size - i)...size
|
459
|
+
result[j] += 1 if result[j] > x
|
460
|
+
end
|
465
461
|
end
|
462
|
+
result
|
463
|
+
end
|
466
464
|
end
|
467
|
-
|
465
|
+
# vim: set et sw=4 ts=4:
|
data/lib/permutation/version.rb
CHANGED
data/test/test.rb
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,62 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.2
|
3
|
-
specification_version: 1
|
4
2
|
name: permutation
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.1.
|
7
|
-
date: 2007-04-17 00:00:00 +02:00
|
8
|
-
summary: Permutation library in pure Ruby
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email: flori@ping.de
|
12
|
-
homepage: http://permutation.rubyforge.org
|
13
|
-
rubyforge_project: permutation
|
14
|
-
description: Library to perform different operations with permutations of sequences (strings, arrays, etc.)
|
15
|
-
autorequire:
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
4
|
+
version: 0.1.6
|
25
5
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
6
|
authors:
|
30
7
|
- Florian Frank
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-12-01 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Library to perform different operations with permutations of sequences (strings, arrays, etc.)
|
17
|
+
email: flori@ping.de
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- lib/permutation/version.rb
|
24
|
+
- lib/permutation.rb
|
31
25
|
files:
|
32
|
-
- VERSION
|
33
|
-
- GPL
|
34
|
-
- README.en
|
35
26
|
- install.rb
|
36
|
-
- Rakefile
|
37
|
-
- examples
|
38
27
|
- lib
|
39
|
-
- test
|
40
|
-
- CHANGES
|
41
|
-
- examples/tsp.rb
|
42
|
-
- lib/permutation.rb
|
43
28
|
- lib/permutation
|
44
29
|
- lib/permutation/version.rb
|
30
|
+
- lib/permutation.rb
|
31
|
+
- CHANGES
|
32
|
+
- README.en
|
33
|
+
- VERSION
|
34
|
+
- test
|
45
35
|
- test/test.rb
|
46
|
-
|
47
|
-
-
|
36
|
+
- Rakefile
|
37
|
+
- GPL
|
38
|
+
- examples
|
39
|
+
- examples/tsp.rb
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://permutation.rubyforge.org
|
42
|
+
post_install_message:
|
48
43
|
rdoc_options:
|
49
44
|
- --title
|
50
45
|
- Permutation
|
51
46
|
- --line-numbers
|
52
|
-
|
53
|
-
- lib
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
59
61
|
requirements: []
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
+
rubyforge_project: permutation
|
64
|
+
rubygems_version: 1.3.1
|
65
|
+
signing_key:
|
66
|
+
specification_version: 2
|
67
|
+
summary: Permutation library in pure Ruby
|
68
|
+
test_files:
|
69
|
+
- test/test.rb
|