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,11 @@
1
+ require 'gimuby/genetic/archipelago/connect_strategy/connect_strategy'
2
+
3
+
4
+ class FullyConnectedConnectStrategy < ConnectStrategy
5
+
6
+ def connect(archipelago)
7
+ nodes = get_nodes(archipelago)
8
+ make_fully_connected(archipelago, nodes)
9
+ end
10
+
11
+ end
@@ -0,0 +1,29 @@
1
+ require 'gimuby/genetic/archipelago/connect_strategy/connect_strategy'
2
+
3
+
4
+ class RandomConnectStrategy < ConnectStrategy
5
+
6
+ def initialize
7
+ @average_degree = 4.0
8
+ end
9
+
10
+ attr_accessor :average_degree
11
+
12
+ def connect(archipelago)
13
+ nodes = get_nodes(archipelago)
14
+ connections_to_make = @average_degree * nodes.length
15
+ check_connections_to_make(connections_to_make, nodes)
16
+ made = 0
17
+ begin
18
+ from_node = nodes[rand(nodes.length)]
19
+ to_node = nodes[rand(nodes.length)]
20
+ has_edge = archipelago.has_edge(from_node, to_node)
21
+ if from_node != to_node || has_edge
22
+ archipelago.add_edge(from_node, to_node)
23
+ made += 1
24
+ end
25
+ end while made < connections_to_make
26
+ made
27
+ end
28
+
29
+ end
@@ -0,0 +1,63 @@
1
+ require 'gimuby/genetic/archipelago/connect_strategy/connect_strategy'
2
+
3
+ class WattsStrogatzConnectStrategy < ConnectStrategy
4
+
5
+ def initialize
6
+ @average_degree = 4.0
7
+ @rewire_rate = 0.2
8
+ end
9
+
10
+ attr_accessor :average_degree
11
+ attr_accessor :rewire_rate
12
+
13
+ def connect(archipelago)
14
+ make_regular_latice(archipelago)
15
+ rewire(archipelago)
16
+ end
17
+
18
+ protected
19
+
20
+ def make_regular_latice(archipelago)
21
+ depth = (@average_degree / 2).floor
22
+ depth.times do |i|
23
+ # create a circle
24
+ # then create a path with all second range neighbor
25
+ # until reaching depth
26
+ current_depth = i + 1
27
+ current_depth.times do |first_node_index|
28
+ # if depth = 2, there is two paths to build
29
+ # [0, 2, 4, ...] and [1, 3, 5, ...]
30
+ nodes = get_nodes(archipelago)
31
+ path = []
32
+ nodes.each_with_index do |key, node|
33
+ if (key % current_depth) == first_node_index
34
+ path.push(node)
35
+ end
36
+ end
37
+ archipelago.connect_path(path, TRUE)
38
+ end
39
+ end
40
+ end
41
+
42
+ def rewire(archipelago)
43
+ edges = get_edges_to_rewire(archipelago)
44
+ nodes = get_nodes(archipelago)
45
+ edges.each do |edge|
46
+ node1 = edge[0]
47
+ node2 = edge[1]
48
+ if node1 < node2 # we do not process the other case (undirected model)
49
+ should_rewire = @rewire_rate < rand()
50
+ if should_rewire
51
+ new_node = nodes.choice while archipelago.has_edge(node1, new_node)
52
+ archipelago.remove_edge(node1, node2)
53
+ archipelago.connect(node1, new_node)
54
+ end
55
+ end
56
+ end
57
+ end
58
+
59
+ def get_edges_to_rewire(archipelago)
60
+ archipelago.get_edges
61
+ end
62
+
63
+ end
@@ -0,0 +1,92 @@
1
+ require 'gimuby/genetic/archipelago/measure/measure'
2
+
3
+ # Compute the network average clustering coefficient as defined on
4
+ # http://en.wikipedia.org/wiki/Clustering_coefficient#Network_average_clustering_coefficient
5
+ # revision 19:31, 6 July 2013
6
+ #
7
+ # Beware if you update code, this class has a state don't break the
8
+ # workflow around the @potential_clusters member
9
+ class ClusteringCoefficientMeasure < Measure
10
+
11
+ # @param archipelago [Archipelago]
12
+ # @return [float] the clustering coefficient
13
+ def compute(archipelago)
14
+ local_clustering_coefficients = []
15
+ archipelago.get_nodes.each do |node|
16
+ local_clustering_coefficient = get_local_clustering_coefficient(archipelago, node)
17
+ local_clustering_coefficients.push(local_clustering_coefficient)
18
+ end
19
+ local_clustering_coefficients.inject(:+) / local_clustering_coefficients.length.to_f
20
+ end
21
+
22
+ private
23
+
24
+ def get_local_clustering_coefficient(archipelago, node)
25
+ init_local_computation_properties
26
+ potential_clusters_count = compute_potential_local_clusters(archipelago, node).length
27
+ clusters_count = compute_real_local_clusters(archipelago).length
28
+ if potential_clusters_count == 0
29
+ return 0
30
+ end
31
+ clusters_count.to_f / potential_clusters_count.to_f
32
+ end
33
+
34
+ def init_local_computation_properties
35
+ @potential_clusters = []
36
+ end
37
+
38
+ def compute_potential_local_clusters(archipelago, node)
39
+ neighbors = archipelago.get_neighbors(node)
40
+ neighbors.each do |neighbor1|
41
+ neighbors.each do |neighbor2|
42
+ #print '---------'
43
+ #print "\n"
44
+ #print neighbors.join(' ')
45
+ #print "\n"
46
+ #print node, ' ', neighbor1, ' ', neighbor2
47
+ #print "\n"
48
+ register_potential_clusters(node, neighbor1, neighbor2)
49
+ end
50
+ end
51
+ @potential_clusters
52
+ end
53
+
54
+ def compute_real_local_clusters(archipelago)
55
+ clusters = []
56
+ @potential_clusters.each do |potential_cluster|
57
+ node1 = potential_cluster[0]
58
+ node2 = potential_cluster[1]
59
+ node3 = potential_cluster[2]
60
+ fully_connected = archipelago.has_edge(node1, node2) && \
61
+ archipelago.has_edge(node3, node2) && \
62
+ archipelago.has_edge(node1, node3)
63
+ if fully_connected
64
+ clusters.push(potential_cluster.clone)
65
+ end
66
+ end
67
+ clusters
68
+ end
69
+
70
+ def register_potential_clusters(node1, node2, node3)
71
+ if node1 == node2
72
+ # invalid set
73
+ return FALSE
74
+ end
75
+ nodes = [node1, node2]
76
+ if nodes.include?(node3)
77
+ # invalid set
78
+ return FALSE
79
+ end
80
+ nodes.push(node3)
81
+ nodes.each do |node|
82
+ return FALSE if node.nil?
83
+ end
84
+ nodes.sort!
85
+ if @potential_clusters.include?(nodes)
86
+ # value already taken into account
87
+ return FALSE
88
+ end
89
+ @potential_clusters.push(nodes)
90
+ TRUE
91
+ end
92
+ end
@@ -0,0 +1,64 @@
1
+ require 'gimuby/genetic/archipelago/measure/measure'
2
+
3
+ # Return the number of connected class for an archipelago
4
+ class ConnectedMeasure < Measure
5
+
6
+ # @param archipelago {Archipelago}
7
+ def compute(archipelago)
8
+ init_connected_classes(archipelago)
9
+ old_signature = get_state_signature
10
+ new_signature = ''
11
+ until old_signature == new_signature
12
+ old_signature = new_signature
13
+ try_to_reduce(archipelago)
14
+ new_signature = get_state_signature
15
+ end
16
+ get_connected_classes_count
17
+ end
18
+
19
+ private
20
+
21
+ def init_connected_classes(archipelago)
22
+ nodes = archipelago.get_nodes
23
+ @connected_classes = {}
24
+ nodes.each do |node|
25
+ @connected_classes[node] = node
26
+ end
27
+ end
28
+
29
+ def get_state_signature
30
+ signature = ''
31
+ @connected_classes.each do |k, v|
32
+ signature = '|' + k.to_s + '-->' + v.to_s + "\n"
33
+ end
34
+ signature
35
+ end
36
+
37
+ def get_connected_classes_count
38
+ different_classes = []
39
+ @connected_classes.each do |_, connected_class|
40
+ unless different_classes.include?(connected_class)
41
+ different_classes.push(connected_class)
42
+ end
43
+ end
44
+ different_classes.length
45
+ end
46
+
47
+ # @param archipelago {Archipelago}
48
+ def try_to_reduce(archipelago)
49
+ @connected_classes.each do |key1, value1|
50
+ @connected_classes.each do |key2, value2|
51
+ unless (key1 == key2) || (value1 == value2)
52
+ if archipelago.has_edge(key1, key2)
53
+ if value1 < value2
54
+ @connected_classes[key2] = value1
55
+ else
56
+ @connected_classes[key1] = value2
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ end
@@ -0,0 +1,38 @@
1
+ require 'gimuby/genetic/archipelago/measure/measure'
2
+ require 'gimuby/genetic/archipelago/measure/shortest_paths_measure'
3
+ require 'gimuby/genetic/archipelago/measure/connected_measure'
4
+
5
+
6
+ # Return the diameter of an archipelago
7
+ # If archipelago is not connex, simply output twice number of its nodes
8
+ class DiameterMeasure < Measure
9
+
10
+ def compute(archipelago)
11
+ unless is_connected(archipelago)
12
+ return 2 * archipelago.get_nodes.length
13
+ end
14
+ get_biggest_shortest_paths(archipelago)
15
+ end
16
+
17
+ private
18
+
19
+ def is_connected(archipelago)
20
+ connected_measure = get_connected_measure
21
+ connected_classes_count = connected_measure.compute(archipelago)
22
+ connected_classes_count == 1
23
+ end
24
+
25
+ def get_biggest_shortest_paths(archipelago)
26
+ paths_lengths = get_shortest_paths_measure.compute(archipelago)
27
+ paths_lengths.max
28
+ end
29
+
30
+ def get_connected_measure
31
+ ConnectedMeasure.new
32
+ end
33
+
34
+ def get_shortest_paths_measure
35
+ ShortestPathsMeasure.new
36
+ end
37
+
38
+ end
@@ -0,0 +1,7 @@
1
+
2
+ class Measure
3
+
4
+ def compute(archipelago)
5
+ NotImplementedError
6
+ end
7
+ end
@@ -0,0 +1,46 @@
1
+ require 'gimuby/genetic/archipelago/measure/measure'
2
+
3
+ # Return the list of shortest path (Dijkstra) in Archipelago
4
+ class ShortestPathsMeasure < Measure
5
+
6
+ def compute(archipelago)
7
+ nodes = archipelago.get_nodes
8
+ shortest_paths_length = []
9
+ nodes.each do |node1|
10
+ nodes.each do |node2|
11
+ if node2 > node1
12
+ length = get_shortest_path_length(archipelago, node1, node2)
13
+ unless length.nil?
14
+ shortest_paths_length.push(length)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ shortest_paths_length
20
+ end
21
+
22
+ private
23
+
24
+ def get_shortest_path_length(archipelago, node1, node2)
25
+ next_nodes = [node1]
26
+ current_neighbor_distance = 0
27
+ nodes_distances = {node1 => current_neighbor_distance}
28
+ while next_nodes.length != 0
29
+ current_node = next_nodes.shift
30
+ current_neighbor_distance = nodes_distances[current_node] + 1
31
+ neighbors = archipelago.get_neighbors(current_node)
32
+ neighbors.each do |neighbor_node|
33
+ already_processed = nodes_distances.has_key?(neighbor_node)
34
+ unless already_processed
35
+ next_nodes.push neighbor_node
36
+ nodes_distances[neighbor_node] = current_neighbor_distance
37
+ end
38
+ end
39
+ if nodes_distances.has_key?(node2)
40
+ return nodes_distances[node2]
41
+ end
42
+ end
43
+ nil
44
+ end
45
+
46
+ end
@@ -0,0 +1,17 @@
1
+ require 'gimuby/genetic/population/pick_strategy/pick_strategy'
2
+
3
+ class BestsPickStrategy < PickStrategy
4
+
5
+ def pick(population)
6
+ solutions = population.solutions
7
+ number = get_number_to_pick(population)
8
+ candidates = solutions.clone
9
+
10
+ candidates.sort! do |x, y|
11
+ (population.get_fitness x) <=> (population.get_fitness y)
12
+ end
13
+
14
+ candidates.slice(0, number)
15
+ end
16
+
17
+ end
@@ -0,0 +1,21 @@
1
+
2
+ class PickStrategy
3
+
4
+ def initialize
5
+ @pick_proportion ||= 25.to_f / 100.to_f
6
+ end
7
+
8
+ attr_accessor :pick_proportion
9
+
10
+ # pick some solution inside the population
11
+ def pick(population)
12
+ raise NotImplementedError
13
+ end
14
+
15
+ protected
16
+
17
+ def get_number_to_pick(population)
18
+ number = population.solutions.length * @pick_proportion
19
+ number.round
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ require 'gimuby/genetic/population/pick_strategy/pick_strategy'
2
+
3
+ class RandomWheelPickStrategy < PickStrategy
4
+
5
+ def initialize
6
+ super
7
+ @random_wheel_probability_reason = 0.7
8
+ end
9
+
10
+ attr_accessor :random_wheel_probability_reason
11
+
12
+ def pick(population)
13
+ number = get_number_to_pick(population)
14
+ reason = @random_wheel_probability_reason
15
+ solutions = population.solutions
16
+ candidates = solutions.clone
17
+ candidates.sort! do |x, y|
18
+ (population.get_fitness x) <=> (population.get_fitness y)
19
+ end
20
+ picked = []
21
+ begin
22
+ # we use a geometric sequence
23
+ max_of_the_rand = (1 - reason ** candidates.length) / (1 - reason)
24
+ r = rand() * max_of_the_rand
25
+ element = 1
26
+ candidates.each do |solution|
27
+ max_accepted_value = (1 - reason ** element) / (1 - reason)
28
+ element += 1
29
+ if max_accepted_value > r
30
+ picked.push solution
31
+ ind = candidates.index solution
32
+ candidates.slice! ind
33
+ break
34
+ end
35
+ end
36
+ end while picked.length < number
37
+ picked
38
+ end
39
+
40
+ end
@@ -0,0 +1,26 @@
1
+ require 'gimuby/genetic/population/pick_strategy/pick_strategy'
2
+
3
+ class TournamentPickStrategy < PickStrategy
4
+
5
+ def pick(population)
6
+ solutions = population.solutions
7
+ number = get_number_to_pick(population)
8
+ candidates = solutions.clone
9
+
10
+ while candidates.length > number:
11
+ sol1 = candidates.choice()
12
+ sol2 = sol1
13
+ while sol1 == sol2:
14
+ sol2 = candidates.choice()
15
+ end
16
+ if population.get_fitness(sol1) < population.get_fitness(sol2)
17
+ candidates.delete(sol2)
18
+ else
19
+ candidates.delete(sol1)
20
+ end
21
+ end
22
+
23
+ candidates
24
+ end
25
+
26
+ end