mhl 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- Vector[*phi.zip(@attractor[:position]).map {|phi_j,p_j| phi_j * p_j }] +
23
- Vector[*phi.zip(swarm_attractor[:position]).map {|phi_j,g_j| (1.0 - phi_j) * g_j }]
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
- @position.zip(mean_best).map {|x,y| alpha * (x-y).abs }. # \alpha * | X_{i,n} - C_n |
29
- map {|x| x * Math.log(1.0 / SecureRandom.random_number) } # log(\frac{1}{u_{i,n+1}})
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 + Vector[*delta]
33
+ @position = p_i.zip(delta).map {|p_in,delta_n| p_in + delta_n }
34
34
  else
35
- @position = p_i - Vector[*delta]
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
- unless @swarm_size
22
- raise ArgumentError, 'Swarm size is a required parameter!'
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(Facter.value(:processorcount).to_i * 4)
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
- # setup swarm
55
- if @start_positions.nil?
56
- swarm = QPSOSwarm.new(@swarm_size,
57
- Array.new(@swarm_size) { Vector[*@random_position_func.call] },
58
- params)
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 'Unimplemented yet!'
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
- gen = 0
81
+ iter = 0
68
82
  overall_best = nil
69
83
 
70
84
  # default behavior is to loop forever
71
85
  begin
72
- gen += 1
73
- @logger.info "QPSO - Starting generation #{gen}" if @logger
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 "> gen #{gen}, best: #{swarm_attractor[:position]}, #{swarm_attractor[:height]}" unless @quiet
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(gen, overall_best)
120
+ end while @exit_condition.nil? or !@exit_condition.call(iter, overall_best)
107
121
 
108
122
  overall_best
109
123
  end
@@ -1,3 +1,3 @@
1
1
  module MHL
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -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.5'
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', '~> 1.3'
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
- :random_position_func => lambda { Array.new(2) { rand(20).to_f } },
10
- :random_velocity_func => lambda { Array.new(2) { rand(10).to_f } },
11
- :exit_condition => lambda {|generation,best_sample| best_sample[:height].abs < 0.001 },
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
- :swarm_size => 40,
8
- :random_position_func => lambda { Array.new(2) { rand(20) } },
9
- :random_velocity_func => lambda { Array.new(2) { rand(10) } },
10
- :exit_condition => lambda {|generation,best_sample| best_sample[:height].abs < 0.001 },
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
- :swarm_size => 40,
8
- :random_position_func => lambda { Array.new(2) { rand(20) } },
9
- :exit_condition => lambda {|generation,best_sample| best_sample[:height].abs < 0.001 },
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.1.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: 2014-12-19 00:00:00.000000000 Z
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.5'
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.5'
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: '1.3'
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.1.9
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