partitioner 0.1.0
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/.gitignore +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +25 -0
- data/README.md +21 -0
- data/lib/partitioner.rb +56 -0
- data/lib/partitioner/bucket.rb +7 -0
- data/partitioner.gemspec +23 -0
- data/spec/partitioner_spec.rb +61 -0
- metadata +108 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
partitioner (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.2)
|
10
|
+
rspec (2.5.0)
|
11
|
+
rspec-core (~> 2.5.0)
|
12
|
+
rspec-expectations (~> 2.5.0)
|
13
|
+
rspec-mocks (~> 2.5.0)
|
14
|
+
rspec-core (2.5.2)
|
15
|
+
rspec-expectations (2.5.0)
|
16
|
+
diff-lcs (~> 1.1.2)
|
17
|
+
rspec-mocks (2.5.0)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
bundler (>= 1.0.0)
|
24
|
+
partitioner!
|
25
|
+
rspec (>= 2.5.0)
|
data/README.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Partitioner
|
2
|
+
=============
|
3
|
+
|
4
|
+
The Partitioner can be used to evenly distribute sets of anything
|
5
|
+
with a numeric cost to into buckets.
|
6
|
+
|
7
|
+
Proposed usage and reason for existence is to distribute specs over
|
8
|
+
multiple machines.
|
9
|
+
|
10
|
+
Inputs
|
11
|
+
-------
|
12
|
+
|
13
|
+
At first, the knowledge base must be preseeded wih your data.
|
14
|
+
The datastructure is an Array, where each element is a bi-tupel of
|
15
|
+
|
16
|
+
[ Identifier, Costs ]
|
17
|
+
|
18
|
+
Examples
|
19
|
+
-------
|
20
|
+
|
21
|
+
See specs for examples
|
data/lib/partitioner.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'partitioner/bucket'
|
2
|
+
class Partitioner
|
3
|
+
attr_accessor :kb, :bucket_count
|
4
|
+
def initialize(bucket_count = nil)
|
5
|
+
@kb = {}
|
6
|
+
@bucket_count = bucket_count
|
7
|
+
@prepared = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def buckets
|
11
|
+
time_optimal_size! unless @bucket_count
|
12
|
+
fill_buckets unless @prepared
|
13
|
+
@buckets
|
14
|
+
end
|
15
|
+
alias subsets buckets
|
16
|
+
|
17
|
+
def smallest_bucket
|
18
|
+
cadidate = @buckets.detect(&:empty?)
|
19
|
+
candidate ||= @buckets.min {|a,b| a.value_sum <=> b.value_sum}
|
20
|
+
candidate
|
21
|
+
end
|
22
|
+
|
23
|
+
def biggest_bucket
|
24
|
+
@buckets.max {|a,b| a.value_sum <=> b.value_sum}
|
25
|
+
end
|
26
|
+
|
27
|
+
def fill_buckets
|
28
|
+
reset!
|
29
|
+
kb = @kb.dup
|
30
|
+
kb = kb.sort_by {|x| x.last}.reverse
|
31
|
+
|
32
|
+
while !kb.empty?
|
33
|
+
smallest_bucket << kb.shift
|
34
|
+
end
|
35
|
+
@prepared = true
|
36
|
+
end
|
37
|
+
|
38
|
+
def reset!
|
39
|
+
@buckets = Array.new(@bucket_count) { Bucket.new }
|
40
|
+
@prepared = false
|
41
|
+
end
|
42
|
+
|
43
|
+
# optimizes the bucketsize for time
|
44
|
+
# takes the longest critical path (biggest task)
|
45
|
+
# and calculates the amount of buckets of equal size
|
46
|
+
# needed that all other tasks can fit in them
|
47
|
+
def time_optimal_size
|
48
|
+
total_time = kb.inject(0){|a,b| a+b.last}
|
49
|
+
(total_time / kb.map(&:last).max.to_f).ceil
|
50
|
+
end
|
51
|
+
|
52
|
+
def time_optimal_size!
|
53
|
+
@bucket_count = time_optimal_size
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/partitioner.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "partitioner"
|
5
|
+
s.version = "0.1.0"
|
6
|
+
s.platform = Gem::Platform::RUBY
|
7
|
+
s.authors = []
|
8
|
+
s.email = []
|
9
|
+
s.homepage = "http://rubygems.org/gems/partitioner"
|
10
|
+
s.summary = "get all your tasks parallelized into even buckets."
|
11
|
+
s.description = "partitioner. solves the bin packing problem."
|
12
|
+
|
13
|
+
s.required_rubygems_version = ">= 1.3.6"
|
14
|
+
s.rubyforge_project = "partitioner"
|
15
|
+
|
16
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
17
|
+
s.add_development_dependency "rspec", ">= 2.5.0"
|
18
|
+
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
22
|
+
s.require_path = 'lib'
|
23
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'partitioner'
|
3
|
+
|
4
|
+
describe Partitioner do
|
5
|
+
|
6
|
+
def create_timings(array)
|
7
|
+
ret = []
|
8
|
+
array.each_with_index do |e,i|
|
9
|
+
ret << [i, e]
|
10
|
+
end
|
11
|
+
ret
|
12
|
+
end
|
13
|
+
|
14
|
+
before(:each) do
|
15
|
+
@partition = Partitioner.new(4)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be able to just fit in 1" do
|
19
|
+
@partition.kb = create_timings([1])
|
20
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include [1]
|
21
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include []
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should do the right thing with a 1..6 range" do
|
25
|
+
@partition.kb = create_timings([1,2,3,4,5,6])
|
26
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include [6]
|
27
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include [5]
|
28
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include [4,1]
|
29
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include [3,2]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should do the right thing with a 1..7 range" do
|
33
|
+
@partition.kb = create_timings([1,2,3,4,5,6,7])
|
34
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include [7]
|
35
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include [6,1]
|
36
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include [5,2]
|
37
|
+
@partition.subsets.map {|x| x.map(&:last)}.should include [4,3]
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "the optimization capability" do
|
41
|
+
describe "of time" do
|
42
|
+
describe "calculates the optimum for" do
|
43
|
+
|
44
|
+
it "a single element" do
|
45
|
+
@partition.kb = [[1,1]]
|
46
|
+
@partition.time_optimal_size.should == 1
|
47
|
+
end
|
48
|
+
|
49
|
+
it "an even kb" do
|
50
|
+
@partition.kb = create_timings([5,5,5,5])
|
51
|
+
@partition.time_optimal_size.should == 4
|
52
|
+
end
|
53
|
+
|
54
|
+
it "an extreme kb" do
|
55
|
+
@partition.kb = create_timings([5,1,1,1,1])
|
56
|
+
@partition.time_optimal_size.should == 2
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: partitioner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors: []
|
13
|
+
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-05-13 00:00:00 -07:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: bundler
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 23
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 0
|
33
|
+
- 0
|
34
|
+
version: 1.0.0
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 27
|
46
|
+
segments:
|
47
|
+
- 2
|
48
|
+
- 5
|
49
|
+
- 0
|
50
|
+
version: 2.5.0
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
description: partitioner. solves the bin packing problem.
|
54
|
+
email: []
|
55
|
+
|
56
|
+
executables: []
|
57
|
+
|
58
|
+
extensions: []
|
59
|
+
|
60
|
+
extra_rdoc_files: []
|
61
|
+
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- Gemfile
|
65
|
+
- Gemfile.lock
|
66
|
+
- README.md
|
67
|
+
- lib/partitioner.rb
|
68
|
+
- lib/partitioner/bucket.rb
|
69
|
+
- partitioner.gemspec
|
70
|
+
- spec/partitioner_spec.rb
|
71
|
+
has_rdoc: true
|
72
|
+
homepage: http://rubygems.org/gems/partitioner
|
73
|
+
licenses: []
|
74
|
+
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 23
|
95
|
+
segments:
|
96
|
+
- 1
|
97
|
+
- 3
|
98
|
+
- 6
|
99
|
+
version: 1.3.6
|
100
|
+
requirements: []
|
101
|
+
|
102
|
+
rubyforge_project: partitioner
|
103
|
+
rubygems_version: 1.3.7
|
104
|
+
signing_key:
|
105
|
+
specification_version: 3
|
106
|
+
summary: get all your tasks parallelized into even buckets.
|
107
|
+
test_files: []
|
108
|
+
|