mhl 0.2.0 → 0.3.0
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.
- 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
|
+
[](https://badge.fury.io/rb/mhl)
|
4
|
+
[](https://travis-ci.org/mtortonesi/ruby-mhl)
|
5
|
+
[](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?
|