combinatorics 0.3.1 → 0.4.1

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.
Files changed (69) hide show
  1. data/.gemtest +0 -0
  2. data/.gitignore +8 -0
  3. data/Benchmarks.md +257 -26
  4. data/ChangeLog.md +12 -0
  5. data/LICENSE.txt +1 -2
  6. data/README.md +102 -32
  7. data/Rakefile +13 -2
  8. data/benchmarks/cartesian_product.rb +18 -0
  9. data/benchmarks/choose.rb +19 -0
  10. data/benchmarks/derange.rb +18 -0
  11. data/benchmarks/list_comprehension.rb +2 -5
  12. data/benchmarks/permute.rb +18 -0
  13. data/benchmarks/power_set.rb +18 -0
  14. data/combinatorics.gemspec +124 -7
  15. data/gemspec.yml +11 -6
  16. data/lib/combinatorics.rb +7 -0
  17. data/lib/combinatorics/cartesian_product.rb +3 -0
  18. data/lib/combinatorics/cartesian_product/cardinality.rb +45 -0
  19. data/lib/combinatorics/cartesian_product/extensions.rb +2 -0
  20. data/lib/combinatorics/cartesian_product/extensions/array.rb +7 -0
  21. data/lib/combinatorics/cartesian_product/extensions/set.rb +9 -0
  22. data/lib/combinatorics/cartesian_product/mixin.rb +57 -0
  23. data/lib/combinatorics/choose.rb +3 -0
  24. data/lib/combinatorics/choose/cardinality.rb +99 -0
  25. data/lib/combinatorics/choose/extensions.rb +2 -0
  26. data/lib/combinatorics/choose/extensions/array.rb +5 -0
  27. data/lib/combinatorics/choose/extensions/set.rb +6 -0
  28. data/lib/combinatorics/choose/mixin.rb +53 -0
  29. data/lib/combinatorics/derange.rb +3 -0
  30. data/lib/combinatorics/derange/cardinality.rb +23 -0
  31. data/lib/combinatorics/derange/extensions.rb +1 -0
  32. data/lib/combinatorics/derange/extensions/array.rb +5 -0
  33. data/lib/combinatorics/derange/mixin.rb +47 -0
  34. data/lib/combinatorics/enumerator.rb +2 -0
  35. data/lib/combinatorics/extensions/math.rb +177 -0
  36. data/lib/combinatorics/generator.rb +8 -1
  37. data/lib/combinatorics/permute.rb +3 -0
  38. data/lib/combinatorics/permute/cardinality.rb +98 -0
  39. data/lib/combinatorics/permute/extensions.rb +2 -0
  40. data/lib/combinatorics/permute/extensions/array.rb +7 -0
  41. data/lib/combinatorics/permute/extensions/set.rb +9 -0
  42. data/lib/combinatorics/permute/mixin.rb +48 -0
  43. data/lib/combinatorics/power_set.rb +1 -0
  44. data/lib/combinatorics/power_set/cardinality.rb +36 -0
  45. data/lib/combinatorics/power_set/mixin.rb +19 -22
  46. data/lib/combinatorics/version.rb +2 -2
  47. data/spec/cartesian_product/array_spec.rb +10 -0
  48. data/spec/cartesian_product/cardinality_spec.rb +64 -0
  49. data/spec/cartesian_product/mixin_examples.rb +98 -0
  50. data/spec/cartesian_product/set_spec.rb +10 -0
  51. data/spec/choose/array_spec.rb +9 -0
  52. data/spec/choose/cardinality_spec.rb +132 -0
  53. data/spec/choose/mixin_examples.rb +48 -0
  54. data/spec/choose/set_spec.rb +9 -0
  55. data/spec/derange/array_spec.rb +10 -0
  56. data/spec/derange/cardinality_spec.rb +14 -0
  57. data/spec/derange/mixin_examples.rb +52 -0
  58. data/spec/extensions/math_spec.rb +100 -0
  59. data/spec/extensions/range_spec.rb +1 -1
  60. data/spec/permute/array_spec.rb +10 -0
  61. data/spec/permute/cardinality_spec.rb +146 -0
  62. data/spec/permute/mixin_examples.rb +42 -0
  63. data/spec/permute/set_spec.rb +10 -0
  64. data/spec/power_set/array_spec.rb +3 -2
  65. data/spec/power_set/cardinality_spec.rb +32 -0
  66. data/spec/power_set/mixin_examples.rb +17 -8
  67. data/spec/power_set/set_spec.rb +3 -2
  68. data/spec/spec_helper.rb +5 -3
  69. metadata +114 -95
