gimuby 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
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