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
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ require 'cartesian_product/mixin_examples'
3
+
4
+ require 'combinatorics/cartesian_product/extensions/set'
5
+
6
+ describe Set do
7
+ subject { Set }
8
+
9
+ it_should_behave_like "CartesianProduct::Mixin"
10
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+ require 'combinatorics/choose/extensions/array'
3
+ require 'choose/mixin_examples'
4
+
5
+ describe Array do
6
+ subject { Array }
7
+
8
+ it_should_behave_like 'Choose::Mixin'
9
+ end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+ require 'combinatorics/choose'
3
+
4
+ describe Choose do
5
+ subject { Choose }
6
+
7
+ describe "cardinality" do
8
+ it "should raise RangeError if n is negative" do
9
+ lambda { subject.cardinality(-1) }.should raise_error(RangeError)
10
+ end
11
+
12
+ it "should raise RangeError if n is negative" do
13
+ lambda { subject.cardinality(-1, 1) }.should raise_error(RangeError)
14
+ end
15
+
16
+ it "should raise RangeError if r is negative" do
17
+ lambda { subject.cardinality(1, -1) }.should raise_error(RangeError)
18
+ end
19
+
20
+ it "should raise RangeError if r is greater than n" do
21
+ lambda { subject.cardinality(2, 3) }.should raise_error(RangeError)
22
+ end
23
+
24
+ it "should return 1 for subject.cardinality(0)" do
25
+ subject.cardinality(0).should == 1
26
+ end
27
+
28
+ it "should return 1 for subject.cardinality(1)" do
29
+ subject.cardinality(1).should == 1
30
+ end
31
+
32
+ it "should return 2 for subject.cardinality(2)" do
33
+ subject.cardinality(2).should == 2
34
+ end
35
+
36
+ it "should return 6 for subject.cardinality(3)" do
37
+ subject.cardinality(3).should == 6
38
+ end
39
+
40
+ it "should return 24 for subject.cardinality(4)" do
41
+ subject.cardinality(4).should == 24
42
+ end
43
+
44
+ it "should return 0 for subject.cardinality(1, 0)" do
45
+ subject.cardinality(1, 0).should == 0
46
+ end
47
+
48
+ it "should return 1 for subject.cardinality(1, 1)" do
49
+ subject.cardinality(1, 1).should == 1
50
+ end
51
+
52
+ it "should return 2 for subject.cardinality(2, 1)" do
53
+ subject.cardinality(2, 1).should == 2
54
+ end
55
+
56
+ it "should return 1 for subject.cardinality(2, 2)" do
57
+ subject.cardinality(2, 2).should == 1
58
+ end
59
+
60
+ it "should return 3 for subject.cardinality(3, 1)" do
61
+ subject.cardinality(3, 1).should == 3
62
+ end
63
+
64
+ it "should return 3 for subject.cardinality(3, 2)" do
65
+ subject.cardinality(3, 2).should == 3
66
+ end
67
+
68
+ it "should return 1 for subject.cardinality(3, 3)" do
69
+ subject.cardinality(3, 3).should == 1
70
+ end
71
+
72
+ it "should return 4 for subject.cardinality(4, 1)" do
73
+ subject.cardinality(4, 1).should == 4
74
+ end
75
+
76
+ it "should return 6 for subject.cardinality(4, 2)" do
77
+ subject.cardinality(4, 2).should == 6
78
+ end
79
+
80
+ it "should return 4 for subject.cardinality(4, 3)" do
81
+ subject.cardinality(4, 3).should == 4
82
+ end
83
+
84
+ it "should return 1 for subject.cardinality(4, 4)" do
85
+ subject.cardinality(4, 4).should == 1
86
+ end
87
+
88
+ it "should return 15 for subject.cardinality(6, 4)" do
89
+ subject.cardinality(6, 4).should == 15
90
+ end
91
+
92
+ it "should return 3628800 for subject.cardinality(10)" do
93
+ subject.cardinality(10).should == 3628800
94
+ end
95
+ end
96
+
97
+ describe "cardinality_all" do
98
+ it "should return [] for subject.cardinality_all(0)" do
99
+ subject.cardinality_all(0).should be_empty
100
+ end
101
+
102
+ it "should return [1] for subject.cardinality_all(1)" do
103
+ subject.cardinality_all(1).should == [1]
104
+ end
105
+
106
+ it "should return [2, 1] for subject.cardinality_all(2)" do
107
+ subject.cardinality_all(2).should == [2, 1]
108
+ end
109
+
110
+ it "should return [3, 3, 1] for subject.cardinality_all(3)" do
111
+ subject.cardinality_all(3).should == [3, 3, 1]
112
+ end
113
+
114
+ it "should return [4, 6, 4, 1] for subject.cardinality_all(4)" do
115
+ subject.cardinality_all(4).should == [4, 6, 4, 1]
116
+ end
117
+
118
+ it "should allow specifying the range of `r` values" do
119
+ subject.cardinality_all(10,5..10).should == [
120
+ 252, 210, 120, 45, 10, 1
121
+ ]
122
+ end
123
+
124
+ it "should raise RangeError for subject.cardinality_all(-1)" do
125
+ lambda { subject.cardinality_all(-1) }.should raise_error(RangeError)
126
+ end
127
+
128
+ it "should wrap cardinality with Choose.C" do
129
+ should respond_to(:C)
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'combinatorics/choose'
3
+
4
+ shared_examples_for "Choose::Mixin" do
5
+ let(:empty_set) { Set[] }
6
+
7
+ it "should return [[]] for [].choose(0).to_a" do
8
+ set = subject[]
9
+ results = set.choose(0).to_a
10
+
11
+ results.should == [empty_set]
12
+ end
13
+
14
+ it "should return [[]] for [1].choose(0).to_a" do
15
+ set = subject[1]
16
+ results = set.choose(0).to_a
17
+
18
+ results.should == [empty_set]
19
+ end
20
+
21
+ it "should return [[1]] for [1].choose(1).to_a" do
22
+ set = subject[1]
23
+ results = set.choose(1).to_a
24
+
25
+ results.should == [Set[1]]
26
+ end
27
+
28
+ it "should return [[1], [2]] for [1, 2].choose(1).to_a" do
29
+ set = subject[1, 2]
30
+ results = set.choose(1).to_a
31
+
32
+ results.should =~ [Set[1], Set[2]]
33
+ end
34
+
35
+ it "should return [[1, 2]] for [1, 2].choose(2).to_a" do
36
+ set = subject[1, 2]
37
+ results = set.choose(2).to_a
38
+
39
+ results.should == [Set[1, 2]]
40
+ end
41
+
42
+ it "should filter out repeated elements" do
43
+ set1 = subject[1,1,2,3]
44
+ set2 = subject[1,2,3]
45
+
46
+ set1.choose(2).to_a.should == set2.choose(2).to_a
47
+ end
48
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+ require 'combinatorics/choose/extensions/set'
3
+ require 'choose/mixin_examples'
4
+
5
+ describe Set do
6
+ subject { Set }
7
+
8
+ it_should_behave_like 'Choose::Mixin'
9
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ require 'derange/mixin_examples'
3
+
4
+ require 'combinatorics/derange/extensions/array'
5
+
6
+ describe Array do
7
+ subject { Array }
8
+
9
+ it_should_behave_like "Derange::Mixin"
10
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+ require 'combinatorics/derange/cardinality'
3
+
4
+ describe Derange do
5
+ subject { Derange }
6
+
7
+ it "should alias cardinality to subfactorial" do
8
+ should respond_to(:cardinality)
9
+ end
10
+
11
+ it "should wrap subfactorial with Derange.D" do
12
+ should respond_to(:D)
13
+ end
14
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ require 'combinatorics/derange'
4
+
5
+ shared_examples_for "Derange::Mixin" do
6
+ it "the derange of an empty Set should only contain an empty Array" do
7
+ set = subject[]
8
+ results = set.derange.to_a
9
+
10
+ results.should == [[]]
11
+ end
12
+
13
+ it "should return [[]] for [1].derange.to_a" do
14
+ set = subject[1]
15
+ results = set.derange.to_a
16
+
17
+ results.should == [[]]
18
+ end
19
+
20
+ it "should return [[2, 1]] for [1, 2].derange.to_a" do
21
+ set = subject[1, 2]
22
+ results = set.derange.to_a
23
+
24
+ results.should == [[2, 1]]
25
+ end
26
+
27
+ it "should return [[2, 1, 4, 3], [2, 3, 4, 1], [2, 4, 1, 3], [3, 1, 4, 2], [3, 4, 1, 2], [3, 4, 2, 1], [4, 1, 2, 3], [4, 3, 1, 2], [4, 3, 2, 1]] for [1, 2, 3, 4].derange.to_a" do
28
+ set = [1, 2, 3, 4]
29
+ results = set.derange.to_a
30
+
31
+ results.should == [
32
+ [2, 1, 4, 3],
33
+ [2, 3, 4, 1],
34
+ [2, 4, 1, 3],
35
+ [3, 1, 4, 2],
36
+ [3, 4, 1, 2],
37
+ [3, 4, 2, 1],
38
+ [4, 1, 2, 3],
39
+ [4, 3, 1, 2],
40
+ [4, 3, 2, 1]
41
+ ]
42
+ end
43
+
44
+ it "should take an optional block argument" do
45
+ set = subject[1, 2, 3]
46
+ results = []
47
+
48
+ set.derange { |deranged| results << deranged }
49
+
50
+ results.should == [[2, 3, 1], [3, 1, 2]]
51
+ end
52
+ end
@@ -0,0 +1,100 @@
1
+ require 'spec_helper'
2
+ require 'combinatorics/extensions/math'
3
+
4
+ describe Math do
5
+ it "should alias Sigma to sigma" do
6
+ should respond_to(:Sigma)
7
+ end
8
+
9
+ it "should alias Pi to pi" do
10
+ should respond_to(:Pi)
11
+ end
12
+
13
+ describe "sigma" do
14
+ it "should return 6 for sigma(1..3)" do
15
+ subject.sigma(1..3).should == 6
16
+ end
17
+
18
+ it "should return 60 for sigma(3..5)" do
19
+ subject.sigma(3..5).should == 12
20
+ end
21
+
22
+ it "should take an optional block argument" do
23
+ result = subject.sigma(1..5) { |i| i * 2 }
24
+
25
+ result.should == (1 * 2) + (2 * 2) + (3 * 2) + (4 * 2) + (5 * 2)
26
+ end
27
+ end
28
+
29
+ describe "pi" do
30
+ it "should return 24 for pi(1..4)" do
31
+ subject.pi(1..4).should == 24
32
+ end
33
+
34
+ it "should return 30 for pi(5..6)" do
35
+ subject.pi(5..6).should == 30
36
+ end
37
+
38
+ it "should take an optional block argument" do
39
+ result = subject.pi(1..3) { |i| i * 2 }
40
+
41
+ result.should == (1 * 2) * (2 * 2) * (3 * 2)
42
+ end
43
+ end
44
+
45
+ describe "factorial" do
46
+ it "should return 1 for factorial(0)" do
47
+ subject.factorial(0).should == 1
48
+ end
49
+
50
+ it "should return 1 for factorial(1)" do
51
+ subject.factorial(1).should == 1
52
+ end
53
+
54
+ it "should return 2 for factorial(2)" do
55
+ subject.factorial(2).should == 2
56
+ end
57
+
58
+ it "should return 6 for factorial(3)" do
59
+ subject.factorial(3).should == 6
60
+ end
61
+
62
+ it "should return 3628800 for factorial(10)" do
63
+ subject.factorial(10).should == 3628800
64
+ end
65
+
66
+ it "should raise RangeError for factorial(-1)" do
67
+ lambda { subject.factorial(-1) }.should raise_error(RangeError)
68
+ end
69
+ end
70
+
71
+ describe "subfactorial" do
72
+ it "should return 1 for subfactorial(0)" do
73
+ subject.subfactorial(0).should == 1
74
+ end
75
+
76
+ it "should return 0 for subfactorial(1)" do
77
+ subject.subfactorial(1).should == 0
78
+ end
79
+
80
+ it "should return 1 for subfactorial(2)" do
81
+ subject.subfactorial(2).should == 1
82
+ end
83
+
84
+ it "should return 2 for subfactorial(3)" do
85
+ subject.subfactorial(3).should == 2
86
+ end
87
+
88
+ it "should return 9 for subfactorial(4)" do
89
+ subject.subfactorial(4).should == 9
90
+ end
91
+
92
+ it "should return 44 for subfactorial(5)" do
93
+ subject.subfactorial(5).should == 44
94
+ end
95
+
96
+ it "should raise RangeError for subfactorial(-1)" do
97
+ lambda { subject.subfactorial(-1) }.should raise_error(RangeError)
98
+ end
99
+ end
100
+ end
@@ -7,7 +7,7 @@ describe Range do
7
7
  ((100..200) & (150..200)).first.should == 150