data/Rakefile CHANGED
@@ -2,28 +2,39 @@ require 'rubygems'
2
2
  require 'rake'
3
3
 
4
4
  begin
5
+ gem 'ore-tasks', '~> 0.4'
5
6
  require 'ore/tasks'
7
+
6
8
  Ore::Tasks.new
7
9
  rescue LoadError => e
8
- STDERR.puts e.message
9
- STDERR.puts "Run `gem install ore-tasks` to install 'ore/tasks'."
10
+ warn e.message
11
+ warn "Run `gem install ore-tasks` to install 'ore/tasks'."
10
12
  end
11
13
 
12
14
  begin
15
+ gem 'rspec', '~> 2.4'
13
16
  require 'rspec/core/rake_task'
17
+
14
18
  RSpec::Core::RakeTask.new
15
19
  rescue LoadError => e
16
20
  task :spec do
17
21
  abort "Please run `gem install rspec` to install RSpec."
18
22
  end
19
23
  end
24
+ task :test => :spec
20
25
  task :default => :spec
21
26
 
22
27
  begin
28
+ gem 'yard', '~> 0.7'
23
29
  require 'yard'
30
+
24
31
  YARD::Rake::YardocTask.new
25
32
  rescue LoadError => e
26
33
  task :yard do
27
34
  abort "Please run `gem install yard` to install YARD."
28
35
  end
29
36
  end
37
+
38
+ task :benchmark do
39
+ Dir.glob('benchmarks/*.rb') { |script| ruby(script) }
40
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
4
+ lib_dir = File.join(root_dir,'lib')
5
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
6
+
7
+ require 'benchmark'
8
+ require 'combinatorics/cartesian_product'
9
+
10
+ Benchmark.bm(13) do |b|
11
+ [100, 200, 400, 800].each do |i|
12
+ n = (1..i).to_a
13
+
14
+ b.report("{#{i}} x {#{i}}") do
15
+ n.cartesian_product(n).to_a
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
4
+ lib_dir = File.join(root_dir,'lib')
5
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
6
+
7
+ require 'benchmark'
8
+ require 'combinatorics/choose'
9
+
10
+ Benchmark.bm do |b|
11
+ n = 20
12
+ array = (1..n).to_a
13
+
14
+ (1..n).each do |i|
15
+ b.report("n=#{n} k=#{i}") do
16
+ array.choose(i) { |s| }
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
4
+ lib_dir = File.join(root_dir,'lib')
5
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
6
+
7
+ require 'benchmark'
8
+ require 'combinatorics/derange'
9
+
10
+ Benchmark.bm do |b|
11
+ (1..10).each do |n|
12
+ array = (1..n).to_a
13
+
14
+ b.report("n=#{n}") do
15
+ array.derange { |s| }
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,3 @@
1
- #!/usr/bin/env ruby
2
-
3
1
  root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
4
2
  lib_dir = File.join(root_dir,'lib')
5
3
  $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
@@ -9,14 +7,13 @@ require 'combinatorics/list_comprehension'
9
7
 
10
8
  Benchmark.bm(12) do |b|
11
9
  singleton_list = ([1] * 500)
12
- single_enum_list = [1..200, 1]
13
- depth_list = [1..200]
10
+ single_enum_list = [1..100, 1]
11
+ depth_list = [1..100]
14
12
 
15
13
  b.report('singleton:') do
16
14
  singleton_list.comprehension.each { |list| list.last }
