opt_alg_framework 1.0.3 → 1.0.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 +5 -13
- data/Gemfile +1 -0
- data/README.md +8 -26
- data/lib/opt_alg_framework.rb +13 -3
- data/lib/opt_alg_framework/algorithm/README.md +8 -0
- data/lib/opt_alg_framework/algorithm/algorithm_interface.rb +10 -0
- data/lib/opt_alg_framework/algorithm/local_search/hill_climbing.rb +10 -8
- data/lib/opt_alg_framework/algorithm/local_search/simulated_annealing.rb +11 -9
- data/lib/opt_alg_framework/algorithm/local_search/tabu_search.rb +16 -13
- data/lib/opt_alg_framework/operator/README.md +8 -0
- data/lib/opt_alg_framework/operator/crossover/crossover_interface.rb +10 -0
- data/lib/opt_alg_framework/operator/crossover/permutation/two_point_crossover.rb +3 -2
- data/lib/opt_alg_framework/operator/selector/selector_interface.rb +10 -0
- data/lib/opt_alg_framework/operator/selector/tournament_selection.rb +2 -2
- data/lib/opt_alg_framework/operator/tweak/random_swap.rb +2 -3
- data/lib/opt_alg_framework/operator/tweak/tweak_interface.rb +10 -0
- data/lib/opt_alg_framework/problem/README.md +12 -6
- data/lib/opt_alg_framework/problem/fsp.rb +58 -54
- data/lib/opt_alg_framework/problem/problem_interface.rb +10 -0
- data/lib/opt_alg_framework/version.rb +1 -1
- data/opt_alg_framework.gemspec +4 -3
- metadata +38 -17
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZmUwM2I2ZjM1YjBhNzY0YjBlOTNmYWVhM2JlY2Q5YTkyOTcwMGY1NA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e5238e0506bf85414aee3fb138a49038c83ebb2d
|
4
|
+
data.tar.gz: e0f07c319a8d4f8e8bac291f1a9f73862153d370
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
Y2NlNmRiYzdlNWIxYTc1MDBiMWEzODNmNzljYmU2Nzc1NDAwNTkwNWE4YTk1
|
11
|
-
MTE3ODY4YmQwYWJiM2NjMzc0OGJmYThmZTUyMDdmMzNlNmQ0NmI=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
MDcwNmEzZDQ2NDFlN2NlMGFkMTAxYTllMDdlYjYzOWRiODU5MjY5MGEyM2Jh
|
14
|
-
NDAzZWZjYTQxZThhN2Y3YWIyNmQwMmNmOThmZWU5ODUzNDEzYWE0ODRmNTM1
|
15
|
-
NDQ0MzhlNGJkMDc4OTE1OTAyZjBlNWRmM2IwYTI1MmY0NjI1NmM=
|
6
|
+
metadata.gz: 1f4296bb2cc65002a2e1409c674f76e249790c316d61c91ef214e83b18b4658ea82cadb22548f22816c7c779d7ee1fae38e401ec0ea2fe86e598149ade080b9b
|
7
|
+
data.tar.gz: 9551a80e24e9967b52f44490d9d4c8a95236ed955f5acea96d53698d5d03bf94834bbe8dee8d8c5ac91e50185e97ce9e7e4e964ecf449ea58617e3dfec230b9f
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# opt-alg-framework (Optimization Algorithm Framework)
|
2
2
|
|
3
|
-
|
3
|
+
**opt-alg-framework** is a framework to work with and build optimization algorithm. The basic idea is: you will have a codificated problem with a method to calculate its fitness, an algorithm to improve this fitness and operators used with the algorithm to build new solutions.
|
4
4
|
|
5
5
|
What is already implemented:
|
6
6
|
|
@@ -31,7 +31,7 @@ gem 'opt_alg_framework'
|
|
31
31
|
|
32
32
|
And then execute:
|
33
33
|
|
34
|
-
$ bundle
|
34
|
+
$ bundle install
|
35
35
|
|
36
36
|
Or install it yourself as:
|
37
37
|
|
@@ -39,46 +39,28 @@ Or install it yourself as:
|
|
39
39
|
|
40
40
|
## Usage
|
41
41
|
|
42
|
-
Example:
|
42
|
+
Example: Read two instances of FSP problem (about the instances format, read README in *problem* directory!) and get its best results with SimulatedAnnealing algorithm, using RandomSwap operator.
|
43
43
|
|
44
44
|
```ruby
|
45
45
|
operator = Operator::Tweak::RandomSwap.new
|
46
46
|
problem = Problem::FSP.new
|
47
|
-
problem.load_schedule(path)
|
47
|
+
problem.load_schedule("path to instance file")
|
48
48
|
algorithm = Algorithm::LocalSearch::SimulatedAnnealing.new max_iterations: 10,
|
49
49
|
cooling_rate: 0.009,
|
50
50
|
problem: problem,
|
51
51
|
tweak_operator: operator
|
52
52
|
|
53
|
-
puts algorithm.start
|
53
|
+
puts algorithm.start # It will return a hash with the best solution found and its fitness
|
54
54
|
```
|
55
55
|
|
56
56
|
## Development
|
57
57
|
|
58
58
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` or, alternatively, `bundle console` for an interactive prompt that will allow you to experiment.
|
59
59
|
|
60
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
61
|
-
|
62
|
-
####Some conventions must be followed:
|
63
|
-
|
64
|
-
* All problem classes need to have its fitness method acessible with the name *fitness*;
|
65
|
-
* All swap operator classes need to have its swap method acessible with the name *tweak*;
|
66
|
-
* All crossover operator classes need to have its crossover method named *cross*;
|
67
|
-
* All selector operator classes need to have its selection method names *select*;
|
68
|
-
* All algorithm classes need to have its main method names *start*;
|
69
|
-
* In the algorithms, a solution is represent with a hash structure, and it's mandatory have at least the pair key-value *:solution* with the representation of the solution and *:fitness* with the fitness of the solution.
|
70
|
-
|
71
|
-
####TODO:
|
72
|
-
|
73
|
-
* Treatments to verify if the conventions are being followed;
|
74
|
-
* General implementations, like:
|
75
|
-
* Local search algorithms;
|
76
|
-
* Population based algorithms;
|
77
|
-
* Operators (crossover, swap, selector) to any type of problem (permutational, binary, etc);
|
78
|
-
* Different type of problems.
|
79
|
-
|
80
60
|
## Contributing
|
81
61
|
|
62
|
+
**This gem can deal with a lot of stuff, and everything must be simple to use (a.k.a *generic*). Before start to code, take a look in the README inside the folder of what you want to code (algorithms, problems, etc), some tips of what your class should have are there. Sugestions are welcome too! (;**
|
63
|
+
|
82
64
|
1. Fork it ( https://github.com/[my-github-username]/opt_alg_framework/fork )
|
83
65
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
84
66
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
data/lib/opt_alg_framework.rb
CHANGED
@@ -1,6 +1,16 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'opt_alg_framework/algorithm/algorithm_interface'
|
2
|
+
require 'opt_alg_framework/problem/problem_interface'
|
3
|
+
require 'opt_alg_framework/operator/tweak/tweak_interface'
|
4
|
+
require 'opt_alg_framework/operator/selector/selector_interface'
|
5
|
+
require 'opt_alg_framework/operator/crossover/crossover_interface'
|
6
|
+
|
7
|
+
Dir[File.dirname(__FILE__) + "/opt_alg_framework/problem/**/*.rb"].each { |f| require f }
|
8
|
+
Dir[File.dirname(__FILE__) + "/opt_alg_framework/operator/**/*.rb"].each { |f| require f }
|
9
|
+
Dir[File.dirname(__FILE__) + "/opt_alg_framework/algorithm/**/*.rb"].each { |f| require f }
|
10
|
+
|
11
|
+
#valid_files = Dir["#{File.dirname(__FILE__)}/**/*.rb"].reject {|f| File.directory?(f) }
|
12
|
+
#valid_files.each { |f| require f }
|
3
13
|
|
4
14
|
module OptAlgFramework
|
5
|
-
|
15
|
+
|
6
16
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Implementation Details
|
2
|
+
|
3
|
+
* Inside your class, use `implements AlgorithmInterface`. That provides an interface behavior, enforcing
|
4
|
+
the implementation of mandatory methods;
|
5
|
+
* Organize algorithm class inside modules (e.g., `HillClimbing` class);
|
6
|
+
* `initialize` have only a hash like argument, where the configurations used in algorithm are specifyied;
|
7
|
+
* A solution is represented like a hash, with at least `:solution` and `:fitness` keys. The best solution should be
|
8
|
+
returned by the main method.
|
@@ -1,34 +1,36 @@
|
|
1
1
|
module Algorithm
|
2
2
|
module LocalSearch
|
3
3
|
class HillClimbing
|
4
|
+
implements AlgorithmInterface
|
5
|
+
|
4
6
|
# Initialize passing a instantiated class of a problem and tweak operator
|
5
7
|
def initialize(params)
|
6
8
|
@tweak_operator = params[:tweak_operator]
|
7
9
|
@problem = params[:problem]
|
8
10
|
end
|
9
11
|
|
10
|
-
#
|
12
|
+
# solution_b = best solution
|
13
|
+
# solution_n = neighbor solution
|
11
14
|
def start
|
12
|
-
|
15
|
+
solution_b = encapsulate_solution(@problem.default_solution.shuffle)
|
13
16
|
while true do
|
14
|
-
|
15
|
-
if
|
16
|
-
|
17
|
+
solution_n = encapsulate_solution(@tweak_operator.tweak(solution_b[:solution]))
|
18
|
+
if solution_n[:fitness] < solution_b[:fitness]
|
19
|
+
solution_b = solution_n.dup
|
17
20
|
else
|
18
21
|
break
|
19
22
|
end
|
20
23
|
end
|
21
|
-
|
24
|
+
solution_b
|
22
25
|
end
|
23
26
|
|
24
27
|
# Solution is a hash, with the keys :solution and :fitness
|
25
28
|
def encapsulate_solution(solution)
|
26
29
|
hash = Hash.new
|
27
30
|
hash[:solution] = solution
|
28
|
-
hash[:fitness] = @problem.fitness(
|
31
|
+
hash[:fitness] = @problem.fitness(solution)
|
29
32
|
hash
|
30
33
|
end
|
31
|
-
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Algorithm
|
2
2
|
module LocalSearch
|
3
3
|
class SimulatedAnnealing
|
4
|
+
include AlgorithmInterface
|
4
5
|
include Math
|
5
|
-
attr_reader :temperature
|
6
6
|
|
7
7
|
# Initialize specifying the cooling rate percentage (@cooling_rate), number of iterations in each
|
8
8
|
# temperature (@max_iterations) and passing an instantiated problem and tweak operator class.
|
@@ -14,22 +14,24 @@ module Algorithm
|
|
14
14
|
@temperature = initial_temperature
|
15
15
|
end
|
16
16
|
|
17
|
-
#
|
17
|
+
# solution_b = best solution
|
18
|
+
# solution_n = neighbor solution
|
19
|
+
# solution_c = current solution
|
18
20
|
def start
|
19
|
-
|
20
|
-
|
21
|
+
solution_b = encapsulate_solution(@problem.default_solution.shuffle)
|
22
|
+
solution_c = solution_b.dup
|
21
23
|
temperature = @temperature
|
22
24
|
while temperature > 1 do
|
23
25
|
iteration = 1
|
24
26
|
while iteration < @max_iterations do
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
solution_n = encapsulate_solution(@tweak_operator.tweak(solution_c[:solution]))
|
28
|
+
solution_c = solution_n.dup if accept?(solution_c[:fitness], solution_n[:fitness], temperature)
|
29
|
+
solution_b = solution_c.dup if solution_c[:fitness] < solution_b[:fitness]
|
28
30
|
iteration += 1
|
29
31
|
end
|
30
32
|
temperature *= 1 - @cooling_rate
|
31
33
|
end
|
32
|
-
|
34
|
+
solution_b
|
33
35
|
end
|
34
36
|
|
35
37
|
private
|
@@ -50,7 +52,7 @@ module Algorithm
|
|
50
52
|
def encapsulate_solution(solution)
|
51
53
|
hash = Hash.new
|
52
54
|
hash[:solution] = solution
|
53
|
-
hash[:fitness] = @problem.fitness(
|
55
|
+
hash[:fitness] = @problem.fitness(solution)
|
54
56
|
hash
|
55
57
|
end
|
56
58
|
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module Algorithm
|
2
2
|
module LocalSearch
|
3
3
|
class TabuSearch
|
4
|
+
implements AlgorithmInterface
|
4
5
|
|
5
|
-
# Initialize specifying as parameters the tabu list size (@list_max_size), number of tweaks in each
|
6
|
+
# Initialize specifying as parameters the tabu list size (@list_max_size), number of tweaks in each
|
6
7
|
# current solution (@tweak_number), number of iteratiions to perform in the algorithm (@iterations)
|
7
8
|
# and an instantiated problem and tweak operator class.
|
8
9
|
def initialize(params)
|
@@ -16,30 +17,32 @@ module Algorithm
|
|
16
17
|
|
17
18
|
# Main method.
|
18
19
|
def start
|
19
|
-
|
20
|
-
|
21
|
-
@tabu_list <<
|
20
|
+
solution_c = encapsulate_solution(@problem.default_solution.dup)
|
21
|
+
solution_s = solution_c.dup
|
22
|
+
@tabu_list << solution_c[:solution]
|
22
23
|
@iterations.times do
|
23
24
|
@tabu_list.shift if @tabu_list.size == @list_max_size
|
24
|
-
|
25
|
+
solution_bn = solution_n1 = encapsulate_solution(@tweak_operator.tweak(solution_c[:solution]))
|
25
26
|
(@tweak_number - 1).times do
|
26
|
-
|
27
|
-
|
27
|
+
solution_n2 = encapsulate_solution(@tweak_operator.tweak(solution_c[:solution]))
|
28
|
+
solution_bn = solution_n2.dup if !@tabu_list.include?(solution_n2) &&
|
29
|
+
solution_n2[:fitness] < solution_n1[:fitness] ||
|
30
|
+
@tabu_list.include?(solution_n1[:solution])
|
28
31
|
end
|
29
|
-
if !@tabu_list.include?(
|
30
|
-
|
31
|
-
@tabu_list <<
|
32
|
+
if !@tabu_list.include?(solution_bn[:solution])
|
33
|
+
solution_c = solution_bn.dup
|
34
|
+
@tabu_list << solution_n1
|
32
35
|
end
|
33
|
-
|
36
|
+
solution_s = solution_c.dup if solution_c[:fitness] < solution_s[:fitness]
|
34
37
|
end
|
35
|
-
|
38
|
+
solution_s
|
36
39
|
end
|
37
40
|
|
38
41
|
# A solution is a hash, with the keys :solution and :fitness.
|
39
42
|
def encapsulate_solution(solution)
|
40
43
|
hash = Hash.new
|
41
44
|
hash[:solution] = solution
|
42
|
-
hash[:fitness] = @problem.fitness(
|
45
|
+
hash[:fitness] = @problem.fitness(solution)
|
43
46
|
hash
|
44
47
|
end
|
45
48
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Implementation Details
|
2
|
+
|
3
|
+
* Inside your class, use `implements [interface class name]`. That provides an interface behavior, enforcing
|
4
|
+
the implementation of mandatory methods. Different operators, different interfaces, take a look inside the folder of your
|
5
|
+
type of operator and see what is being used (you can identify it looking for a file who name ends with `interface`);
|
6
|
+
* Organize algorithm class inside modules (e.g., `RandomSwap` class);
|
7
|
+
* `initialize` have no arguments.
|
8
|
+
|
@@ -1,8 +1,9 @@
|
|
1
1
|
module Operator
|
2
2
|
module Crossover
|
3
3
|
module Permutation
|
4
|
-
|
5
4
|
class TwoPointCrossover
|
5
|
+
implements CrossoverInterface
|
6
|
+
|
6
7
|
# Main method.
|
7
8
|
def cross(chromossome1, chromossome2)
|
8
9
|
point1 = Random.rand(0..chromossome1.size - 1)
|
@@ -27,7 +28,7 @@ module Operator
|
|
27
28
|
start_piece + middle_piece + end_piece
|
28
29
|
end
|
29
30
|
end
|
30
|
-
|
31
|
+
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
module Operator
|
2
2
|
module Selector
|
3
|
-
|
4
3
|
class TournamentSelection
|
4
|
+
implements SelectorInterface
|
5
|
+
|
5
6
|
# Initialize informing the tournament size.
|
6
7
|
def initialize(size)
|
7
8
|
@size = size
|
@@ -17,6 +18,5 @@ module Operator
|
|
17
18
|
best_individual
|
18
19
|
end
|
19
20
|
end
|
20
|
-
|
21
21
|
end
|
22
22
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Operator
|
2
2
|
module Tweak
|
3
|
-
|
4
3
|
class RandomSwap
|
5
|
-
|
4
|
+
implements TweakInterface
|
5
|
+
|
6
6
|
def tweak(solution)
|
7
7
|
copy = solution.dup
|
8
8
|
piece1 = Random.rand(0...copy.size)
|
@@ -13,6 +13,5 @@ module Operator
|
|
13
13
|
copy
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
17
16
|
end
|
18
17
|
end
|
@@ -1,7 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# Implementation Details
|
2
|
+
|
3
|
+
* Inside your class, use `implements ProblemInterface`. That provides an interface behavior, enforcing
|
4
|
+
the implementation of mandatory methods;
|
5
|
+
* Organize algorithm class inside modules (e.g., `FSP` class);
|
6
|
+
* `initialize` have no arguments;
|
7
|
+
* Make sure that you have `attr_reader :default_solution` in your class and fill this instance variable with an initial solution. This variable will be called inside algorithm classes.
|
8
|
+
|
9
|
+
# About the problem instances
|
2
10
|
|
3
11
|
## FSP (Flow Shop Permutation)
|
4
|
-
The instance of this kind of problem is a matrix, specifically a matrix where the rows are tasks and columns are machines.
|
12
|
+
The instance of this kind of problem is a matrix, specifically a matrix where the rows are tasks and columns are machines. This order need to be preserved to the fitness method work properly.
|
5
13
|
|
6
14
|
A valid instance example is shown bellow, with 5 tasks (lines) and 3 machines (columns):
|
7
15
|
|
@@ -11,10 +19,8 @@ A valid instance example is shown bellow, with 5 tasks (lines) and 3 machines (c
|
|
11
19
|
> 33 21 22 <br>
|
12
20
|
> 10 9 11 <br>
|
13
21
|
|
14
|
-
However, if your instance file is an inverted matrix (rows are machines and columns are tasks), just
|
22
|
+
However, if your instance file is an inverted matrix (rows are machines and columns are tasks), just pass *true* in a block to transpose the matrix.
|
15
23
|
|
16
24
|
```ruby
|
17
|
-
fsp.load_schedule(path_to_instance
|
25
|
+
fsp.load_schedule(path_to_instance) { true }
|
18
26
|
```
|
19
|
-
|
20
|
-
That will invert the matrix to the right format.
|
@@ -1,10 +1,13 @@
|
|
1
1
|
module Problem
|
2
|
-
|
2
|
+
#require 'opt_alg_framework/problem/problem_interface'
|
3
3
|
# FSP class have a inner class Schedule
|
4
4
|
class FSP
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
implements ProblemInterface
|
6
|
+
attr_reader :default_solution
|
7
|
+
|
8
|
+
# Inner class who represents the production schedule, that is, a matrix
|
9
|
+
# were the rows are the tasks and the columns the machines.
|
10
|
+
class Production
|
8
11
|
require 'matrix'
|
9
12
|
|
10
13
|
attr_reader :schedule
|
@@ -28,61 +31,62 @@ module Problem
|
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
31
|
-
|
34
|
+
# Initialize the FSP problem with a empty schedule
|
35
|
+
def initialize
|
36
|
+
@production = Production.new
|
37
|
+
end
|
32
38
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
39
|
+
# Load the production schedule from a file
|
40
|
+
def load_instance(path)
|
41
|
+
transpose = block_given? ? yield : false
|
42
|
+
@production.build_from_file(path, transpose)
|
43
|
+
@default_solution = (0...@production.schedule.row_size).to_a
|
44
|
+
end
|
38
45
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
46
|
+
def fitness(solution)
|
47
|
+
schedule = @production.reorder_schedule(solution)
|
48
|
+
makespan(schedule: schedule, task: schedule.row_size - 1,
|
49
|
+
machine: schedule.column_size - 1, memory: {})
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def bigger(num1 = 0, num2 = 0)
|
55
|
+
num1 ||= num2 ||= 0
|
56
|
+
if num1 > num2 ||= 0 then num1 else num2 end
|
57
|
+
end
|
58
|
+
|
59
|
+
# The hash options are:
|
60
|
+
# - schedule: matrix of the production schedule;
|
61
|
+
# - task: task index;
|
62
|
+
# - machine: machine index;
|
63
|
+
# - memory: store the total time spent at the point where the task index X is processed at the machine index Y
|
64
|
+
# (that avoid desnecessary recursive calls).
|
65
|
+
def makespan(options = {})
|
66
|
+
schedule = options[:schedule]
|
67
|
+
task = options[:task]
|
68
|
+
machine = options[:machine]
|
69
|
+
memory = options[:memory]
|
70
|
+
key = "#{task},#{machine}"
|
71
|
+
time = schedule[task, machine]
|
43
72
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
73
|
+
return time if task == 0 && machine == 0
|
74
|
+
|
75
|
+
if task > 0 # Before everithing, calculate the time spent in the tasks from N to 0
|
76
|
+
time_task_before = memory["#{task - 1},#{machine}"]
|
77
|
+
time_task_before = makespan(schedule: schedule, task: task - 1,
|
78
|
+
machine: machine, memory: memory) if memory["#{task - 1},#{machine}"].nil?
|
48
79
|
end
|
49
80
|
|
50
|
-
#
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
# - memory: store the total time spent at the point where the task index X is processed at the machine index Y
|
55
|
-
# (that avoid desnecessary recursive calls);
|
56
|
-
# - tasks_sequence: sequence of tasks used to reorganize the schedule after calculate its makespan.
|
57
|
-
# The default use of the method is: inform the tasks sequence as parameter and the method do all the work,
|
58
|
-
# returning the makespan as result.
|
59
|
-
def makespan(options = {}, block = @@bigger)
|
60
|
-
if options[:tasks_sequence]
|
61
|
-
schedule = @schedule.reorder_schedule(options[:tasks_sequence])
|
62
|
-
makespan({schedule: schedule, task: schedule.row_size - 1, machine: schedule.column_size - 1, memory: {}}, block)
|
63
|
-
else
|
64
|
-
schedule = options[:schedule]
|
65
|
-
task = options[:task]
|
66
|
-
machine = options[:machine]
|
67
|
-
memory = options[:memory]
|
68
|
-
key = "#{task},#{machine}"
|
69
|
-
time = schedule[task, machine]
|
70
|
-
if task == 0 && machine == 0
|
71
|
-
return time
|
72
|
-
end
|
73
|
-
if task > 0 # Before everithing, calculate the time spent in the tasks from N to 0
|
74
|
-
time_task_before = memory["#{task - 1},#{machine}"]
|
75
|
-
time_task_before = makespan({schedule: schedule, task: task - 1, machine: machine, memory: memory}, block) if memory["#{task - 1},#{machine}"].nil?
|
76
|
-
end
|
77
|
-
if machine > 0 # Calculate the time spent at the machines from N to 0
|
78
|
-
time_machine_before = memory["#{task},#{machine - 1}"]
|
79
|
-
time_machine_before = makespan({schedule: schedule, task: task, machine: machine - 1, memory: memory}, block) if memory["#{task},#{machine - 1}"].nil?
|
80
|
-
end
|
81
|
-
total_time = block.call(time_task_before, time_machine_before) + time # Calculate the total time
|
82
|
-
memory[key] = total_time # Store the total time
|
83
|
-
total_time
|
84
|
-
end
|
81
|
+
if machine > 0 # Calculate the time spent of the same task at the machines from N to 0
|
82
|
+
time_machine_before = memory["#{task},#{machine - 1}"]
|
83
|
+
time_machine_before = makespan(schedule: schedule, task: task,
|
84
|
+
machine: machine - 1, memory: memory) if memory["#{task},#{machine - 1}"].nil?
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
|
+
total_time = bigger(time_task_before, time_machine_before) + time # Calculate the total time
|
88
|
+
memory[key] = total_time # Store the total time
|
89
|
+
total_time
|
90
|
+
end
|
87
91
|
end
|
88
92
|
end
|
data/opt_alg_framework.gemspec
CHANGED
@@ -6,10 +6,10 @@ require 'opt_alg_framework/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "opt_alg_framework"
|
8
8
|
spec.version = OptAlgFramework::VERSION
|
9
|
-
spec.authors = ["
|
9
|
+
spec.authors = ["rwehresmann"]
|
10
10
|
spec.email = ["igoehresmann@gmail.com"]
|
11
11
|
|
12
|
-
spec.summary = %q{Gem with
|
12
|
+
spec.summary = %q{Gem with an optimization algorithm framework who implements problems, algorithms and operators classes.}
|
13
13
|
spec.homepage = "https://github.com/rodrigo-ehresmann/opt_alg_framework"
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
23
23
|
end
|
24
24
|
|
25
|
-
spec.add_development_dependency "bundler", "~> 1.
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
26
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
28
|
end
|
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opt_alg_framework
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- rwehresmann
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.13'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.13'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '10.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
41
55
|
description:
|
42
56
|
email:
|
43
57
|
- igoehresmann@gmail.com
|
@@ -45,9 +59,9 @@ executables: []
|
|
45
59
|
extensions: []
|
46
60
|
extra_rdoc_files: []
|
47
61
|
files:
|
48
|
-
- .gitignore
|
49
|
-
- .rspec
|
50
|
-
- .travis.yml
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
51
65
|
- Gemfile
|
52
66
|
- LICENSE.txt
|
53
67
|
- README.md
|
@@ -55,14 +69,21 @@ files:
|
|
55
69
|
- bin/console
|
56
70
|
- bin/setup
|
57
71
|
- lib/opt_alg_framework.rb
|
72
|
+
- lib/opt_alg_framework/algorithm/README.md
|
73
|
+
- lib/opt_alg_framework/algorithm/algorithm_interface.rb
|
58
74
|
- lib/opt_alg_framework/algorithm/local_search/hill_climbing.rb
|
59
75
|
- lib/opt_alg_framework/algorithm/local_search/simulated_annealing.rb
|
60
76
|
- lib/opt_alg_framework/algorithm/local_search/tabu_search.rb
|
77
|
+
- lib/opt_alg_framework/operator/README.md
|
78
|
+
- lib/opt_alg_framework/operator/crossover/crossover_interface.rb
|
61
79
|
- lib/opt_alg_framework/operator/crossover/permutation/two_point_crossover.rb
|
80
|
+
- lib/opt_alg_framework/operator/selector/selector_interface.rb
|
62
81
|
- lib/opt_alg_framework/operator/selector/tournament_selection.rb
|
63
82
|
- lib/opt_alg_framework/operator/tweak/random_swap.rb
|
83
|
+
- lib/opt_alg_framework/operator/tweak/tweak_interface.rb
|
64
84
|
- lib/opt_alg_framework/problem/README.md
|
65
85
|
- lib/opt_alg_framework/problem/fsp.rb
|
86
|
+
- lib/opt_alg_framework/problem/problem_interface.rb
|
66
87
|
- lib/opt_alg_framework/version.rb
|
67
88
|
- opt_alg_framework.gemspec
|
68
89
|
homepage: https://github.com/rodrigo-ehresmann/opt_alg_framework
|
@@ -76,19 +97,19 @@ require_paths:
|
|
76
97
|
- lib
|
77
98
|
required_ruby_version: !ruby/object:Gem::Requirement
|
78
99
|
requirements:
|
79
|
-
- -
|
100
|
+
- - ">="
|
80
101
|
- !ruby/object:Gem::Version
|
81
102
|
version: '0'
|
82
103
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
104
|
requirements:
|
84
|
-
- -
|
105
|
+
- - ">="
|
85
106
|
- !ruby/object:Gem::Version
|
86
107
|
version: '0'
|
87
108
|
requirements: []
|
88
109
|
rubyforge_project:
|
89
|
-
rubygems_version: 2.
|
110
|
+
rubygems_version: 2.5.1
|
90
111
|
signing_key:
|
91
112
|
specification_version: 4
|
92
|
-
summary: Gem with
|
93
|
-
and
|
113
|
+
summary: Gem with an optimization algorithm framework who implements problems, algorithms
|
114
|
+
and operators classes.
|
94
115
|
test_files: []
|