combinatorics 0.4.3 → 0.4.4
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.
- checksums.yaml +7 -0
- data/.github/workflows/ruby.yml +28 -0
- data/.gitignore +4 -5
- data/ChangeLog.md +5 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +1 -1
- data/README.md +144 -105
- data/Rakefile +6 -30
- data/combinatorics.gemspec +1 -0
- data/gemspec.yml +7 -3
- data/lib/combinatorics/choose/cardinality.rb +1 -1
- data/lib/combinatorics/generator.rb +1 -1
- data/lib/combinatorics/version.rb +1 -1
- data/spec/cartesian_product/cardinality_spec.rb +13 -13
- data/spec/cartesian_product/mixin_examples.rb +14 -14
- data/spec/choose/cardinality_spec.rb +31 -31
- data/spec/choose/mixin_examples.rb +6 -6
- data/spec/combinatorics_spec.rb +1 -1
- data/spec/derange/mixin_examples.rb +6 -6
- data/spec/enumerator_spec.rb +1 -1
- data/spec/extensions/math_spec.rb +19 -19
- data/spec/extensions/range_spec.rb +12 -12
- data/spec/generator_spec.rb +1 -1
- data/spec/list_comprehension_spec.rb +10 -10
- data/spec/permute/cardinality_spec.rb +28 -28
- data/spec/permute/mixin_examples.rb +5 -5
- data/spec/power_set/mixin_examples.rb +4 -4
- data/spec/spec_helper.rb +0 -2
- metadata +26 -57
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e0761711a88421b7b0214a3b585b6a843401bd1e84bb189c87a0c4167d7e5f32
|
4
|
+
data.tar.gz: 6c42e53311328f5d0f6c27ea339c3539046fee352dfb548155d35183a19d5aef
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1d9df890fc1669969b84e48a0b3d6126111cc6e13369308f76c274e0227fcd475a9047872ef247dc83b009f4b5d234526aa9d88c0c59cff7c9129d080c93a044
|
7
|
+
data.tar.gz: 53eabbc7025dbaa9e79d8fe44c8d68c0182de3b575f425f6b4d0231c88920a8ee7b8c85bfd8f94743b8a618184525d0db5264d37232bd8793396b93afbfb1a0f
|
@@ -0,0 +1,28 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [ push, pull_request ]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
tests:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
fail-fast: false
|
10
|
+
matrix:
|
11
|
+
ruby:
|
12
|
+
- 2.6
|
13
|
+
- 2.7
|
14
|
+
- '3.0'
|
15
|
+
- 3.1
|
16
|
+
- jruby
|
17
|
+
- truffleruby
|
18
|
+
name: Ruby ${{ matrix.ruby }}
|
19
|
+
steps:
|
20
|
+
- uses: actions/checkout@v2
|
21
|
+
- name: Set up Ruby
|
22
|
+
uses: ruby/setup-ruby@v1
|
23
|
+
with:
|
24
|
+
ruby-version: ${{ matrix.ruby }}
|
25
|
+
- name: Install dependencies
|
26
|
+
run: bundle install --jobs 4 --retry 3
|
27
|
+
- name: Run tests
|
28
|
+
run: bundle exec rake test
|
data/.gitignore
CHANGED
data/ChangeLog.md
CHANGED
data/Gemfile
ADDED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
# Combinatorics
|
2
2
|
|
3
|
+
[](https://github.com/postmodern/combinatorics/actions/workflows/ruby.yml)
|
4
|
+
[](https://codeclimate.com/github/postmodern/combinatorics)
|
5
|
+
|
3
6
|
* [Source](https://github.com/postmodern/combinatorics)
|
4
7
|
* [Issues](https://github.com/postmodern/combinatorics/issues)
|
5
8
|
* [Documentation](http://rubydoc.info/gems/combinatorics)
|
6
|
-
* [Email](mailto:postmodern.mod3 at gmail.com)
|
7
9
|
|
8
10
|
## Description
|
9
11
|
|
10
12
|
A collection of modules and methods for performing
|
11
13
|
[Combinatoric](http://en.wikipedia.org/wiki/Combinatoric) calculations.
|
12
|
-
Methods are defined to compute power sets,
|
14
|
+
Methods are defined to compute power sets, Cartesian products, permutations,
|
13
15
|
combinations, and derangements.
|
14
16
|
|
15
17
|
Note: this includes k-combinations and k-permutations, i.e. only generating
|
@@ -22,134 +24,169 @@ never complete due to exponential computational complexity.)
|
|
22
24
|
|
23
25
|
## Features
|
24
26
|
|
25
|
-
* Adds Haskell/Python style list comprehensions via
|
27
|
+
* Adds Haskell/Python style list comprehensions via [Array#comprehension].
|
26
28
|
* Provides reusable Combinatorics Mixins:
|
27
|
-
*
|
28
|
-
*
|
29
|
-
*
|
30
|
-
*
|
31
|
-
*
|
32
|
-
* Adds Combinatorics
|
33
|
-
*
|
34
|
-
*
|
35
|
-
*
|
36
|
-
*
|
37
|
-
*
|
38
|
-
* Adds
|
39
|
-
*
|
40
|
-
*
|
41
|
-
*
|
42
|
-
*
|
43
|
-
*
|
44
|
-
*
|
45
|
-
*
|
29
|
+
* [Combinatorics::CartesianProduct]
|
30
|
+
* [Combinatorics::Choose]
|
31
|
+
* [Combinatorics::Derange]
|
32
|
+
* [Combinatorics::Permute]
|
33
|
+
* [Combinatorics::PowerSet]
|
34
|
+
* Adds Combinatorics core extension methods to {Array} and {Set}:
|
35
|
+
* [cartesian_product]
|
36
|
+
* [choose]
|
37
|
+
* [derange]
|
38
|
+
* [permute]
|
39
|
+
* [powerset]
|
40
|
+
* Adds additional core extension methods:
|
41
|
+
* [Range#&]
|
42
|
+
* [Range#upto]
|
43
|
+
* [Range#downto]
|
44
|
+
* [Math.sigma]
|
45
|
+
* [Math.pi]
|
46
|
+
* [Math.factorial]
|
47
|
+
* [Math.subfactorial]
|
48
|
+
|
49
|
+
[Array#comprehension]: https://rubydoc.info/gems/combinatorics/Array#comprehension-instance_method
|
50
|
+
[Combinatorics::CartesianProduct]: https://rubydoc.info/gems/combinatorics/Combinatorics/CartesianProduct
|
51
|
+
[Combinatorics::Choose]: https://rubydoc.info/gems/combinatorics/Combinatorics/Choose
|
52
|
+
[Combinatorics::Derange]: https://rubydoc.info/gems/combinatorics/Combinatorics/Derange
|
53
|
+
[Combinatorics::Permute]: https://rubydoc.info/gems/combinatorics/Combinatorics/Permute
|
54
|
+
[Combinatorics::PowerSet]: https://rubydoc.info/gems/combinatorics/Combinatorics/PowerSet
|
55
|
+
[cartesian_product]: https://rubydoc.info/gems/combinatorics/Combinatorics/CartesianProduct/Mixin#cartesian_product-instance_method
|
56
|
+
[choose]: https://rubydoc.info/gems/combinatorics/Combinatorics/Choose/Mixin#choose-instance_method
|
57
|
+
[derange]: https://rubydoc.info/gems/combinatorics/Combinatorics/Derange/Mixin#derange-instance_method
|
58
|
+
[permute]: https://rubydoc.info/gems/combinatorics/Combinatorics/Permute/Mixin#permute-instance_method
|
59
|
+
[powerset]: https://rubydoc.info/gems/combinatorics/Combinatorics/PowerSet/Mixin#powerset-instance_method
|
60
|
+
[Range#&]: https://rubydoc.info/gems/combinatorics/Range#&-instance_method
|
61
|
+
[Range#upto]: https://rubydoc.info/gems/combinatorics/Range#upto-instance_method
|
62
|
+
[Range#downto]: https://rubydoc.info/gems/combinatorics/Range#downto-instance_method
|
63
|
+
[Math.sigma]: https://rubydoc.info/gems/combinatorics/Math#sigma-class_method
|
64
|
+
[Math.pi]: https://rubydoc.info/gems/combinatorics/Math#pi-class_method
|
65
|
+
[Math.factorial]: https://rubydoc.info/gems/combinatorics/Math#factorial-class_method
|
66
|
+
[Math.subfactorial]: https://rubydoc.info/gems/combinatorics/Math#subfactorial-class_method
|
46
67
|
|
47
68
|
## Examples
|
48
69
|
|
49
70
|
Power-set:
|
50
71
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
72
|
+
```ruby
|
73
|
+
Set['ab', 'cd', 'ef'].powerset
|
74
|
+
# => [#<Set: {}>,
|
75
|
+
#<Set: {"ef"}>,
|
76
|
+
#<Set: {"cd"}>,
|
77
|
+
#<Set: {"cd", "ef"}>,
|
78
|
+
#<Set: {"ab"}>,
|
79
|
+
#<Set: {"ab", "ef"}>,
|
80
|
+
#<Set: {"ab", "cd"}>,
|
81
|
+
#<Set: {"ab", "cd", "ef"}>]
|
82
|
+
```
|
60
83
|
|
61
84
|
Cartesian products:
|
62
85
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
86
|
+
```ruby
|
87
|
+
require 'combinatorics/cartesian_product'
|
88
|
+
|
89
|
+
['a', 'b', 'c'].cartesian_product([0, 1, 2]).to_a
|
90
|
+
# => [["a", 0],
|
91
|
+
["b", 0],
|
92
|
+
["c", 0],
|
93
|
+
["a", 1],
|
94
|
+
["b", 1],
|
95
|
+
["c", 1],
|
96
|
+
["a", 2],
|
97
|
+
["b", 2],
|
98
|
+
["c", 2]]
|
99
|
+
```
|
75
100
|
|
76
101
|
k-combinations:
|
77
102
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
103
|
+
```ruby
|
104
|
+
require 'combinatorics/choose'
|
105
|
+
|
106
|
+
('a'..'f').to_a.choose(2).to_a
|
107
|
+
# => [["a", "b"],
|
108
|
+
["a", "c"],
|
109
|
+
["a", "d"],
|
110
|
+
["a", "e"],
|
111
|
+
["a", "f"],
|
112
|
+
["b", "c"],
|
113
|
+
["b", "d"],
|
114
|
+
["b", "e"],
|
115
|
+
["b", "f"],
|
116
|
+
["c", "d"],
|
117
|
+
["c", "e"],
|
118
|
+
["c", "f"],
|
119
|
+
["d", "e"],
|
120
|
+
["d", "f"],
|
121
|
+
["e", "f"]]
|
122
|
+
```
|
96
123
|
|
97
124
|
Derangements:
|
98
125
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
126
|
+
```ruby
|
127
|
+
require 'combinatorics/derange'
|
128
|
+
|
129
|
+
[:_, :q, :z, :x].derange.to_a
|
130
|
+
# => [[:q, :_, :x, :z],
|
131
|
+
[:q, :z, :x, :_],
|
132
|
+
[:q, :x, :_, :z],
|
133
|
+
[:z, :_, :x, :q],
|
134
|
+
[:z, :x, :_, :q],
|
135
|
+
[:z, :x, :q, :_],
|
136
|
+
[:x, :_, :q, :z],
|
137
|
+
[:x, :z, :_, :q],
|
138
|
+
[:x, :z, :q, :_]]
|
139
|
+
```
|
111
140
|
|
112
141
|
Permutation cardinality:
|
113
142
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
143
|
+
```ruby
|
144
|
+
require 'combinatorics/permutation'
|
145
|
+
|
146
|
+
Combinatorics::Permute.cardinality(128)
|
147
|
+
# => 8256
|
148
|
+
```
|
118
149
|
|
119
150
|
List comprehensions:
|
120
151
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
152
|
+
```ruby
|
153
|
+
require 'combinatorics/list_comprehension'
|
154
|
+
|
155
|
+
[(0..10).step(2),('a'..'c')].comprehension.to_a
|
156
|
+
# => [[0, "a"],
|
157
|
+
[0, "b"],
|
158
|
+
[0, "c"],
|
159
|
+
[2, "a"],
|
160
|
+
[2, "b"],
|
161
|
+
[2, "c"],
|
162
|
+
[4, "a"],
|
163
|
+
[4, "b"],
|
164
|
+
[4, "c"],
|
165
|
+
[6, "a"],
|
166
|
+
[6, "b"],
|
167
|
+
[6, "c"],
|
168
|
+
[8, "a"],
|
169
|
+
[8, "b"],
|
170
|
+
[8, "c"],
|
171
|
+
[10, "a"],
|
172
|
+
[10, "b"],
|
173
|
+
[10, "c"]]
|
174
|
+
```
|
142
175
|
|
143
176
|
Find the intersecting sub-range between two ranges:
|
144
177
|
|
145
|
-
|
146
|
-
|
178
|
+
```ruby
|
179
|
+
(1..50) & (20..100)
|
180
|
+
# => (20..50)
|
181
|
+
```
|
147
182
|
|
148
183
|
Enumerate over every sub-range between two ranges:
|
149
184
|
|
150
|
-
|
151
|
-
|
152
|
-
|
185
|
+
```ruby
|
186
|
+
(1..5).upto(2..10).to_a
|
187
|
+
# => [1..5, 1..6, 1..7, 1..8, 1..9, 1..10,
|
188
|
+
2..5, 2..6, 2..7, 2..8, 2..9, 2..10]
|
189
|
+
```
|
153
190
|
|
154
191
|
## Requirements
|
155
192
|
|
@@ -157,10 +194,12 @@ Enumerate over every sub-range between two ranges:
|
|
157
194
|
|
158
195
|
## Install
|
159
196
|
|
160
|
-
|
197
|
+
```shell
|
198
|
+
$ gem install combinatorics
|
199
|
+
```
|
161
200
|
|
162
201
|
## Copyright
|
163
202
|
|
164
|
-
Copyright (c) 2010-
|
203
|
+
Copyright (c) 2010-2022 Hal Brodigan
|
165
204
|
|
166
205
|
See {file:LICENSE.txt} for license information.
|
data/Rakefile
CHANGED
@@ -1,39 +1,15 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'rake'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
require 'rubygems/tasks'
|
3
|
+
require 'rubygems/tasks'
|
4
|
+
Gem::Tasks.new
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
warn e.message
|
11
|
-
warn "Run `gem install rubygems-tasks` to install 'rubygems/tasks'."
|
12
|
-
end
|
13
|
-
|
14
|
-
begin
|
15
|
-
gem 'rspec', '~> 2.4'
|
16
|
-
require 'rspec/core/rake_task'
|
17
|
-
|
18
|
-
RSpec::Core::RakeTask.new
|
19
|
-
rescue LoadError => e
|
20
|
-
task :spec do
|
21
|
-
abort "Please run `gem install rspec` to install RSpec."
|
22
|
-
end
|
23
|
-
end
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
RSpec::Core::RakeTask.new
|
24
8
|
task :test => :spec
|
25
9
|
task :default => :spec
|
26
10
|
|
27
|
-
|
28
|
-
|
29
|
-
require 'yard'
|
30
|
-
|
31
|
-
YARD::Rake::YardocTask.new
|
32
|
-
rescue LoadError => e
|
33
|
-
task :yard do
|
34
|
-
abort "Please run `gem install yard` to install YARD."
|
35
|
-
end
|
36
|
-
end
|
11
|
+
require 'yard'
|
12
|
+
YARD::Rake::YardocTask.new
|
37
13
|
|
38
14
|
task :benchmark do
|
39
15
|
Dir.glob('benchmarks/*.rb') { |script| ruby(script) }
|
data/combinatorics.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.authors = Array(gemspec['authors'])
|
21
21
|
gem.email = gemspec['email']
|
22
22
|
gem.homepage = gemspec['homepage']
|
23
|
+
gem.metadata = gemspec['metadata'] if gemspec['metadata']
|
23
24
|
|
24
25
|
glob = lambda { |patterns| gem.files & Dir[*patterns] }
|
25
26
|
|
data/gemspec.yml
CHANGED
@@ -13,9 +13,13 @@ email:
|
|
13
13
|
homepage: https://github.com/postmodern/combinatorics#readme
|
14
14
|
has_yard: true
|
15
15
|
|
16
|
+
metadata:
|
17
|
+
documentation_uri: https://rubydoc.info/gems/combinatorics
|
18
|
+
source_code_uri: https://github.com/postmodern/combinatorics.rb
|
19
|
+
bug_tracker_uri: https://github.com/postmodern/combinatorics.rb/issues
|
20
|
+
changelog_uri: https://github.com/postmodern/combinatorics.rb/blob/master/ChangeLog.md
|
21
|
+
|
16
22
|
required_ruby_version: ">= 1.8.7"
|
17
23
|
|
18
24
|
development_dependencies:
|
19
|
-
|
20
|
-
rspec: ~> 2.4
|
21
|
-
yard: ~> 0.7
|
25
|
+
bundler: ~> 2.0
|
@@ -5,7 +5,7 @@ module Combinatorics
|
|
5
5
|
# auto-detects the `Generator` class.
|
6
6
|
Generator = if defined?(::Generator) # 1.8.7
|
7
7
|
::Generator
|
8
|
-
elsif defined?(::Enumerator::Generator) # 1.9
|
8
|
+
elsif defined?(::Enumerator::Generator) # >= 1.9.1
|
9
9
|
::Enumerator::Generator
|
10
10
|
else
|
11
11
|
raise(NameError,"unable to find the Generator class")
|
@@ -6,55 +6,55 @@ describe CartesianProduct do
|
|
6
6
|
|
7
7
|
describe "cardinality" do
|
8
8
|
it "should return 1 for cardinality(1, 1)" do
|
9
|
-
subject.cardinality(1, 1).
|
9
|
+
expect(subject.cardinality(1, 1)).to eq(1)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "should return 2 for cardinality(1, 2)" do
|
13
|
-
subject.cardinality(1, 2).
|
13
|
+
expect(subject.cardinality(1, 2)).to eq(2)
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should return 2 for cardinality(2, 1)" do
|
17
|
-
subject.cardinality(2, 1).
|
17
|
+
expect(subject.cardinality(2, 1)).to eq(2)
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should return 4 for cardinality(2, 2)" do
|
21
|
-
subject.cardinality(2, 2).
|
21
|
+
expect(subject.cardinality(2, 2)).to eq(4)
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should return 3 for cardinality(3, 1)" do
|
25
|
-
subject.cardinality(3, 1).
|
25
|
+
expect(subject.cardinality(3, 1)).to eq(3)
|
26
26
|
end
|
27
27
|
|
28
28
|
it "should return 3 for cardinality(1, 3)" do
|
29
|
-
subject.cardinality(1, 3).
|
29
|
+
expect(subject.cardinality(1, 3)).to eq(3)
|
30
30
|
end
|
31
31
|
|
32
32
|
it "should return 6 for cardinality(2, 3)" do
|
33
|
-
subject.cardinality(2, 3).
|
33
|
+
expect(subject.cardinality(2, 3)).to eq(6)
|
34
34
|
end
|
35
35
|
|
36
36
|
it "should return 6 for cardinality(3, 2)" do
|
37
|
-
subject.cardinality(3, 2).
|
37
|
+
expect(subject.cardinality(3, 2)).to eq(6)
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should return 9 for cardinality(3, 3)" do
|
41
|
-
subject.cardinality(3, 3).
|
41
|
+
expect(subject.cardinality(3, 3)).to eq(9)
|
42
42
|
end
|
43
43
|
|
44
44
|
it "should raise RangeError if c1 is negative" do
|
45
|
-
|
45
|
+
expect { subject.cardinality(-1, 1) }.to raise_error(RangeError)
|
46
46
|
end
|
47
47
|
|
48
48
|
it "should raise RangeError if c2 is negative" do
|
49
|
-
|
49
|
+
expect { subject.cardinality(1, -1) }.to raise_error(RangeError)
|
50
50
|
end
|
51
51
|
|
52
52
|
it "should raise RangeError if c1 is zero" do
|
53
|
-
|
53
|
+
expect { subject.cardinality(0, 1) }.to raise_error(RangeError)
|
54
54
|
end
|
55
55
|
|
56
56
|
it "should raise RangeError if c2 is zero" do
|
57
|
-
|
57
|
+
expect { subject.cardinality(1, 0) }.to raise_error(RangeError)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|