17
15
  end
18
16
 
19
-
20
17
  b.report('single-enum:') do
21
18
  single_enum_list.comprehension.each { |list| list.last }
22
19
  end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
4
+ lib_dir = File.join(root_dir,'lib')
5
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
6
+
7
+ require 'benchmark'
8
+ require 'combinatorics/permute'
9
+
10
+ Benchmark.bm do |b|
11
+ array = (1..10).to_a
12
+
13
+ (1..10).each do |n|
14
+ b.report("r=#{n}") do
15
+ array.permute(n) { |s| }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ root_dir = File.expand_path(File.join(File.dirname(__FILE__),'..'))
4
+ lib_dir = File.join(root_dir,'lib')
5
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
6
+
7
+ require 'benchmark'
8
+ require 'combinatorics/power_set'
9
+
10
+ Benchmark.bm do |b|
11
+ (10..20).each do |n|
12
+ array = (1..n).to_a
13
+
14
+ b.report("n=#{n}") do
15
+ array.power_set { |s| }
16
+ end
17
+ end
18
+ end
@@ -1,10 +1,127 @@
1
- # -*- encoding: utf-8 -*-
1
+ # encoding: utf-8
2
2
 
3
- begin
4
- Ore::Specification.new do |gemspec|
5
- # custom logic here
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gemspec|
6
+ files = if File.directory?('.git')
7
+ `git ls-files`.split($/)
8
+ elsif File.directory?('.hg')
9
+ `hg manifest`.split($/)
10
+ elsif File.directory?('.svn')
11
+ `svn ls -R`.split($/).select { |path| File.file?(path) }
12
+ else
13
+ Dir['{**/}{.*,*}'].select { |path| File.file?(path) }
14
+ end
15
+
16
+ filter_files = lambda { |paths|
17
+ case paths
18
+ when Array
19
+ (files & paths)
20
+ when String
21
+ (files & Dir[paths])
22
+ end
23
+ }
24
+
25
+ version = {
26
+ :file => 'lib/combinatorics/version.rb',
27
+ :constant => 'Combinatorics::VERSION'
28
+ }
29
+
30
+ defaults = {
31
+ 'name' => File.basename(File.dirname(__FILE__)),
32
+ 'files' => files,
33
+ 'executables' => filter_files['bin/*'].map { |path| File.basename(path) },
34
+ 'test_files' => filter_files['{test/{**/}*_test.rb,spec/{**/}*_spec.rb}'],
35
+ 'extra_doc_files' => filter_files['*.{txt,rdoc,md,markdown,tt,textile}'],
36
+ }
37
+
38
+ metadata = defaults.merge(YAML.load_file('gemspec.yml'))
39
+
40
+ gemspec.name = metadata.fetch('name',defaults[:name])
41
+ gemspec.version = if metadata['version']
42
+ metadata['version']
43
+ elsif File.file?(version[:file])
44
+ require File.join('.',version[:file])
45
+ eval(version[:constant])
46
+ end
47
+
48
+ gemspec.summary = metadata.fetch('summary',metadata['description'])
49
+ gemspec.description = metadata.fetch('description',metadata['summary'])
50
+
51
+ case metadata['license']
52
+ when Array
53
+ gemspec.licenses = metadata['license']
54
+ when String
55
+ gemspec.license = metadata['license']
56
+ end
57
+
58
+ case metadata['authors']
59
+ when Array
60
+ gemspec.authors = metadata['authors']
61
+ when String
62
+ gemspec.author = metadata['authors']
63
+ end
64
+
65
+ gemspec.email = metadata['email']
66
+ gemspec.homepage = metadata['homepage']
67
+
68
+ case metadata['require_paths']
69
+ when Array
70
+ gemspec.require_paths = metadata['require_paths']
71
+ when String
72
+ gemspec.require_path = metadata['require_paths']
73
+ end
74
+
75
+ gemspec.files = filter_files[metadata['files']]
76
+
77
+ gemspec.executables = metadata['executables']
78
+ gemspec.extensions = metadata['extensions']
79
+
80
+ if Gem::VERSION < '1.7.'
81
+ gemspec.default_executable = gemspec.executables.first
82
+ end
83
+
84
+ gemspec.test_files = filter_files[metadata['test_files']]
85
+
86
+ unless gemspec.files.include?('.document')
87
+ gemspec.extra_rdoc_files = metadata['extra_doc_files']
88
+ end
89
+
90
+ gemspec.post_install_message = metadata['post_install_message']
91
+ gemspec.requirements = metadata['requirements']
92
+
93
+ if gemspec.respond_to?(:required_ruby_version=)
94
+ gemspec.required_ruby_version = metadata['required_ruby_version']
95
+ end
96
+
97
+ if gemspec.respond_to?(:required_rubygems_version=)
98
+ gemspec.required_rubygems_version = metadata['required_rubygems_version']
99
+ end
100
+
101
+ parse_versions = lambda { |versions|
102
+ case versions
103
+ when Array
104
+ versions.map { |v| v.to_s }
105
+ when String
106
+ versions.split(/,\s*/)
107
+ end
108
+ }
109
+
110
+ if metadata['dependencies']
111
+ metadata['dependencies'].each do |name,versions|
112
+ gemspec.add_dependency(name,parse_versions[versions])
113
+ end
114
+ end
115
+
116
+ if metadata['runtime_dependencies']
117
+ metadata['runtime_dependencies'].each do |name,versions|
118
+ gemspec.add_runtime_dependency(name,parse_versions[versions])
119
+ end
120
+ end
121
+
122
+ if metadata['development_dependencies']
123
+ metadata['development_dependencies'].each do |name,versions|
124
+ gemspec.add_development_dependency(name,parse_versions[versions])
125
+ end
6
126
  end
