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