8
8
  end
9
9
 
10
- it "should pick the mimum ending value" do
10
+ it "should pick the minimum ending value" do
11
11
  ((100..150) & (100..200)).last.should == 150
12
12
  end
13
13
  end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ require 'permute/mixin_examples'
3
+
4
+ require 'combinatorics/permute/extensions/array'
5
+
6
+ describe Array do
7
+ subject { Array }
8
+
9
+ it_should_behave_like "Permute::Mixin"
10
+ end
@@ -0,0 +1,146 @@
1
+ require 'spec_helper'
2
+ require 'combinatorics/permute'
3
+
4
+ describe Permute do
5
+ subject { Permute }
6
+
7
+ describe "cardinality" do
8
+ it "should raise RangeError if n is negative without passing r" do
9
+ lambda { subject.cardinality(-1) }.should raise_error(RangeError)
10
+ end
11
+
12
+ it "should raise RangeError if n is negative when r is provided" do
13
+ lambda { subject.cardinality(-1, 1) }.should raise_error(RangeError)
14
+ end
15
+
16
+ it "should raise RangeError if r is negative" do
17
+ lambda { subject.cardinality(1, -1) }.should raise_error(RangeError)
18
+ end
19
+
20
+ it "should raise RangeError if r is greater than n" do
21
+ lambda { subject.cardinality(2, 3) }.should raise_error(RangeError)
22
+ end
23
+
24
+ it "should return 1 for subject.cardinality(0)" do
25
+ subject.cardinality(0).should == 1
26
+ end
27
+
28
+ it "should return 1 for subject.cardinality(1)" do
29
+ subject.cardinality(1).should == 1
30
+ end
31
+
32
+ it "should return 2 for subject.cardinality(2)" do
33
+ subject.cardinality(2).should == 2
34
+ end
35
+
36
+ it "should return 6 for subject.cardinality(3)" do
37
+ subject.cardinality(3).should == 6
38
+ end
39
+
40
+ it "should return 24 for subject.cardinality(4)" do
41
+ subject.cardinality(4).should == 24
42
+ end
43
+
44
+ it "should return 0 for subject.cardinality(1, 0)" do
45
+ subject.cardinality(1, 0).should == 0
46
+ end
47
+
48
+ it "should return 1 for subject.cardinality(1, 1)" do
49
+ subject.cardinality(1, 1).should == 1
50
+ end
51
+
52
+ it "should return 2 for subject.cardinality(2, 1)" do
53
+ subject.cardinality(2, 1).should == 2
54
+ end
55
+
56
+ it "should return 1 for subject.cardinality(2, 2)" do
57
+ subject.cardinality(2, 2).should == 2
58
+ end
59
+
60
+ it "should return 3 for subject.cardinality(3, 1)" do
61
+ subject.cardinality(3, 1).should == 3
62
+ end
63
+
64
+ it "should return 3 for subject.cardinality(3, 2)" do
65
+ subject.cardinality(3, 2).should == 6
66
+ end
67
+
68
+ it "should return 1 for subject.cardinality(3, 3)" do
69
+ subject.cardinality(3, 3).should == 6
70
+ end
71
+
72
+ it "should return 4 for subject.cardinality(4, 1)" do
73
+ subject.cardinality(4, 1).should == 4
74
+ end
75
+
76
+ it "should return 12 for subject.cardinality(4, 2)" do
77
+ subject.cardinality(4, 2).should == 12
78
+ end
79
+
80
+ it "should return 24 for subject.cardinality(4, 3)" do
81
+ subject.cardinality(4, 3).should == 24
82
+ end
83
+
84
+ it "should return 1 for subject.cardinality(4, 4)" do
85
+ subject.cardinality(4, 4).should == 24
86
+ end
87
+
88
+ it "should return 360 for subject.cardinality(6, 4)" do
89
+ subject.cardinality(6, 4).should == 360
90
+ end
91
+
92
+ it "should return 3628800 for subject.cardinality(10)" do
93
+ subject.cardinality(10).should == 3628800
94
+ end
95
+ end
96
+
97
+ describe "cardinality_all" do
98
+ it "should return [] for cardinality_all(0)" do
99
+ subject.cardinality_all(0).should be_empty
100
+ end
101
+
102
+ it "should return [1] for cardinality_all(1)" do
103
+ subject.cardinality_all(1).should == [1]
104
+ end
105
+
106
+ it "should return [2, 1] for cardinality_all(2)" do
107
+ subject.cardinality_all(2).should == [2, 2]
108
+ end
109
+
110
+ it "should return [3, 6, 1] for cardinality_all(3)" do
111
+ subject.cardinality_all(3).should == [3, 6, 6]
112
+ end
113
+
114
+ it "should return [4, 12, 24, 1] for cardinality_all(4)" do
115
+ subject.cardinality_all(4).should == [4, 12, 24, 24]
116
+ end
117
+
118
+ it "should raise RangeError for cardinality_all(-1)" do
119
+ lambda { subject.cardinality_all(-1) }.should raise_error(RangeError)
120
+ end
121
+
122
+ it "should wrap cardinality with Permute.N" do
123
+ should respond_to(:N)
124
+ end
125
+
126
+ it "should wrap cardinalith with Permute.R" do
127
+ should respond_to(:R)
128
+ end
129
+
130
+ it "should wrap cardinality with Permute.NR" do
131
+ should respond_to(:NR)
132
+ end
133
+
134
+ it "should alias cardinality_all to N_all" do
135
+ should respond_to(:N_all)
136
+ end
137
+
138
+ it "should alias cardinality_all to NR_all" do
139
+ should respond_to(:NR_all)
140
+ end
141
+
142
+ it "should alias cardinality_all to R_all" do
143
+ should respond_to(:R_all)
144
+ end
145
+ end
146
+ end