7
- rescue NameError
8
- STDERR.puts "The 'combinatorics.gemspec' file requires Ore."
9
- STDERR.puts "Run `gem install ore` to install Ore."
10
127
  end
data/gemspec.yml CHANGED
@@ -4,13 +4,18 @@ description:
4
4
  A collection of modules and methods for performing Combinatoric
5
5
  calculations.
6
6
  license: MIT
7
- authors: Postmodern
8
- email: postmodern.mod3@gmail.com
7
+ authors:
8
+ - Postmodern
9
+ - Duper
10
+ email:
11
+ - postmodern.mod3@gmail.com
12
+ - super@manson.vistech.net
9
13
  homepage: http://github.com/postmodern/combinatorics
10
14
  has_yard: true
11
15
 
16
+ required_ruby_version: ">= 1.8.7"
17
+
12
18
  development_dependencies:
13
- ore: ~> 0.1.0
14
- ore-tasks: ~> 0.1.0
15
- rspec: ~> 2.0.0
16
- yard: ~> 0.6.0
19
+ ore-tasks: ~> 0.4
20
+ rspec: ~> 2.4
21
+ yard: ~> 0.7
data/lib/combinatorics.rb CHANGED
@@ -1,4 +1,11 @@
1
+ require 'combinatorics/cartesian_product'
2
+ require 'combinatorics/choose'
3
+ require 'combinatorics/derange'
1
4
  require 'combinatorics/extensions'
2
5
  require 'combinatorics/list_comprehension'
3
6
  require 'combinatorics/power_set'
7
+ require 'combinatorics/permute'
4
8
  require 'combinatorics/version'
