mhl 0.1.0 → 0.2.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 +4 -4
- data/README.md +203 -12
- data/lib/mhl/charged_swarm.rb +31 -19
- data/lib/mhl/generic_particle.rb +0 -28
- data/lib/mhl/generic_swarm.rb +12 -10
- data/lib/mhl/genetic_algorithm_solver.rb +1 -2
- data/lib/mhl/multiswarm_qpso_solver.rb +62 -24
- data/lib/mhl/particle.rb +47 -12
- data/lib/mhl/particle_swarm_optimization_solver.rb +67 -33
- data/lib/mhl/pso_swarm.rb +11 -14
- data/lib/mhl/qpso_swarm.rb +23 -12
- data/lib/mhl/quantum_particle.rb +29 -10
- data/lib/mhl/quantum_particle_swarm_optimization_solver.rb +35 -21
- data/lib/mhl/version.rb +1 -1
- data/mhl.gemspec +2 -3
- data/test/mhl/multiswarm_qpso_solver_test.rb +5 -4
- data/test/mhl/particle_swarm_optimization_solver_test.rb +5 -4
- data/test/mhl/quantum_particle_swarm_optimization_solver_test.rb +5 -3
- metadata +18 -32
data/lib/mhl/quantum_particle.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'matrix'
|
2
1
|
require 'securerandom'
|
3
2
|
|
4
3
|
require 'mhl/generic_particle'
|
5
4
|
|
5
|
+
|
6
6
|
module MHL
|
7
7
|
class QuantumParticle < GenericParticle
|
8
8
|
attr_reader :position
|
@@ -10,7 +10,6 @@ module MHL
|
|
10
10
|
# move particle using QPSO - Type II algorithm
|
11
11
|
def move(alpha, mean_best, swarm_attractor)
|
12
12
|
raise 'Particle attractor is nil!' if @attractor.nil?
|
13
|
-
# raise 'Swarm attractor is nil!' if swarm_attractor.nil?
|
14
13
|
|
15
14
|
dimension = @position.size
|
16
15
|
|
@@ -18,21 +17,41 @@ module MHL
|
|
18
17
|
phi = Array.new(dimension) { SecureRandom.random_number }
|
19
18
|
|
20
19
|
# p_i represents the p_{i,n} parameter in [SUN11], formulae 4.82 and 4.83
|
21
|
-
p_i =
|
22
|
-
|
23
|
-
|
20
|
+
p_i = phi.zip(@attractor[:position], swarm_attractor[:position]).map do |phi_j,p_j,g_j|
|
21
|
+
phi_j * p_j + (1.0 - phi_j) * g_j
|
22
|
+
end
|
24
23
|
|
25
24
|
# delta represents the displacement for the current position.
|
26
25
|
# See [SUN11], formula 4.82
|
27
|
-
delta =
|
28
|
-
|
29
|
-
|
26
|
+
delta = @position.zip(mean_best).map do |x_n,c_n|
|
27
|
+
# \alpha * | X_{i,n} - C_n | * log(\frac{1}{u_{i,n+1}})
|
28
|
+
alpha * (x_n - c_n).abs * Math.log(1.0 / SecureRandom.random_number)
|
29
|
+
end
|
30
30
|
|
31
31
|
# update position
|
32
32
|
if SecureRandom.random_number < 0.5
|
33
|
-
@position = p_i +
|
33
|
+
@position = p_i.zip(delta).map {|p_in,delta_n| p_in + delta_n }
|
34
34
|
else
|
35
|
-
@position = p_i -
|
35
|
+
@position = p_i.zip(delta).map {|p_in,delta_n| p_in - delta_n }
|
36
|
+
end
|
37
|
+
|
38
|
+
@position
|
39
|
+
end
|
40
|
+
|
41
|
+
# implement confinement à la SPSO 2011. for more information, see equations
|
42
|
+
# 3.14 of [CLERC12].
|
43
|
+
def remain_within(constraints)
|
44
|
+
@position = @position.map.with_index do |x_j,j|
|
45
|
+
d_max = constraints[:max][j]
|
46
|
+
d_min = constraints[:min][j]
|
47
|
+
if x_j > d_max
|
48
|
+
# puts "resetting #{j}-th position component #{x_j} to #{d_max}"
|
49
|
+
x_j = d_max
|
50
|
+
elsif x_j < d_min
|
51
|
+
# puts "resetting #{j}-th position component #{x_j} to #{d_min}"
|
52
|
+
x_j = d_min
|
53
|
+
end
|
54
|
+
x_j
|
36
55
|
end
|
37
56
|
end
|
38
57
|
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'concurrent'
|
2
|
-
require 'facter'
|
3
2
|
require 'logger'
|
4
|
-
require 'matrix'
|
5
3
|
require 'securerandom'
|
6
4
|
|
7
5
|
require 'mhl/qpso_swarm'
|
@@ -16,18 +14,20 @@ module MHL
|
|
16
14
|
# Classical and Quantum Perspectives", CRC Press, 2011
|
17
15
|
class QuantumPSOSolver
|
18
16
|
|
17
|
+
DEFAULT_SWARM_SIZE = 40
|
18
|
+
|
19
19
|
def initialize(opts={})
|
20
|
-
@swarm_size = opts[:swarm_size].to_i
|
21
|
-
|
22
|
-
|
23
|
-
end
|
20
|
+
@swarm_size = opts[:swarm_size].try(:to_i) || DEFAULT_SWARM_SIZE
|
21
|
+
|
22
|
+
@constraints = opts[:constraints]
|
24
23
|
|
25
24
|
@random_position_func = opts[:random_position_func]
|
26
25
|
|
27
26
|
@start_positions = opts[:start_positions]
|
27
|
+
|
28
28
|
@exit_condition = opts[:exit_condition]
|
29
29
|
|
30
|
-
@pool = Concurrent::FixedThreadPool.new(
|
30
|
+
@pool = Concurrent::FixedThreadPool.new(Concurrent::processor_count * 4)
|
31
31
|
|
32
32
|
case opts[:logger]
|
33
33
|
when :stdout
|
@@ -51,26 +51,40 @@ module MHL
|
|
51
51
|
# object) that accepts the genotype as argument (that is, the set of
|
52
52
|
# parameters) and returns the phenotype (that is, the function result)
|
53
53
|
def solve(func, params={})
|
54
|
-
#
|
55
|
-
if @start_positions
|
56
|
-
|
57
|
-
|
58
|
-
|
54
|
+
# initialize particle positions
|
55
|
+
init_pos = if @start_positions
|
56
|
+
# start positions have the highest priority
|
57
|
+
@start_positions
|
58
|
+
elsif @random_position_func
|
59
|
+
# random_position_func has the second highest priority
|
60
|
+
Array.new(@swarm_size) { @random_position_func.call }
|
61
|
+
elsif @constraints
|
62
|
+
# constraints were given, so we use them to initialize particle
|
63
|
+
# positions. to this end, we adopt the SPSO 2006-2011 random position
|
64
|
+
# initialization algorithm [CLERC12].
|
65
|
+
Array.new(@swarm_size) do
|
66
|
+
min = @constraints[:min]
|
67
|
+
max = @constraints[:max]
|
68
|
+
# randomization is independent along each dimension
|
69
|
+
random_pos = min.zip(max).map do |min_i,max_i|
|
70
|
+
min_i + SecureRandom.random_number * (max_i - min_i)
|
71
|
+
end
|
72
|
+
end
|
59
73
|
else
|
60
|
-
raise
|
61
|
-
# particles = @start_positions.map do |pos|
|
62
|
-
# { position: Vector[*pos] }
|
63
|
-
# end
|
74
|
+
raise ArgumentError, "Not enough information to initialize particle positions!"
|
64
75
|
end
|
65
76
|
|
77
|
+
swarm = QPSOSwarm.new(@swarm_size, init_pos,
|
78
|
+
params.merge(constraints: @constraints))
|
79
|
+
|
66
80
|
# initialize variables
|
67
|
-
|
81
|
+
iter = 0
|
68
82
|
overall_best = nil
|
69
83
|
|
70
84
|
# default behavior is to loop forever
|
71
85
|
begin
|
72
|
-
|
73
|
-
@logger.info "QPSO - Starting
|
86
|
+
iter += 1
|
87
|
+
@logger.info "QPSO - Starting iteration #{iter}" if @logger
|
74
88
|
|
75
89
|
# create latch to control program termination
|
76
90
|
latch = Concurrent::CountDownLatch.new(@swarm_size)
|
@@ -91,7 +105,7 @@ module MHL
|
|
91
105
|
swarm_attractor = swarm.update_attractor
|
92
106
|
|
93
107
|
# print results
|
94
|
-
puts ">
|
108
|
+
puts "> iter #{iter}, best: #{swarm_attractor[:position]}, #{swarm_attractor[:height]}" unless @quiet
|
95
109
|
|
96
110
|
# calculate overall best (that plays the role of swarm attractor)
|
97
111
|
if overall_best.nil?
|
@@ -103,7 +117,7 @@ module MHL
|
|
103
117
|
# mutate swarm
|
104
118
|
swarm.mutate
|
105
119
|
|
106
|
-
end while @exit_condition.nil? or !@exit_condition.call(
|
120
|
+
end while @exit_condition.nil? or !@exit_condition.call(iter, overall_best)
|
107
121
|
|
108
122
|
overall_best
|
109
123
|
end
|
data/lib/mhl/version.rb
CHANGED
data/mhl.gemspec
CHANGED
@@ -19,10 +19,9 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
21
|
spec.add_dependency 'bitstring'
|
22
|
-
spec.add_dependency 'concurrent-ruby', '~> 0
|
22
|
+
spec.add_dependency 'concurrent-ruby', '~> 1.0'
|
23
23
|
spec.add_dependency 'erv'
|
24
|
-
spec.add_dependency 'facter'
|
25
24
|
|
26
|
-
spec.add_development_dependency 'bundler'
|
25
|
+
spec.add_development_dependency 'bundler'
|
27
26
|
spec.add_development_dependency 'rake'
|
28
27
|
end
|
@@ -4,11 +4,12 @@ describe MHL::MultiSwarmQPSOSolver do
|
|
4
4
|
|
5
5
|
it 'should solve a 2-dimension parabola in real space' do
|
6
6
|
solver = MHL::MultiSwarmQPSOSolver.new(
|
7
|
-
:swarm_size => 20,
|
8
7
|
:num_swarms => 4,
|
9
|
-
:
|
10
|
-
|
11
|
-
|
8
|
+
:constraints => {
|
9
|
+
:min => [ -100, -100 ],
|
10
|
+
:max => [ 100, 100 ],
|
11
|
+
},
|
12
|
+
:exit_condition => lambda {|iteration,best| best[:height].abs < 0.001 },
|
12
13
|
:logger => :stdout,
|
13
14
|
:log_level => ENV['DEBUG'] ? Logger::DEBUG : Logger::WARN,
|
14
15
|
)
|
@@ -4,10 +4,11 @@ describe MHL::ParticleSwarmOptimizationSolver do
|
|
4
4
|
|
5
5
|
it 'should solve a 2-dimension parabola in real space' do
|
6
6
|
solver = MHL::ParticleSwarmOptimizationSolver.new(
|
7
|
-
:
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
:constraints => {
|
8
|
+
:min => [ -100, -100 ],
|
9
|
+
:max => [ 100, 100 ],
|
10
|
+
},
|
11
|
+
:exit_condition => lambda {|iteration,best| best[:height].abs < 0.001 },
|
11
12
|
:logger => :stderr,
|
12
13
|
:log_level => ENV['DEBUG'] ? Logger::DEBUG : Logger::WARN,
|
13
14
|
)
|
@@ -4,9 +4,11 @@ describe MHL::QuantumPSOSolver do
|
|
4
4
|
|
5
5
|
it 'should solve a 2-dimension parabola in real space' do
|
6
6
|
solver = MHL::QuantumPSOSolver.new(
|
7
|
-
:
|
8
|
-
|
9
|
-
|
7
|
+
:constraints => {
|
8
|
+
:min => [ -100, -100 ],
|
9
|
+
:max => [ 100, 100 ],
|
10
|
+
},
|
11
|
+
:exit_condition => lambda {|iteration,best| best[:height].abs < 0.001 },
|
10
12
|
:logger => :stderr,
|
11
13
|
:log_level => ENV['DEBUG'] ? Logger::DEBUG : Logger::WARN,
|
12
14
|
)
|
metadata
CHANGED
@@ -1,19 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mhl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mauro Tortonesi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
|
-
- -
|
16
|
+
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
18
|
version: '0'
|
19
19
|
name: bitstring
|
@@ -21,27 +21,27 @@ dependencies:
|
|
21
21
|
type: :runtime
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
|
-
- - ~>
|
30
|
+
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '0
|
32
|
+
version: '1.0'
|
33
33
|
name: concurrent-ruby
|
34
34
|
prerelease: false
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0
|
40
|
+
version: '1.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
|
-
- -
|
44
|
+
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0'
|
47
47
|
name: erv
|
@@ -49,41 +49,27 @@ dependencies:
|
|
49
49
|
type: :runtime
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
|
-
- -
|
58
|
+
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0'
|
61
|
-
name: facter
|
62
|
-
prerelease: false
|
63
|
-
type: :runtime
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - '>='
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
requirement: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - ~>
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '1.3'
|
75
61
|
name: bundler
|
76
62
|
prerelease: false
|
77
63
|
type: :development
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
79
65
|
requirements:
|
80
|
-
- -
|
66
|
+
- - ">="
|
81
67
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
68
|
+
version: '0'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
requirement: !ruby/object:Gem::Requirement
|
85
71
|
requirements:
|
86
|
-
- -
|
72
|
+
- - ">="
|
87
73
|
- !ruby/object:Gem::Version
|
88
74
|
version: '0'
|
89
75
|
name: rake
|
@@ -91,7 +77,7 @@ dependencies:
|
|
91
77
|
type: :development
|
92
78
|
version_requirements: !ruby/object:Gem::Requirement
|
93
79
|
requirements:
|
94
|
-
- -
|
80
|
+
- - ">="
|
95
81
|
- !ruby/object:Gem::Version
|
96
82
|
version: '0'
|
97
83
|
description: A Ruby Metaheuristics library
|
@@ -137,17 +123,17 @@ require_paths:
|
|
137
123
|
- lib
|
138
124
|
required_ruby_version: !ruby/object:Gem::Requirement
|
139
125
|
requirements:
|
140
|
-
- -
|
126
|
+
- - ">="
|
141
127
|
- !ruby/object:Gem::Version
|
142
128
|
version: '0'
|
143
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
144
130
|
requirements:
|
145
|
-
- -
|
131
|
+
- - ">="
|
146
132
|
- !ruby/object:Gem::Version
|
147
133
|
version: '0'
|
148
134
|
requirements: []
|
149
135
|
rubyforge_project:
|
150
|
-
rubygems_version: 2.
|
136
|
+
rubygems_version: 2.6.4
|
151
137
|
signing_key:
|
152
138
|
specification_version: 4
|
153
139
|
summary: A scientific library for Ruby that provides several metaheuristics
|