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
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
|