9
+
10
+ # @todo inversions (permutation mutations)
11
+ # @todo set families (approximate power set subsets)
@@ -0,0 +1,3 @@
1
+ require 'combinatorics/cartesian_product/mixin'
2
+ require 'combinatorics/cartesian_product/extensions'
3
+ require 'combinatorics/cartesian_product/cardinality'
@@ -0,0 +1,45 @@
1
+ module Combinatorics
2
+ #
3
+ # @author duper <super@manson.vistech.net>
4
+ #
5
+ # @since 0.4.0
6
+ #
7
+ module CartesianProduct
8
+ #
9
+ # Wrapper for Cartesian product cardinality method defined above
10
+ #
11
+ # @param [Fixnum] a
12
+ # Cardinality of first set.
13
+ #
14
+ # @param [Fixnum] b
15
+ # Cardinality of second set.
16
+ #
17
+ # @raise [RangeError]
18
+ # Inputs must be greater than zero.
19
+ #
20
+ # @return [Fixnum]
21
+ # Length of enumeration resulting from a Cartesian product.
22
+ #
23
+ # @example Calculate elements in Cartesian product of two equal-size sets
24
+ # cardinality(3, 4)
25
+ # # => 12
26
+ #
27
+ def self.cardinality(a,b)
28
+ if (a <= 0 || b <= 0)
29
+ raise(RangeError,"inputs must be greater than zero")
30
+ end
31
+
32
+ a * b
33
+ end
34
+
35
+ #
36
+ # @note The letter `X' is scholastic notation for the Cartesian product
37
+ # set operation
38
+ #
39
+ # @see cardinality
40
+ #
41
+ def self.X(a,b)
42
+ cardinality(a,b)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,2 @@
1
+ require 'combinatorics/cartesian_product/extensions/array'
2
+ require 'combinatorics/cartesian_product/extensions/set'
@@ -0,0 +1,7 @@
1
+ require 'combinatorics/cartesian_product/mixin'
2
+
3
+ class Array
4
+
5
+ include Combinatorics::CartesianProduct::Mixin
6
+
7
+ end
@@ -0,0 +1,9 @@
1
+ require 'combinatorics/cartesian_product/mixin'
2
+
3
+ require 'set'
4
+
5
+ class Set
6
+
7
+ include Combinatorics::CartesianProduct::Mixin
8
+
9
+ end
@@ -0,0 +1,57 @@
1
+ require 'combinatorics/list_comprehension'
2
+
3
+ module Combinatorics
4
+ module CartesianProduct
5
+ #
6
+ # @author duper <super@manson.vistech.net>
7
+ #
8
+ # @since 0.4.0
9
+ #
10
+ module Mixin
11
+ #
12
+ # Calculates the Cartesian product of an Enumerable object.
13
+ #
14
+ # @yield [subset]
15
+ # If a block is given, it will be passed each individual subset
16
+ # element from the Cartesian product set as a whole.
17
+ #
18
+ # @yieldparam [Array] subset
19
+ # The sub-set from the Cartesian product.
20
+ #
21
+ # @return [Enumerator]
22
+ # Resulting Cartesian product set.
23
+ #
24
+ # @raise [TypeError]
25
+ # `other` must be Enumerable.
26
+ #
27
+ # @example Cartesian product of an Array
28
+ # [1, 2].cartesian_product([3, 4])
29
+ # # => [[1, 3], [2, 3], [1, 4], [2, 4]]
30
+ #
31
+ # @example Cartesian product over an Array of Strings
32
+ # ['a'].cartesian_product(['b', 'c', 'd']).to_a
33
+ # # => [["a", "b"], ["a", "c"], ["a", "d"]]
34
+ #
35
+ # @example Three-way Cartesian product operation
36
+ # [0, 1].cartesian_product([2, 3], [4, 5]).to_a
37
+ # # => [
38
+ # # [0, 2, 4], [0, 2, 5], [0, 3, 4], [0, 3, 5],
39
+ # # [1, 2, 4], [1, 2, 5], [1, 3, 4], [1, 3, 5],
40
+ # # ]
41
+ #
42
+ # @see http://en.wikipedia.org/wiki/Cartesian_product
43
+ #
44
+ def cartesian_product(*others,&block)
45
+ return enum_for(:cartesian_product,*others) unless block
46
+
47
+ # a single empty Set will result in an empty Set
48
+ return nil if (empty? || others.any?(&:empty?))
49
+
50
+ Array[self,*others].comprehension(&block)
51
+ end
52
+
53
+ alias cartprod cartesian_product
54
+ alias cartesian cartesian_product
55
+ end
56
+ end
57
+ end