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
data/Gemfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rake
|
data/LICENSE.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
The MIT License
|
2
|
+
===============
|
3
|
+
|
4
|
+
Copyright © 2014 Fräntz Miccoli
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
7
|
+
this software and associated documentation files (the "Software"), to deal in
|
8
|
+
the Software without restriction, including without limitation the rights to
|
9
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
10
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
11
|
+
so, subject to the following conditions:
|
12
|
+
|
13
|
+
Except as contained in this notice, the name(s) of the above copyright holders
|
14
|
+
shall not be used in advertising or otherwise to promote the sale, use or other
|
15
|
+
dealings in this Software without prior written authorization.
|
16
|
+
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
18
|
+
copies or substantial portions of the Software.
|
19
|
+
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
22
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
23
|
+
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
24
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
25
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
File without changes
|
data/lib/gimuby.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
# Please note that the default are important to let unit test run perfectly
|
3
|
+
class GimubyConfig
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@persistence_dir_path = '/tmp'
|
7
|
+
|
8
|
+
# Problem specific configuration
|
9
|
+
|
10
|
+
# TSP
|
11
|
+
@tsp_number_points = 100
|
12
|
+
|
13
|
+
# Rastrigin
|
14
|
+
@rastrigin_dimension = 20
|
15
|
+
|
16
|
+
# Lennard Jones
|
17
|
+
@lennard_jones_atoms = 31
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_accessor :persistence_dir_path
|
21
|
+
|
22
|
+
attr_accessor :problem
|
23
|
+
|
24
|
+
# TSP
|
25
|
+
attr_accessor :tsp_number_points
|
26
|
+
|
27
|
+
# Rastrigin
|
28
|
+
attr_accessor :rastrigin_dimension
|
29
|
+
|
30
|
+
# Lennard Jones
|
31
|
+
attr_accessor :lennard_jones_atoms
|
32
|
+
|
33
|
+
attr_accessor :optimal_population
|
34
|
+
attr_accessor :optimal_archipelago
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
$config = GimubyConfig.new()
|
39
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'gimuby/factory'
|
2
|
+
require 'gimuby/event/event_manager'
|
3
|
+
require 'gimuby/problem/tsp/tsp'
|
4
|
+
require 'gimuby/problem/foxholes/foxholes'
|
5
|
+
|
6
|
+
# Dependencies container that is accessed from everywhere in the app
|
7
|
+
class Dependencies
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@event_manager = EventManager.new
|
11
|
+
|
12
|
+
# problem specific
|
13
|
+
@tsp = nil
|
14
|
+
@foxholes = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_accessor :event_manager
|
18
|
+
|
19
|
+
# problem specific
|
20
|
+
|
21
|
+
def tsp
|
22
|
+
if @tsp.nil?
|
23
|
+
@tsp = Tsp.new
|
24
|
+
end
|
25
|
+
@tsp
|
26
|
+
end
|
27
|
+
|
28
|
+
def foxholes
|
29
|
+
if @foxholes.nil?
|
30
|
+
@foxholes = Foxholes.new
|
31
|
+
end
|
32
|
+
@foxholes
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
$dependencies = Dependencies.new
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'gimuby/dependencies'
|
2
|
+
|
3
|
+
class Event
|
4
|
+
|
5
|
+
# @param format [String] The name of the event
|
6
|
+
# @param data [Hash] An Hash containing the data that will be passed
|
7
|
+
# to the listeners
|
8
|
+
# @api
|
9
|
+
def initialize(name = nil?, data = {})
|
10
|
+
@name = name
|
11
|
+
@data = data
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_accessor :name
|
15
|
+
attr_accessor :data
|
16
|
+
|
17
|
+
# Trigger the event (through the event manager)
|
18
|
+
# @api
|
19
|
+
def trigger
|
20
|
+
event_manager = get_event_manager
|
21
|
+
event_manager.trigger_event(name, self)
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def get_event_manager
|
27
|
+
$dependencies.event_manager
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'gimuby/event/event'
|
2
|
+
|
3
|
+
# Core of the event managing system, this class stores listener and call them
|
4
|
+
# on event triggering.
|
5
|
+
class EventManager
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@listeners_registry = {} #contains array
|
9
|
+
end
|
10
|
+
|
11
|
+
# @param name {String} The event name
|
12
|
+
# @param block {Block} The callback that will be call
|
13
|
+
# @api
|
14
|
+
def register_listener(name, &block)
|
15
|
+
unless @listeners_registry.has_key? name
|
16
|
+
@listeners_registry[name] = []
|
17
|
+
end
|
18
|
+
@listeners_registry[name].push block
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param name {String} The event name
|
22
|
+
# @param event {Event} The event object
|
23
|
+
def trigger_event(name, event = {})
|
24
|
+
if @listeners_registry.has_key? name
|
25
|
+
if event.class == Hash
|
26
|
+
event = Event.new(name, event)
|
27
|
+
end
|
28
|
+
listeners = @listeners_registry[name]
|
29
|
+
listeners.each do |block|
|
30
|
+
block.call event
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'gimuby/dependencies'
|
2
|
+
require 'gimuby/config'
|
3
|
+
require 'gimuby/genetic/archipelago/archipelago'
|
4
|
+
require 'gimuby/genetic/population/population'
|
5
|
+
require 'gimuby/genetic/population/pick_strategy/bests_pick_strategy'
|
6
|
+
require 'gimuby/genetic/population/pick_strategy/random_wheel_pick_strategy'
|
7
|
+
require 'gimuby/genetic/population/pick_strategy/tournament_pick_strategy'
|
8
|
+
require 'gimuby/genetic/population/replace_strategy/replace_worst_replace_strategy'
|
9
|
+
require 'gimuby/genetic/population/replace_strategy/uniform_replace_strategy'
|
10
|
+
require 'gimuby/genetic/archipelago/connect_strategy/circle_connect_strategy'
|
11
|
+
require 'gimuby/genetic/archipelago/connect_strategy/fully_connected_connect_strategy'
|
12
|
+
require 'gimuby/genetic/archipelago/connect_strategy/random_connect_strategy'
|
13
|
+
require 'gimuby/genetic/archipelago/connect_strategy/constant_degree_connect_strategy'
|
14
|
+
require 'gimuby/genetic/archipelago/connect_strategy/barabasi_albert_connect_strategy'
|
15
|
+
require 'gimuby/genetic/archipelago/connect_strategy/watts_strogatz_connect_strategy'
|
16
|
+
require 'gimuby/problem/tsp/tsp_solution'
|
17
|
+
require 'gimuby/problem/rastrigin/rastrigin_solution'
|
18
|
+
require 'gimuby/problem/lennard_jones/lennard_jones_solution'
|
19
|
+
require 'gimuby/problem/schaffer/schaffer_solution'
|
20
|
+
require 'gimuby/problem/rosenbrock/rosenbrock_solution'
|
21
|
+
require 'gimuby/problem/step/step_solution'
|
22
|
+
require 'gimuby/problem/sphere/sphere_solution'
|
23
|
+
require 'gimuby/problem/foxholes/foxholes_solution'
|
24
|
+
|
25
|
+
class Factory
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@optimal_population = FALSE
|
29
|
+
@optimal_archipelago = FALSE
|
30
|
+
|
31
|
+
# use for test purpose to avoid provided archipelago to be connected
|
32
|
+
@connected_archipelago = TRUE
|
33
|
+
|
34
|
+
# those values are set by the user, let them nil and we won't use them
|
35
|
+
@solutions_number = nil
|
36
|
+
@populations_number = nil
|
37
|
+
|
38
|
+
# if we have to generate values we store them here
|
39
|
+
@_solutions_number = nil
|
40
|
+
@_populations_number = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
attr_accessor :optimal_population
|
44
|
+
attr_accessor :optimal_archipelago
|
45
|
+
|
46
|
+
attr_accessor :connected_archipelago
|
47
|
+
|
48
|
+
attr_accessor :solutions_number
|
49
|
+
attr_accessor :populations_number
|
50
|
+
|
51
|
+
def reset_state
|
52
|
+
@connected_archipelago = TRUE
|
53
|
+
@_populations_number = nil
|
54
|
+
@_solutions_number = nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_population(&solution_generator)
|
58
|
+
_get_population(:population, &solution_generator)
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_archipelago(&solution_generator)
|
62
|
+
if @optimal_archipelago
|
63
|
+
return get_optimal_archipelago(&solution_generator)
|
64
|
+
end
|
65
|
+
get_random_archipelago(&solution_generator)
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_optimal_population(optimizer, &solution_generator)
|
69
|
+
candidate_population = get_random_population(optimizer, &solution_generator)
|
70
|
+
begin
|
71
|
+
candidate_population = get_random_population(optimizer, &solution_generator)
|
72
|
+
if candidate_population.solutions.length >= 1000
|
73
|
+
next
|
74
|
+
end
|
75
|
+
if candidate_population.solutions[0].mutation_strategy.mutation_rate >= 0.1
|
76
|
+
next
|
77
|
+
end
|
78
|
+
if candidate_population.replace_strategy.replace_proportion <= 0.4
|
79
|
+
next
|
80
|
+
end
|
81
|
+
if candidate_population.pick_strategy.pick_proportion >= 0.4
|
82
|
+
next
|
83
|
+
end
|
84
|
+
end while FALSE
|
85
|
+
candidate_population
|
86
|
+
end
|
87
|
+
|
88
|
+
def get_optimal_archipelago(&solution_generator)
|
89
|
+
is_optimal = FALSE
|
90
|
+
begin
|
91
|
+
candidate_archipelago = get_random_archipelago(&solution_generator)
|
92
|
+
is_optimal = TRUE
|
93
|
+
if (candidate_archipelago.get_population_size <= 500) or
|
94
|
+
(candidate_archipelago.get_population_size >= 1100)
|
95
|
+
is_optimal = FALSE
|
96
|
+
end
|
97
|
+
if candidate_archipelago.migration_rate <= 0.25
|
98
|
+
is_optimal = FALSE
|
99
|
+
end
|
100
|
+
if (candidate_archipelago.populations.length < 10) or
|
101
|
+
(candidate_archipelago.populations.length > 29)
|
102
|
+
is_optimal = FALSE
|
103
|
+
end
|
104
|
+
if candidate_archipelago.get_diameter >= 100
|
105
|
+
is_optimal = FALSE
|
106
|
+
end
|
107
|
+
end until is_optimal
|
108
|
+
candidate_archipelago
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_random_population(optimizer, &solution_generator)
|
112
|
+
population = Population.new
|
113
|
+
population.pick_strategy = get_random_pick_strategy
|
114
|
+
population.replace_strategy = get_random_replace_strategy
|
115
|
+
populations_number = get_populations_number
|
116
|
+
unless optimizer == :archipelago
|
117
|
+
populations_number = 1
|
118
|
+
end
|
119
|
+
solutions_number = get_solutions_number(populations_number)
|
120
|
+
number_solutions_per_population = solutions_number / populations_number
|
121
|
+
mutation_rate = rand * 0.7
|
122
|
+
number_solutions_per_population.times do
|
123
|
+
solution = solution_generator.call
|
124
|
+
solution.mutation_strategy.mutation_rate = mutation_rate
|
125
|
+
population.add_solution(solution)
|
126
|
+
end
|
127
|
+
|
128
|
+
population
|
129
|
+
end
|
130
|
+
|
131
|
+
def get_random_archipelago(&solution_generator)
|
132
|
+
archipelago = Archipelago.new
|
133
|
+
archipelago.connect_strategy = get_random_connect_strategy
|
134
|
+
# between 0.01% and ~35%
|
135
|
+
archipelago.migration_rate = (rand() * 35.0 / 100.0) + 0.0001
|
136
|
+
archipelago.migration_symmetric = [true, false].choice
|
137
|
+
archipelago.migration_type = [:random, :synchronized, :fixed_time].choice
|
138
|
+
get_populations_number.times do |_|
|
139
|
+
archipelago.add_population(_get_population(:archipelago, &solution_generator))
|
140
|
+
end
|
141
|
+
if @connected_archipelago
|
142
|
+
archipelago.connect_all
|
143
|
+
end
|
144
|
+
archipelago
|
145
|
+
end
|
146
|
+
|
147
|
+
protected
|
148
|
+
|
149
|
+
def _get_population(optimizer, &solution_generator)
|
150
|
+
if @optimal_population
|
151
|
+
return get_optimal_population(optimizer, &solution_generator)
|
152
|
+
end
|
153
|
+
get_random_population(optimizer, &solution_generator)
|
154
|
+
end
|
155
|
+
|
156
|
+
def get_solutions_number(populations_number = 1)
|
157
|
+
unless @_solutions_number.nil?
|
158
|
+
return @_solutions_number
|
159
|
+
end
|
160
|
+
unless @solutions_number.nil?
|
161
|
+
return @solutions_number
|
162
|
+
end
|
163
|
+
|
164
|
+
max_population_size = 5000
|
165
|
+
min_population_size = 12 * populations_number
|
166
|
+
if @optimal_population
|
167
|
+
max_population_size = 1000
|
168
|
+
end
|
169
|
+
if @optimal_archipelago
|
170
|
+
min_population_size = 500
|
171
|
+
max_population_size = [max_population_size, 1100].min
|
172
|
+
end
|
173
|
+
|
174
|
+
solutions_number_range = *(min_population_size..max_population_size)
|
175
|
+
picked_solutions_number = 0
|
176
|
+
solutions_per_population = 0
|
177
|
+
min_solutions_per_population = min_population_size / populations_number
|
178
|
+
begin
|
179
|
+
picked_solutions_number = solutions_number_range.choice
|
180
|
+
picked_solutions_number /= populations_number
|
181
|
+
picked_solutions_number *= populations_number
|
182
|
+
solutions_per_population = picked_solutions_number / populations_number
|
183
|
+
end while solutions_per_population < min_solutions_per_population
|
184
|
+
|
185
|
+
@_solutions_number = picked_solutions_number
|
186
|
+
@_solutions_number
|
187
|
+
end
|
188
|
+
|
189
|
+
def get_populations_number
|
190
|
+
unless @_populations_number.nil?
|
191
|
+
return @_populations_number
|
192
|
+
end
|
193
|
+
unless @populations_number.nil?
|
194
|
+
@_populations_number = @populations_number
|
195
|
+
return @_populations_number
|
196
|
+
end
|
197
|
+
|
198
|
+
populations_number_range = *(2..100)
|
199
|
+
if @optimal_archipelago
|
200
|
+
populations_number_range = *(10..29)
|
201
|
+
end
|
202
|
+
|
203
|
+
@_populations_number = populations_number_range.choice
|
204
|
+
@_populations_number
|
205
|
+
end
|
206
|
+
|
207
|
+
def get_random_pick_strategy
|
208
|
+
max = 10
|
209
|
+
r = rand(max)
|
210
|
+
if r == 0
|
211
|
+
return BestsPickStrategy.new
|
212
|
+
elsif r == 1
|
213
|
+
return TournamentPickStrategy.new
|
214
|
+
end
|
215
|
+
r = rand(9) + 1
|
216
|
+
strategy = RandomWheelPickStrategy.new
|
217
|
+
reason = 1.0 / 10.0 * r
|
218
|
+
strategy.random_wheel_probability_reason = reason
|
219
|
+
|
220
|
+
# pick proportion
|
221
|
+
min = 0.1
|
222
|
+
max = 0.9
|
223
|
+
spread = max - min
|
224
|
+
strategy.pick_proportion = (rand() * spread) + min
|
225
|
+
|
226
|
+
strategy
|
227
|
+
end
|
228
|
+
|
229
|
+
def get_random_replace_strategy
|
230
|
+
if rand() < 0.2
|
231
|
+
strategy = UniformReplaceStrategy.new
|
232
|
+
else
|
233
|
+
strategy = ReplaceWorstReplaceStrategy.new
|
234
|
+
end
|
235
|
+
|
236
|
+
# replace proportion
|
237
|
+
min = 0.05
|
238
|
+
max = 1.0
|
239
|
+
spread = max - min
|
240
|
+
replace_proportion = (rand() * spread) + min
|
241
|
+
strategy.replace_proportion = replace_proportion
|
242
|
+
strategy
|
243
|
+
end
|
244
|
+
|
245
|
+
def get_random_connect_strategy
|
246
|
+
r = rand(10)
|
247
|
+
if r == 0
|
248
|
+
return CircleConnectStrategy.new
|
249
|
+
end
|
250
|
+
if r == 1
|
251
|
+
return FullyConnectedConnectStrategy.new
|
252
|
+
end
|
253
|
+
r = rand(4)
|
254
|
+
max_degree = [22, get_populations_number - 1].min
|
255
|
+
# even number means easier by two divisions
|
256
|
+
average_degree = (rand((max_degree - 1)/ 2) + 1) * 2
|
257
|
+
# avoid a bug on an edge case when max_degree = 2
|
258
|
+
average_degree = [average_degree, max_degree].min
|
259
|
+
case r
|
260
|
+
when 0
|
261
|
+
strategy = RandomConnectStrategy.new
|
262
|
+
when 1
|
263
|
+
strategy = ConstantDegreeConnectStrategy.new
|
264
|
+
when 2
|
265
|
+
strategy = BarabasiAlbertConnectStrategy.new
|
266
|
+
when 3
|
267
|
+
strategy = WattsStrogatzConnectStrategy.new
|
268
|
+
else
|
269
|
+
raise 'random value (r) has an unexpected value'
|
270
|
+
end
|
271
|
+
strategy.average_degree = average_degree
|
272
|
+
strategy
|
273
|
+
end
|
274
|
+
|
275
|
+
end
|