gimuby 0.7.2
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/Gemfile +1 -0
- data/LICENSE.md +25 -0
- data/README.md +0 -0
- data/lib/gimuby.rb +10 -0
- data/lib/gimuby/config.rb +39 -0
- data/lib/gimuby/dependencies.rb +37 -0
- data/lib/gimuby/event/event.rb +29 -0
- data/lib/gimuby/event/event_manager.rb +34 -0
- data/lib/gimuby/factory.rb +275 -0
- data/lib/gimuby/genetic/archipelago/archipelago.rb +305 -0
- data/lib/gimuby/genetic/archipelago/connect_strategy/barabasi_albert_connect_strategy.rb +77 -0
- data/lib/gimuby/genetic/archipelago/connect_strategy/circle_connect_strategy.rb +11 -0
- data/lib/gimuby/genetic/archipelago/connect_strategy/connect_strategy.rb +34 -0
- data/lib/gimuby/genetic/archipelago/connect_strategy/constant_degree_connect_strategy.rb +22 -0
- data/lib/gimuby/genetic/archipelago/connect_strategy/fully_connected_connect_strategy.rb +11 -0
- data/lib/gimuby/genetic/archipelago/connect_strategy/random_connect_strategy.rb +29 -0
- data/lib/gimuby/genetic/archipelago/connect_strategy/watts_strogatz_connect_strategy.rb +63 -0
- data/lib/gimuby/genetic/archipelago/measure/clustering_coefficient_measure.rb +92 -0
- data/lib/gimuby/genetic/archipelago/measure/connected_measure.rb +64 -0
- data/lib/gimuby/genetic/archipelago/measure/diameter_measure.rb +38 -0
- data/lib/gimuby/genetic/archipelago/measure/measure.rb +7 -0
- data/lib/gimuby/genetic/archipelago/measure/shortest_paths_measure.rb +46 -0
- data/lib/gimuby/genetic/population/pick_strategy/bests_pick_strategy.rb +17 -0
- data/lib/gimuby/genetic/population/pick_strategy/pick_strategy.rb +21 -0
- data/lib/gimuby/genetic/population/pick_strategy/random_wheel_pick_strategy.rb +40 -0
- data/lib/gimuby/genetic/population/pick_strategy/tournament_pick_strategy.rb +26 -0
- data/lib/gimuby/genetic/population/population.rb +97 -0
- data/lib/gimuby/genetic/population/replace_strategy/replace_strategy.rb +9 -0
- data/lib/gimuby/genetic/population/replace_strategy/replace_worst_replace_strategy.rb +52 -0
- data/lib/gimuby/genetic/population/replace_strategy/uniform_replace_strategy.rb +48 -0
- data/lib/gimuby/genetic/solution/check_strategy/check_strategy.rb +8 -0
- data/lib/gimuby/genetic/solution/check_strategy/permutation_check_strategy.rb +37 -0
- data/lib/gimuby/genetic/solution/check_strategy/solution_space_check_strategy.rb +74 -0
- data/lib/gimuby/genetic/solution/function_based_solution.rb +64 -0
- data/lib/gimuby/genetic/solution/mutation_strategy/mutation_strategy.rb +22 -0
- data/lib/gimuby/genetic/solution/mutation_strategy/permutation_mutation_strategy.rb +17 -0
- data/lib/gimuby/genetic/solution/mutation_strategy/solution_space_mutation_strategy.rb +69 -0
- data/lib/gimuby/genetic/solution/new_generation_strategy/average_new_generation_strategy.rb +41 -0
- data/lib/gimuby/genetic/solution/new_generation_strategy/combined_new_generation_strategy.rb +27 -0
- data/lib/gimuby/genetic/solution/new_generation_strategy/cross_over_new_generation_strategy.rb +40 -0
- data/lib/gimuby/genetic/solution/new_generation_strategy/new_generation_strategy.rb +9 -0
- data/lib/gimuby/genetic/solution/new_generation_strategy/parent_range_new_generation_strategy.rb +42 -0
- data/lib/gimuby/genetic/solution/solution.rb +86 -0
- data/lib/gimuby/problem/foxholes/foxholes.rb +76 -0
- data/lib/gimuby/problem/foxholes/foxholes_solution.rb +29 -0
- data/lib/gimuby/problem/lennard_jones/lennard_jones.rb +38 -0
- data/lib/gimuby/problem/lennard_jones/lennard_jones_solution.rb +62 -0
- data/lib/gimuby/problem/rastrigin/rastrigin.rb +26 -0
- data/lib/gimuby/problem/rastrigin/rastrigin_solution.rb +35 -0
- data/lib/gimuby/problem/rosenbrock/rosenbrock.rb +14 -0
- data/lib/gimuby/problem/rosenbrock/rosenbrock_solution.rb +39 -0
- data/lib/gimuby/problem/schaffer/schaffer.rb +18 -0
- data/lib/gimuby/problem/schaffer/schaffer_solution.rb +29 -0
- data/lib/gimuby/problem/sphere/sphere.rb +9 -0
- data/lib/gimuby/problem/sphere/sphere_solution.rb +27 -0
- data/lib/gimuby/problem/step/step.rb +9 -0
- data/lib/gimuby/problem/step/step_solution.rb +29 -0
- data/lib/gimuby/problem/tsp/tsp.rb +76 -0
- data/lib/gimuby/problem/tsp/tsp_solution.rb +46 -0
- metadata +128 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'gimuby/genetic/solution/new_generation_strategy/new_generation_strategy'
|
2
|
+
|
3
|
+
class AverageNewGenerationStrategy < NewGenerationStrategy
|
4
|
+
|
5
|
+
# @param best_weight {Float} The weight given to the best solution
|
6
|
+
def initialize(best_weight = 1.0)
|
7
|
+
@best_weight = best_weight
|
8
|
+
end
|
9
|
+
|
10
|
+
def reproduce(solution1, solution2)
|
11
|
+
weight1 = 1.0
|
12
|
+
weight2 = 1.0
|
13
|
+
if solution1.get_fitness < solution2.get_fitness
|
14
|
+
weight1 = @best_weight
|
15
|
+
else
|
16
|
+
weight2 = @best_weight
|
17
|
+
end
|
18
|
+
x_values1 = solution1.get_solution_representation
|
19
|
+
x_values2 = solution2.get_solution_representation
|
20
|
+
reproduce_from_representation(x_values1, x_values2, weight1, weight2)
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def reproduce_from_representation(x_values1, x_values2, weight1, weight2)
|
26
|
+
x_values = []
|
27
|
+
x_values1.each_index do |i|
|
28
|
+
x_value1 = x_values1[i]
|
29
|
+
x_value2 = x_values2[i]
|
30
|
+
if x_value1.class == Array
|
31
|
+
x_value = reproduce_from_representation(x_value1, x_value2, weight1, weight2).pop()
|
32
|
+
else
|
33
|
+
x_value = x_value1 * weight1 + x_value2 * weight2
|
34
|
+
x_value /= (weight1 + weight2)
|
35
|
+
end
|
36
|
+
x_values.push(x_value)
|
37
|
+
end
|
38
|
+
[x_values]
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'gimuby/genetic/solution/new_generation_strategy/new_generation_strategy'
|
2
|
+
|
3
|
+
# This class pick randomly between strategies to implement more
|
4
|
+
# mitigated new generation strategy
|
5
|
+
class CombinedNewGenerationStrategy < NewGenerationStrategy
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@strategies = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def reproduce(solution1, solution2)
|
12
|
+
strategy = get_concrete_strategy
|
13
|
+
strategy.reproduce(solution1, solution2)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Add a strategy in the handled strategy of the system
|
17
|
+
# @param strategy {NewGenerationStrategy}
|
18
|
+
def add_strategy(strategy)
|
19
|
+
@strategies.push(strategy)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def get_concrete_strategy
|
25
|
+
@strategies.choice
|
26
|
+
end
|
27
|
+
end
|
data/lib/gimuby/genetic/solution/new_generation_strategy/cross_over_new_generation_strategy.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'gimuby/genetic/solution/new_generation_strategy/new_generation_strategy'
|
2
|
+
|
3
|
+
class CrossOverNewGenerationStrategy < NewGenerationStrategy
|
4
|
+
|
5
|
+
def initialize(cross_overs_number = 1)
|
6
|
+
@cross_overs_number = cross_overs_number
|
7
|
+
end
|
8
|
+
|
9
|
+
def reproduce(solution1, solution2)
|
10
|
+
permutation1 = solution1.get_solution_representation
|
11
|
+
permutation2 = solution2.get_solution_representation
|
12
|
+
cross_overs_number = @cross_overs_number
|
13
|
+
if cross_overs_number <= 0
|
14
|
+
cross_overs_number = permutation1.length - cross_overs_number
|
15
|
+
end
|
16
|
+
cross_overs_number.times do |_|
|
17
|
+
r = reproduce_step(permutation1, permutation2)
|
18
|
+
permutation1 = r.shift
|
19
|
+
permutation2 = r.shift
|
20
|
+
end
|
21
|
+
[permutation1, permutation2]
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def reproduce_step(permutation1, permutation2)
|
27
|
+
random_index = rand(permutation1.length)
|
28
|
+
if random_index == permutation1.length - 1
|
29
|
+
new_permutation1 = permutation1.clone()
|
30
|
+
new_permutation2 = permutation2.clone()
|
31
|
+
else
|
32
|
+
new_permutation1 = permutation1[0..random_index] +
|
33
|
+
permutation2[random_index + 1..-1]
|
34
|
+
new_permutation2 = permutation2[0..random_index] +
|
35
|
+
permutation1[random_index + 1..-1]
|
36
|
+
end
|
37
|
+
[new_permutation1, new_permutation2]
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/gimuby/genetic/solution/new_generation_strategy/parent_range_new_generation_strategy.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'gimuby/genetic/solution/new_generation_strategy/new_generation_strategy'
|
2
|
+
|
3
|
+
|
4
|
+
class ParentRangeNewGenerationStrategy < NewGenerationStrategy
|
5
|
+
|
6
|
+
def initialize(widen_range_ratio = 1.10)
|
7
|
+
@widen_range_ratio = widen_range_ratio
|
8
|
+
end
|
9
|
+
|
10
|
+
def reproduce(solution1, solution2)
|
11
|
+
x_values1 = solution1.get_solution_representation
|
12
|
+
x_values2 = solution2.get_solution_representation
|
13
|
+
reproduce_from_representation(x_values1, x_values2)
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def reproduce_from_representation(x_values1, x_values2)
|
19
|
+
new_values = []
|
20
|
+
x_values1.each_index do |i|
|
21
|
+
x_value1 = x_values1[i]
|
22
|
+
x_value2 = x_values2[i]
|
23
|
+
if x_value1.class == Array
|
24
|
+
new_x_value = reproduce_from_representation(x_value1, x_value2).pop
|
25
|
+
else
|
26
|
+
new_x_value = rand_in([x_value1, x_value2])
|
27
|
+
end
|
28
|
+
new_values.push(new_x_value)
|
29
|
+
end
|
30
|
+
[new_values]
|
31
|
+
end
|
32
|
+
|
33
|
+
def rand_in(values)
|
34
|
+
min = values.min
|
35
|
+
max = values.max
|
36
|
+
range = max - min
|
37
|
+
delta_range = range * @widen_range_ratio
|
38
|
+
range += delta_range
|
39
|
+
(rand() * range) + (min - delta_range / 2)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'gimuby/config'
|
3
|
+
require 'gimuby/dependencies'
|
4
|
+
|
5
|
+
# Base class for solutions, extended by each given problem
|
6
|
+
class Solution
|
7
|
+
|
8
|
+
def initialize(representation = nil)
|
9
|
+
@fitness = nil
|
10
|
+
|
11
|
+
@check_strategy ||= nil
|
12
|
+
@new_generation_strategy ||= nil
|
13
|
+
@mutation_strategy ||= nil
|
14
|
+
|
15
|
+
if representation.nil?
|
16
|
+
init_representation
|
17
|
+
else
|
18
|
+
set_solution_representation(representation)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_accessor :check_strategy
|
23
|
+
attr_accessor :new_generation_strategy
|
24
|
+
attr_accessor :mutation_strategy
|
25
|
+
|
26
|
+
# @return [Float]
|
27
|
+
def get_fitness
|
28
|
+
unless has_fitness?
|
29
|
+
@fitness = evaluate
|
30
|
+
event_data = {:solution => self}
|
31
|
+
get_event_manager.trigger_event(:on_solution_needs_evaluation, event_data)
|
32
|
+
end
|
33
|
+
@fitness
|
34
|
+
end
|
35
|
+
|
36
|
+
def reset_fitness_state
|
37
|
+
@fitness = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def mutate
|
41
|
+
@mutation_strategy.mutate(self)
|
42
|
+
end
|
43
|
+
|
44
|
+
def reproduce(sol1, sol2)
|
45
|
+
new_solutions_representations = @new_generation_strategy.reproduce(sol1, sol2)
|
46
|
+
new_solutions_representations.map do |representation|
|
47
|
+
solution = self.class.new(representation)
|
48
|
+
solution.check
|
49
|
+
solution.mutation_strategy = sol1.mutation_strategy
|
50
|
+
solution.check_strategy = sol1.check_strategy
|
51
|
+
solution.new_generation_strategy = sol1.new_generation_strategy
|
52
|
+
solution
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def get_solution_representation
|
57
|
+
raise NotImplementedError
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_solution_representation(representation)
|
61
|
+
raise NotImplementedError
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
|
66
|
+
def init_representation
|
67
|
+
raise NotImplementedError
|
68
|
+
end
|
69
|
+
|
70
|
+
def has_fitness?
|
71
|
+
not @fitness.nil?
|
72
|
+
end
|
73
|
+
|
74
|
+
def evaluate
|
75
|
+
raise NotImplementedError
|
76
|
+
end
|
77
|
+
|
78
|
+
def check
|
79
|
+
checked_representation = @check_strategy.check(get_solution_representation)
|
80
|
+
set_solution_representation(checked_representation)
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_event_manager
|
84
|
+
$dependencies.event_manager
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'gimuby/config'
|
2
|
+
|
3
|
+
# Implementation according to
|
4
|
+
# http://www.sfu.ca/~ssurjano/shekel.html
|
5
|
+
# http://www.zsd.ict.pwr.wroc.pl/files/docs/functions.pdf
|
6
|
+
#
|
7
|
+
class Foxholes
|
8
|
+
|
9
|
+
@@x_value_min = -65536
|
10
|
+
@@x_value_max = 65536
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
ensure_holes_coordinates
|
14
|
+
end
|
15
|
+
|
16
|
+
def evaluate(x_values)
|
17
|
+
sum = 0.0
|
18
|
+
get_number_holes.times do |j|
|
19
|
+
hole_coordinate = @holes_coordinates[j]
|
20
|
+
sub_sum = 0.10
|
21
|
+
hole_coordinate.each_index do |i|
|
22
|
+
sub_sum += (x_values[i].to_f - hole_coordinate[i]) ** 2
|
23
|
+
end
|
24
|
+
sum += 1.0 / sub_sum
|
25
|
+
end
|
26
|
+
sum
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def get_number_holes
|
32
|
+
25
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_holes_coordinates
|
36
|
+
@holes_coordinates
|
37
|
+
end
|
38
|
+
|
39
|
+
def ensure_holes_coordinates
|
40
|
+
path = $config.persistence_dir_path + '/foxholes_holes_coordinates_' +
|
41
|
+
get_number_holes.to_s + '.data'
|
42
|
+
load_holes_coordinates(path)
|
43
|
+
if @holes_coordinates.nil?
|
44
|
+
init_holes_coordinates
|
45
|
+
persist_holes_coordinates(path)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_holes_coordinates(path)
|
50
|
+
if File::exists? path
|
51
|
+
f = File.new(path, 'r')
|
52
|
+
@holes_coordinates = Marshal.load(f.read())
|
53
|
+
f.close()
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def persist_holes_coordinates(path)
|
58
|
+
f = File.new(path, 'w')
|
59
|
+
f.write(Marshal.dump(@holes_coordinates))
|
60
|
+
f.close()
|
61
|
+
end
|
62
|
+
|
63
|
+
def init_holes_coordinates
|
64
|
+
@holes_coordinates = []
|
65
|
+
get_number_holes.times do |_|
|
66
|
+
@holes_coordinates.push(get_random_coordinates)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_random_coordinates
|
71
|
+
scale = @@x_value_max - @@x_value_min
|
72
|
+
x = rand() * scale + @@x_value_min
|
73
|
+
y = rand() * scale + @@x_value_min
|
74
|
+
[x, y]
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'gimuby/dependencies'
|
2
|
+
require 'gimuby/config'
|
3
|
+
require 'gimuby/genetic/solution/function_based_solution'
|
4
|
+
|
5
|
+
class FoxholesSolution < FunctionBasedSolution
|
6
|
+
|
7
|
+
def evaluate
|
8
|
+
get_foxholes.evaluate(@x_values.clone)
|
9
|
+
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def get_x_value_min
|
14
|
+
-65536
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_x_value_max
|
18
|
+
65536
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_dimension_number
|
22
|
+
2
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_foxholes
|
26
|
+
# load through dependency
|
27
|
+
$dependencies.foxholes
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class LennardJones
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@sigma = 1
|
7
|
+
end
|
8
|
+
|
9
|
+
# @param atoms_positions {Array}
|
10
|
+
def evaluate(atoms_positions)
|
11
|
+
number = atoms_positions.length
|
12
|
+
potential = 0.0
|
13
|
+
(number - 1).times do |i|
|
14
|
+
atom_position_i = atoms_positions[i]
|
15
|
+
target_indices = *(i+1..number-1)
|
16
|
+
target_indices = [target_indices] unless target_indices.class == Array
|
17
|
+
target_indices.each do |j|
|
18
|
+
atom_position_j = atoms_positions[j]
|
19
|
+
distance = get_euclidian_distance(atom_position_i, atom_position_j)
|
20
|
+
if distance != 0
|
21
|
+
potential += (@sigma / distance) ** 12
|
22
|
+
potential -= (@sigma / distance) ** 6
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
potential * 4
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def get_euclidian_distance(atom_position1, atom_position2)
|
32
|
+
distance = 0.0
|
33
|
+
atom_position1.each_index do |k|
|
34
|
+
distance += (atom_position1[k] - atom_position2[k]) ** 2
|
35
|
+
end
|
36
|
+
Math.sqrt(distance)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'gimuby/config'
|
2
|
+
require 'gimuby/problem/lennard_jones/lennard_jones'
|
3
|
+
require 'gimuby/genetic/solution/solution'
|
4
|
+
|
5
|
+
class LennardJonesSolution < Solution
|
6
|
+
|
7
|
+
@@positions_dimensions = 3
|
8
|
+
@@position_dimension_min = -3.0
|
9
|
+
@@position_dimension_max = 3.0
|
10
|
+
|
11
|
+
def initialize(atoms_positions = nil)
|
12
|
+
super(atoms_positions)
|
13
|
+
|
14
|
+
@check_strategy = SolutionSpaceCheckStrategy.new
|
15
|
+
@check_strategy.set_min(@@position_dimension_min)
|
16
|
+
@check_strategy.set_max(@@position_dimension_max)
|
17
|
+
|
18
|
+
@new_generation_strategy = CombinedNewGenerationStrategy.new
|
19
|
+
@new_generation_strategy.add_strategy(ParentRangeNewGenerationStrategy.new)
|
20
|
+
@new_generation_strategy.add_strategy(CrossOverNewGenerationStrategy.new)
|
21
|
+
|
22
|
+
@mutation_strategy = SolutionSpaceMutationStrategy.new
|
23
|
+
@mutation_strategy.set_min(@@position_dimension_min)
|
24
|
+
@mutation_strategy.set_max(@@position_dimension_max)
|
25
|
+
end
|
26
|
+
|
27
|
+
def evaluate
|
28
|
+
get_lennard_jones.evaluate(get_solution_representation)
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_solution_representation
|
32
|
+
@atoms_positions.clone
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_solution_representation(atoms_positions)
|
36
|
+
@atoms_positions = atoms_positions.clone
|
37
|
+
#@atoms_positions = @atoms_positions.sort_by do |atom_position|
|
38
|
+
# atom_position[0]
|
39
|
+
#end
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def init_representation
|
45
|
+
@atoms_positions = []
|
46
|
+
atoms_number = $config.lennard_jones_atoms
|
47
|
+
atoms_number.times do
|
48
|
+
atom_position = []
|
49
|
+
@@positions_dimensions.times do
|
50
|
+
position_dimension_range = (@@position_dimension_max - @@position_dimension_min)
|
51
|
+
position_dimension = (rand * position_dimension_range) + @@position_dimension_min
|
52
|
+
atom_position.push(position_dimension)
|
53
|
+
end
|
54
|
+
@atoms_positions.push(atom_position)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_lennard_jones
|
59
|
+
LennardJones.new
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|