combinatorics 0.3.1 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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