mhl 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.projections.json +12 -0
- data/.travis.yml +6 -0
- data/README.md +58 -38
- data/Rakefile +3 -0
- data/TODO +24 -0
- data/extra/process_ga_solver_output.awk +2 -0
- data/extra/process_pso_solver_output.awk +2 -0
- data/lib/mhl/charged_swarm.rb +17 -14
- data/lib/mhl/genetic_algorithm_solver.rb +78 -54
- data/lib/mhl/hm_plus_rechenberg_controller.rb +44 -0
- data/lib/mhl/{integer_genotype_space.rb → integer_vector_genotype_space.rb} +14 -8
- data/lib/mhl/multiswarm_qpso_solver.rb +31 -19
- data/lib/mhl/particle_swarm_optimization_solver.rb +25 -16
- data/lib/mhl/pso_swarm.rb +12 -10
- data/lib/mhl/qpso_swarm.rb +10 -9
- data/lib/mhl/quantum_particle_swarm_optimization_solver.rb +24 -16
- data/lib/mhl/real_vector_genotype_space.rb +142 -0
- data/lib/mhl/rechenberg_controller.rb +49 -0
- data/lib/mhl/version.rb +1 -1
- data/mhl.gemspec +4 -1
- data/test/mhl/genetic_algorithm_solver_test.rb +69 -31
- data/test/mhl/{integer_genotype_space_test.rb → integer_vector_genotype_space_test.rb} +34 -26
- data/test/mhl/multiswarm_qpso_solver_test.rb +48 -10
- data/test/mhl/particle_swarm_optimization_solver_test.rb +47 -9
- data/test/mhl/quantum_particle_swarm_optimization_solver_test.rb +47 -9
- data/test/mhl/real_vector_genotype_space_test.rb +85 -0
- data/test/test_helper.rb +1 -0
- metadata +72 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 36fae082a93b3e25f96b3157a62e8c6d5d95e63379fc6790a2628abcc1c7d754
|
4
|
+
data.tar.gz: 23a0d3730c592f7209d95db64f4843fef6d9e220c76ecf68240dfd0d0d917d63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb0309f4908366b7940ad7d0b160a9aac5a2e2b7c2fe20affaf8176e3f5859bb695ed5182d273c6ebd382325fbd97984d945d9d8063dd2dc47428353ec8572b7
|
7
|
+
data.tar.gz: f2ed2cb5eb6f0e00dd0ec4d22153510c19b77746e14278664146ebcc2bb04e9b30a7f061c0c0bc6dfbc395dd164b9ce55ab862cb9d5e51940f42cc8a01b0cf84
|
data/.projections.json
ADDED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# ruby-mhl - A Ruby metaheuristics library
|
2
2
|
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/mhl.svg)](https://badge.fury.io/rb/mhl)
|
4
|
+
[![Build Status](https://travis-ci.org/mtortonesi/ruby-mhl.png?branch=master)](https://travis-ci.org/mtortonesi/ruby-mhl)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/mtortonesi/ruby-mhl.png)](https://codeclimate.com/github/mtortonesi/ruby-mhl)
|
6
|
+
|
3
7
|
ruby-mhl is a scientific library that provides a fairly large array of advanced
|
4
8
|
computational intelligence methods for continuous optimization solutions.
|
5
9
|
|
@@ -9,26 +13,19 @@ Particle Swarm Optimization (constrained PSO, quantum-inspired PSO, and a
|
|
9
13
|
multi-swarm version of quantum-inspired PSO), extended with adaptation
|
10
14
|
mechanisms to provide support for dynamic optimization problems.
|
11
15
|
|
12
|
-
ruby-mhl was designed for
|
13
|
-
typically involves one or more simulation runs, possibly defined on very
|
14
|
-
complex domains (or search spaces)
|
15
|
-
|
16
|
-
|
16
|
+
ruby-mhl was designed for _heavy duty_ target functions, whose evaluation
|
17
|
+
typically involves one or more long simulation runs, possibly defined on very
|
18
|
+
complex domains (or search spaces). To this end, ruby-mhl allows to evaluate
|
19
|
+
the target function in a concurrent fashion, automatically taking advantage of
|
20
|
+
the full amount of parallelism offered by the processor if the application is
|
21
|
+
running on a Ruby interpreter that does not have a GIL, such as JRuby.
|
22
|
+
(ruby-mhl will work with any Ruby interpreter, but the adoption of JRuby is
|
23
|
+
strongly recommended for performance reasons.)
|
17
24
|
|
18
25
|
|
19
26
|
## Installation
|
20
27
|
|
21
|
-
|
22
|
-
dependent step, so I won't show you how to do it. However, if you are on Linux
|
23
|
-
or OS X I recommend you to use [rbenv](https://github.com/rbenv/rbenv) to
|
24
|
-
install and manage your Ruby installations.
|
25
|
-
|
26
|
-
Once you have JRuby installed, you need to install bundler:
|
27
|
-
|
28
|
-
gem install bundler
|
29
|
-
|
30
|
-
|
31
|
-
### Stable version
|
28
|
+
### Stable version (recommended)
|
32
29
|
|
33
30
|
You can get the stable version of ruby-mhl by installing the mhl gem from
|
34
31
|
RubyGems:
|
@@ -74,16 +71,16 @@ x<sub>2</sub><sup>2</sup>_ equation with a genetic algorithm:
|
|
74
71
|
require 'mhl'
|
75
72
|
|
76
73
|
solver = MHL::GeneticAlgorithmSolver.new(
|
77
|
-
:
|
78
|
-
:
|
79
|
-
:
|
80
|
-
:
|
81
|
-
:
|
82
|
-
:
|
83
|
-
:
|
84
|
-
:
|
74
|
+
population_size: 80,
|
75
|
+
genotype_space_type: :integer,
|
76
|
+
mutation_probability: 0.5,
|
77
|
+
recombination_probability: 0.5,
|
78
|
+
genotype_space_conf: {
|
79
|
+
dimensions: 2,
|
80
|
+
recombination_type: :intermediate,
|
81
|
+
random_func: lambda { Array.new(2) { rand(100) } }
|
85
82
|
},
|
86
|
-
:
|
83
|
+
exit_condition: lambda {|generation,best| best[:fitness] == 0}
|
87
84
|
)
|
88
85
|
solver.solve(Proc.new{|x| -(x[0] ** 2 + x[1] ** 2) })
|
89
86
|
```
|
@@ -148,12 +145,12 @@ x<sub>2</sub><sup>2</sup>_ equation with PSO:
|
|
148
145
|
require 'mhl'
|
149
146
|
|
150
147
|
solver = MHL::ParticleSwarmOptimizationSolver.new(
|
151
|
-
:
|
152
|
-
:
|
153
|
-
:
|
154
|
-
:
|
148
|
+
swarm_size: 40, # 40 is the default swarm size
|
149
|
+
constraints: {
|
150
|
+
min: [ -100, -100 ],
|
151
|
+
max: [ 100, 100 ],
|
155
152
|
},
|
156
|
-
:
|
153
|
+
exit_condition: lambda {|iteration,best| best[:height].abs < 0.001 },
|
157
154
|
)
|
158
155
|
solver.solve(Proc.new{|x| -(x[0] ** 2 + x[1] ** 2) })
|
159
156
|
```
|
@@ -198,12 +195,12 @@ x<sub>2</sub><sup>2</sup>_ equation with PSO:
|
|
198
195
|
require 'mhl'
|
199
196
|
|
200
197
|
solver = MHL::QuantumPSOSolver.new(
|
201
|
-
:
|
202
|
-
:
|
203
|
-
:
|
204
|
-
:
|
198
|
+
swarm_size: 40, # 40 is the default swarm size
|
199
|
+
constraints: {
|
200
|
+
min: [ -100, -100 ],
|
201
|
+
max: [ 100, 100 ],
|
205
202
|
},
|
206
|
-
:
|
203
|
+
exit_condition: lambda {|iteration,best| best[:height].abs < 0.001 },
|
207
204
|
)
|
208
205
|
solver.solve(Proc.new{|x| -(x[0] ** 2 + x[1] ** 2) })
|
209
206
|
```
|
@@ -240,17 +237,32 @@ IFIP/IEEE International Workshop on Business-driven IT Management (BDIM 2013),
|
|
240
237
|
If you are interested in ruby-mhl, please consider reading and citing them.
|
241
238
|
|
242
239
|
|
240
|
+
## Acknowledgements
|
241
|
+
|
242
|
+
The research work that led to the development of ruby-mhl was supported in part by
|
243
|
+
the [DICET - INMOTO - ORganization of Cultural HEritage for Smart
|
244
|
+
Tourism and Real-time Accessibility (OR.C.HE.S.T.R.A.)](http://www.ponrec.it/open-data/progetti/scheda-progetto?ProgettoID=5835)
|
245
|
+
project, funded by the Italian Ministry of University and Research on Axis II
|
246
|
+
of the National operative programme (PON) for Research and Competitiveness
|
247
|
+
2007-13 within the call 'Smart Cities and Communities and Social Innovation'
|
248
|
+
(D.D. n.84/Ric., 2 March 2012).
|
249
|
+
|
250
|
+
|
243
251
|
## References
|
244
252
|
|
245
|
-
[
|
246
|
-
|
253
|
+
[MUHLENBEIN93] H. Mühlenbein, D. Schlierkamp-Voosen, "Predictive Models for the
|
254
|
+
Breeder Genetic Algorithm - I. Continuous Parameter Optimization", Journal of
|
255
|
+
Evolutionary Computation, Vol. 1, No. 1, pp. 25-49, March 1993.
|
256
|
+
|
257
|
+
[SUN11] J. Sun, C.-H. Lai, X.-J. Wu, "Particle Swarm Optimisation: Classical
|
258
|
+
and Quantum Perspectives", CRC Press, 2011.
|
247
259
|
|
248
260
|
[CLERC02] M. Clerc, J. Kennedy, "The particle swarm - explosion,
|
249
261
|
stability, and convergence in a multidimensional complex space", IEEE
|
250
262
|
Transactions on Evolutionary Computation, Vol. 6, No. 1, pp. 58-73,
|
251
263
|
2002, DOI: 10.1109/4235.985692
|
252
264
|
|
253
|
-
[BLACKWELL04]
|
265
|
+
[BLACKWELL04] T. Blackwell, J. Branke, "Multi-swarm Optimization in
|
254
266
|
Dynamic Environments", Applications of Evolutionary Computing, pp. 489-500,
|
255
267
|
Springer, 2004. DOI: 10.1007/978-3-540-24653-4\_50
|
256
268
|
|
@@ -260,3 +272,11 @@ Intelligence, Vol. 25, No. 4, pp. 527-542, 2013. DOI: 10.1080/0952813X.2013.7823
|
|
260
272
|
|
261
273
|
[CLERC12] M. Clerc, "Standard Particle Swarm Optimisation - From 2006 to 2011",
|
262
274
|
available at: [http://clerc.maurice.free.fr/pso/SPSO\_descriptions.pdf](http://clerc.maurice.free.fr/pso/SPSO_descriptions.pdf)
|
275
|
+
|
276
|
+
[LUKE15] S. Luke, "Essentials of Metaheuristics", 2nd Edition, available at:
|
277
|
+
[https://cs.gmu.edu/~sean/book/metaheuristics/](https://cs.gmu.edu/~sean/book/metaheuristics/),
|
278
|
+
Online Version 2.2, October 2015.
|
279
|
+
|
280
|
+
[DEEP07] K. Deep, M. Thakur, "A new mutation operator for real coded genetic
|
281
|
+
algorithms", Applied Mathematics and Computation, Vol. 193, No. 1, pp. 211-230,
|
282
|
+
October 2007.
|
data/Rakefile
CHANGED
data/TODO
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
IMPORTANT
|
2
|
+
|
3
|
+
* improve tournament selection (with default value of k=3)
|
4
|
+
* improve real-valued array chromosome representation support for GA
|
5
|
+
* implement measure of population diversity
|
6
|
+
* survey methods for increasing population diversity
|
7
|
+
* improve implementation of continuous optimization
|
8
|
+
- can we introduce the notion of "mutation intensity" in GAs?
|
9
|
+
- what about PSO variants?
|
10
|
+
* implement support for easy definition of memetic algorithms
|
11
|
+
* implement SPSO (in PSO movement update, do not use the global best as informant but use
|
12
|
+
"links" from neighboring particles)
|
13
|
+
* improve documentation
|
14
|
+
* add specs
|
15
|
+
|
16
|
+
|
17
|
+
MAYBE
|
18
|
+
|
19
|
+
* in random initialization, try using Sobol sequences (or non-linear simplex
|
20
|
+
method or plowing method)?
|
21
|
+
* implement CLONALG?
|
22
|
+
* implement CMA-ES?
|
23
|
+
* implement biased random key genetic algorithms?
|
24
|
+
* implement more rigorous constraint management according to CoelloCoello11?
|
data/lib/mhl/charged_swarm.rb
CHANGED
@@ -8,11 +8,13 @@ module MHL
|
|
8
8
|
# traditional PSO (with inertia), swarms
|
9
9
|
DEFAULT_CHARGED_TO_NEUTRAL_RATIO = 1.0
|
10
10
|
|
11
|
-
def initialize(size
|
11
|
+
def initialize(size:, initial_positions:, initial_velocities:,
|
12
|
+
charged_to_neutral_ratio: nil, alpha: nil, c1: nil, c2: nil,
|
13
|
+
chi: nil, constraints: nil, logger: nil)
|
12
14
|
@size = size
|
13
15
|
|
14
16
|
# retrieve ratio between charged (QPSO) and neutral (constrained PSO) particles
|
15
|
-
ratio = (
|
17
|
+
ratio = (charged_to_neutral_ratio || DEFAULT_CHARGED_TO_NEUTRAL_RATIO).to_f
|
16
18
|
unless ratio > 0.0
|
17
19
|
raise ArgumentError, 'Parameter :charged_to_neutral_ratio should be a real greater than zero!'
|
18
20
|
end
|
@@ -36,28 +38,29 @@ module MHL
|
|
36
38
|
@iteration = 1
|
37
39
|
|
38
40
|
# define procedure to get dynamic value for alpha
|
39
|
-
@get_alpha = if
|
40
|
-
|
41
|
+
@get_alpha = if alpha and alpha.respond_to? :call
|
42
|
+
alpha
|
41
43
|
else
|
42
|
-
->(it) { (
|
44
|
+
->(it) { (alpha || DEFAULT_ALPHA).to_f }
|
43
45
|
end
|
44
46
|
|
45
47
|
# get values for parameters C1 and C2
|
46
|
-
@c1 = (
|
47
|
-
@c2 = (
|
48
|
+
@c1 = (c1 || DEFAULT_C1).to_f
|
49
|
+
@c2 = (c2 || DEFAULT_C2).to_f
|
48
50
|
|
49
51
|
# define procedure to get dynamic value for chi
|
50
|
-
@get_chi = if
|
51
|
-
|
52
|
+
@get_chi = if chi and chi.respond_to? :call
|
53
|
+
chi
|
52
54
|
else
|
53
|
-
->(it) { (
|
55
|
+
->(it) { (chi || DEFAULT_CHI).to_f }
|
54
56
|
end
|
55
57
|
|
56
|
-
|
57
|
-
|
58
|
-
end
|
58
|
+
@constraints = constraints
|
59
|
+
@logger = logger
|
59
60
|
|
60
|
-
@constraints
|
61
|
+
if @constraints and @logger
|
62
|
+
@logger.info "ChargedSwarm called w/ constraints: #{@constraints}"
|
63
|
+
end
|
61
64
|
end
|
62
65
|
|
63
66
|
def mutate
|
@@ -3,7 +3,8 @@ require 'erv'
|
|
3
3
|
require 'logger'
|
4
4
|
|
5
5
|
require 'mhl/bitstring_genotype_space'
|
6
|
-
require 'mhl/
|
6
|
+
require 'mhl/integer_vector_genotype_space'
|
7
|
+
require 'mhl/real_vector_genotype_space'
|
7
8
|
|
8
9
|
|
9
10
|
module MHL
|
@@ -18,16 +19,36 @@ module MHL
|
|
18
19
|
raise ArgumentError, 'Even population size required!'
|
19
20
|
end
|
20
21
|
|
22
|
+
@exit_condition = opts[:exit_condition]
|
23
|
+
@start_population = opts[:genotype_space_conf][:start_population]
|
24
|
+
|
25
|
+
@controller = opts[:controller]
|
26
|
+
|
27
|
+
case opts[:logger]
|
28
|
+
when :stdout
|
29
|
+
@logger = Logger.new(STDOUT)
|
30
|
+
when :stderr
|
31
|
+
@logger = Logger.new(STDERR)
|
32
|
+
else
|
33
|
+
@logger = opts[:logger]
|
34
|
+
end
|
35
|
+
|
36
|
+
@quiet = opts[:quiet]
|
37
|
+
|
38
|
+
if @logger
|
39
|
+
@logger.level = (opts[:log_level] or :warn)
|
40
|
+
end
|
41
|
+
|
21
42
|
# perform genotype space-specific configuration
|
22
43
|
case opts[:genotype_space_type]
|
23
44
|
when :integer
|
24
|
-
@genotype_space = IntegerVectorGenotypeSpace.new(opts[:genotype_space_conf])
|
45
|
+
@genotype_space = IntegerVectorGenotypeSpace.new(opts[:genotype_space_conf], @logger)
|
25
46
|
|
26
47
|
begin
|
27
48
|
@mutation_probability = opts[:mutation_probability].to_f
|
28
49
|
@mutation_rv = \
|
29
|
-
ERV::RandomVariable.new(:
|
30
|
-
:probability_of_success
|
50
|
+
ERV::RandomVariable.new(distribution: :geometric,
|
51
|
+
args: { probability_of_success: @mutation_probability })
|
31
52
|
rescue
|
32
53
|
raise ArgumentError, 'Mutation probability configuration is wrong.'
|
33
54
|
end
|
@@ -35,43 +56,35 @@ module MHL
|
|
35
56
|
begin
|
36
57
|
p_r = opts[:recombination_probability].to_f
|
37
58
|
@recombination_rv = \
|
38
|
-
ERV::RandomVariable.new(:
|
39
|
-
:min_value
|
40
|
-
:max_value => 1.0 + p_r)
|
59
|
+
ERV::RandomVariable.new(distribution: :uniform,
|
60
|
+
args: { min_value: -p_r, max_value: 1.0 + p_r })
|
41
61
|
rescue
|
42
62
|
raise ArgumentError, 'Recombination probability configuration is wrong.'
|
43
63
|
end
|
44
64
|
|
45
|
-
when :
|
46
|
-
@genotype_space
|
47
|
-
@recombination_rv = ERV::RandomVariable.new(:distribution => :uniform, :max_value => 1.0)
|
48
|
-
@mutation_rv = ERV::RandomVariable.new(:distribution => :uniform, :max_value => 1.0)
|
49
|
-
|
50
|
-
else
|
51
|
-
raise ArgumentError, 'Only integer and bitstring genotype representations are supported!'
|
52
|
-
end
|
53
|
-
|
54
|
-
@exit_condition = opts[:exit_condition]
|
55
|
-
@start_population = opts[:genotype_space_conf][:start_population]
|
65
|
+
when :real
|
66
|
+
@genotype_space = RealVectorGenotypeSpace.new(opts[:genotype_space_conf], @logger)
|
56
67
|
|
57
|
-
|
68
|
+
# we have no mutation probability related parameters
|
69
|
+
@mutation_rv = ERV::RandomVariable.new(distribution: :uniform, args: { max_value: 1.0 })
|
58
70
|
|
59
|
-
|
71
|
+
begin
|
72
|
+
p_r = opts[:recombination_probability].to_f
|
73
|
+
@recombination_rv = \
|
74
|
+
ERV::RandomVariable.new(distribution: :uniform,
|
75
|
+
args: { min_value: -p_r, max_value: 1.0 + p_r })
|
76
|
+
rescue
|
77
|
+
raise ArgumentError, 'Recombination probability configuration is wrong.'
|
78
|
+
end
|
60
79
|
|
61
|
-
|
62
|
-
|
63
|
-
@
|
64
|
-
|
65
|
-
@logger = Logger.new(STDERR)
|
80
|
+
when :bitstring
|
81
|
+
@genotype_space = BitstringGenotypeSpace.new(opts[:genotype_space_conf])
|
82
|
+
@recombination_rv = ERV::RandomVariable.new(distribution: :uniform, args: { max_value: 1.0 })
|
83
|
+
@mutation_rv = ERV::RandomVariable.new(distribution: :uniform, args: { max_value: 1.0 })
|
66
84
|
else
|
67
|
-
|
85
|
+
raise ArgumentError, 'Only integer and bitstring genotype representations are supported!'
|
68
86
|
end
|
69
87
|
|
70
|
-
@quiet = opts[:quiet]
|
71
|
-
|
72
|
-
if @logger
|
73
|
-
@logger.level = (opts[:log_level] or Logger::WARN)
|
74
|
-
end
|
75
88
|
end
|
76
89
|
|
77
90
|
def mutation_probability=(new_mp)
|
@@ -80,8 +93,8 @@ module MHL
|
|
80
93
|
end
|
81
94
|
@mutation_probability = new_mp
|
82
95
|
@mutation_rv = \
|
83
|
-
ERV::RandomVariable.new(:
|
84
|
-
:probability_of_success => @mutation_probability)
|
96
|
+
ERV::RandomVariable.new(distribution: :geometric,
|
97
|
+
args: { :probability_of_success => @mutation_probability })
|
85
98
|
end
|
86
99
|
|
87
100
|
# This is the method that solves the optimization problem
|
@@ -89,16 +102,16 @@ module MHL
|
|
89
102
|
# Parameter func is supposed to be a method (or a Proc, a lambda, or any callable
|
90
103
|
# object) that accepts the genotype as argument (that is, the set of
|
91
104
|
# parameters) and returns the phenotype (that is, the function result)
|
92
|
-
def solve(func)
|
105
|
+
def solve(func, params={})
|
93
106
|
# setup population
|
94
107
|
if @start_population.nil?
|
95
108
|
population = Array.new(@population_size) do
|
96
109
|
# generate random genotype according to the chromosome type
|
97
|
-
{ :
|
110
|
+
{ genotype: @genotype_space.get_random }
|
98
111
|
end
|
99
112
|
else
|
100
113
|
population = @start_population.map do |x|
|
101
|
-
{ :
|
114
|
+
{ genotype: x }
|
102
115
|
end
|
103
116
|
end
|
104
117
|
|
@@ -113,34 +126,45 @@ module MHL
|
|
113
126
|
gen += 1
|
114
127
|
@logger.info("GA - Starting generation #{gen}") if @logger
|
115
128
|
|
116
|
-
# create latch to control program termination
|
117
|
-
latch = Concurrent::CountDownLatch.new(@population_size)
|
118
|
-
|
119
129
|
# assess fitness for every member of the population
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
130
|
+
if params[:concurrent]
|
131
|
+
# the function to optimize is thread safe: call it multiple times in
|
132
|
+
# a concurrent fashion
|
133
|
+
# to this end, we use the high level promise-based construct
|
134
|
+
# recommended by the authors of ruby's (fantastic) concurrent gem
|
135
|
+
promises = population.map do |member|
|
136
|
+
Concurrent::Promise.execute do
|
137
|
+
# evaluate target function
|
138
|
+
# do we need to syncronize this call through population_mutex?
|
139
|
+
# probably not.
|
140
|
+
ret = func.call(member[:genotype])
|
141
|
+
|
142
|
+
# protect write access to population struct using mutex
|
143
|
+
population_mutex.synchronize do
|
144
|
+
# update fitness
|
145
|
+
member[:fitness] = ret
|
146
|
+
end
|
129
147
|
end
|
148
|
+
end
|
130
149
|
|
131
|
-
|
132
|
-
|
150
|
+
# wait for all the spawned threads to finish
|
151
|
+
promises.map(&:wait)
|
152
|
+
else
|
153
|
+
# the function to optimize is not thread safe: call it multiple times
|
154
|
+
# in a sequential fashion
|
155
|
+
population.each do |member|
|
156
|
+
# evaluate target function
|
157
|
+
ret = func.call(member[:genotype])
|
158
|
+
# update fitness
|
159
|
+
member[:fitness] = ret
|
133
160
|
end
|
134
161
|
end
|
135
162
|
|
136
|
-
# wait for all the threads to terminate
|
137
|
-
latch.wait
|
138
|
-
|
139
163
|
# find fittest member
|
140
164
|
population_best = population.max_by {|x| x[:fitness] }
|
141
165
|
|
142
166
|
# print results
|
143
|
-
|
167
|
+
@logger.info "> gen #{gen}, best: #{population_best[:genotype]}, #{population_best[:fitness]}" unless @quiet
|
144
168
|
|
145
169
|
# calculate overall best
|
146
170
|
if overall_best.nil?
|