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.
Files changed (60) hide show
  1. data/Gemfile +1 -0
  2. data/LICENSE.md +25 -0
  3. data/README.md +0 -0
  4. data/lib/gimuby.rb +10 -0
  5. data/lib/gimuby/config.rb +39 -0
  6. data/lib/gimuby/dependencies.rb +37 -0
  7. data/lib/gimuby/event/event.rb +29 -0
  8. data/lib/gimuby/event/event_manager.rb +34 -0
  9. data/lib/gimuby/factory.rb +275 -0
  10. data/lib/gimuby/genetic/archipelago/archipelago.rb +305 -0
  11. data/lib/gimuby/genetic/archipelago/connect_strategy/barabasi_albert_connect_strategy.rb +77 -0
  12. data/lib/gimuby/genetic/archipelago/connect_strategy/circle_connect_strategy.rb +11 -0
  13. data/lib/gimuby/genetic/archipelago/connect_strategy/connect_strategy.rb +34 -0
  14. data/lib/gimuby/genetic/archipelago/connect_strategy/constant_degree_connect_strategy.rb +22 -0
  15. data/lib/gimuby/genetic/archipelago/connect_strategy/fully_connected_connect_strategy.rb +11 -0
  16. data/lib/gimuby/genetic/archipelago/connect_strategy/random_connect_strategy.rb +29 -0
  17. data/lib/gimuby/genetic/archipelago/connect_strategy/watts_strogatz_connect_strategy.rb +63 -0
  18. data/lib/gimuby/genetic/archipelago/measure/clustering_coefficient_measure.rb +92 -0
  19. data/lib/gimuby/genetic/archipelago/measure/connected_measure.rb +64 -0
  20. data/lib/gimuby/genetic/archipelago/measure/diameter_measure.rb +38 -0
  21. data/lib/gimuby/genetic/archipelago/measure/measure.rb +7 -0
  22. data/lib/gimuby/genetic/archipelago/measure/shortest_paths_measure.rb +46 -0
  23. data/lib/gimuby/genetic/population/pick_strategy/bests_pick_strategy.rb +17 -0
  24. data/lib/gimuby/genetic/population/pick_strategy/pick_strategy.rb +21 -0
  25. data/lib/gimuby/genetic/population/pick_strategy/random_wheel_pick_strategy.rb +40 -0
  26. data/lib/gimuby/genetic/population/pick_strategy/tournament_pick_strategy.rb +26 -0
  27. data/lib/gimuby/genetic/population/population.rb +97 -0
  28. data/lib/gimuby/genetic/population/replace_strategy/replace_strategy.rb +9 -0
  29. data/lib/gimuby/genetic/population/replace_strategy/replace_worst_replace_strategy.rb +52 -0
  30. data/lib/gimuby/genetic/population/replace_strategy/uniform_replace_strategy.rb +48 -0
  31. data/lib/gimuby/genetic/solution/check_strategy/check_strategy.rb +8 -0
  32. data/lib/gimuby/genetic/solution/check_strategy/permutation_check_strategy.rb +37 -0
  33. data/lib/gimuby/genetic/solution/check_strategy/solution_space_check_strategy.rb +74 -0
  34. data/lib/gimuby/genetic/solution/function_based_solution.rb +64 -0
  35. data/lib/gimuby/genetic/solution/mutation_strategy/mutation_strategy.rb +22 -0
  36. data/lib/gimuby/genetic/solution/mutation_strategy/permutation_mutation_strategy.rb +17 -0
  37. data/lib/gimuby/genetic/solution/mutation_strategy/solution_space_mutation_strategy.rb +69 -0
  38. data/lib/gimuby/genetic/solution/new_generation_strategy/average_new_generation_strategy.rb +41 -0
  39. data/lib/gimuby/genetic/solution/new_generation_strategy/combined_new_generation_strategy.rb +27 -0
  40. data/lib/gimuby/genetic/solution/new_generation_strategy/cross_over_new_generation_strategy.rb +40 -0
  41. data/lib/gimuby/genetic/solution/new_generation_strategy/new_generation_strategy.rb +9 -0
  42. data/lib/gimuby/genetic/solution/new_generation_strategy/parent_range_new_generation_strategy.rb +42 -0
  43. data/lib/gimuby/genetic/solution/solution.rb +86 -0
  44. data/lib/gimuby/problem/foxholes/foxholes.rb +76 -0
  45. data/lib/gimuby/problem/foxholes/foxholes_solution.rb +29 -0
  46. data/lib/gimuby/problem/lennard_jones/lennard_jones.rb +38 -0
  47. data/lib/gimuby/problem/lennard_jones/lennard_jones_solution.rb +62 -0
  48. data/lib/gimuby/problem/rastrigin/rastrigin.rb +26 -0
  49. data/lib/gimuby/problem/rastrigin/rastrigin_solution.rb +35 -0
  50. data/lib/gimuby/problem/rosenbrock/rosenbrock.rb +14 -0
  51. data/lib/gimuby/problem/rosenbrock/rosenbrock_solution.rb +39 -0
  52. data/lib/gimuby/problem/schaffer/schaffer.rb +18 -0
  53. data/lib/gimuby/problem/schaffer/schaffer_solution.rb +29 -0
  54. data/lib/gimuby/problem/sphere/sphere.rb +9 -0
  55. data/lib/gimuby/problem/sphere/sphere_solution.rb +27 -0
  56. data/lib/gimuby/problem/step/step.rb +9 -0
  57. data/lib/gimuby/problem/step/step_solution.rb +29 -0
  58. data/lib/gimuby/problem/tsp/tsp.rb +76 -0
  59. data/lib/gimuby/problem/tsp/tsp_solution.rb +46 -0
  60. 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
@@ -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
@@ -0,0 +1,9 @@
1
+
2
+ class NewGenerationStrategy
3
+
4
+ # Output an array of solution representations
5
+ def reproduce(solution1, solution2)
6
+ raise NotImplementedError
7
+ end
8
+
9
+ end
@@ -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