Class: MHL::QuantumPSOSolver
- Inherits:
-
Object
- Object
- MHL::QuantumPSOSolver
- Defined in:
- lib/mhl/quantum_particle_swarm_optimization_solver.rb
Overview
This solver implements the QPSO Type 2 algorithm.
For more information, refer to equation 4.82 of:
- SUN11
-
Jun Sun, Choi-Hong Lai, Xiao-Jun Wu, “Particle Swarm Optimisation:
Classical and Quantum Perspectives“, CRC Press, 2011
Constant Summary collapse
- DEFAULT_SWARM_SIZE =
40
Instance Method Summary collapse
-
#initialize(opts = {}) ⇒ QuantumPSOSolver
constructor
A new instance of QuantumPSOSolver.
-
#solve(func, params = {}) ⇒ Object
This is the method that solves the optimization problem.
Constructor Details
#initialize(opts = {}) ⇒ QuantumPSOSolver
Returns a new instance of QuantumPSOSolver.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/mhl/quantum_particle_swarm_optimization_solver.rb', line 19 def initialize(opts={}) @swarm_size = opts[:swarm_size].try(:to_i) || DEFAULT_SWARM_SIZE @constraints = opts[:constraints] @random_position_func = opts[:random_position_func] @start_positions = opts[:start_positions] @exit_condition = opts[:exit_condition] case opts[:logger] when :stdout @logger = Logger.new(STDOUT) when :stderr @logger = Logger.new(STDERR) else @logger = opts[:logger] end @quiet = opts[:quiet] if @logger @logger.level = (opts[:log_level] or :warn) end end |
Instance Method Details
#solve(func, params = {}) ⇒ Object
This is the method that solves the optimization problem
Parameter func is supposed to be a method (or a Proc, a lambda, or any callable object) that accepts the genotype as argument (that is, the set of parameters) and returns the phenotype (that is, the function result)
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/mhl/quantum_particle_swarm_optimization_solver.rb', line 51 def solve(func, params={}) # initialize particle positions init_pos = if @start_positions # start positions have the highest priority @start_positions elsif @random_position_func # random_position_func has the second highest priority Array.new(@swarm_size) { @random_position_func.call } elsif @constraints # constraints were given, so we use them to initialize particle # positions. to this end, we adopt the SPSO 2006-2011 random position # initialization algorithm [CLERC12]. Array.new(@swarm_size) do min = @constraints[:min] max = @constraints[:max] # randomization is independent along each dimension min.zip(max).map do |min_i,max_i| min_i + SecureRandom.random_number * (max_i - min_i) end end else raise ArgumentError, "Not enough information to initialize particle positions!" end swarm = QPSOSwarm.new(size: @swarm_size, initial_positions: init_pos, constraints: @constraints, logger: @logger) # initialize variables iter = 0 overall_best = nil # default behavior is to loop forever begin iter += 1 @logger.info "QPSO - Starting iteration #{iter}" if @logger if params[:concurrent] # the function to optimize is thread safe: call it multiple times in # a concurrent fashion # to this end, we use the high level promise-based construct # recommended by the authors of ruby's (fantastic) concurrent gem promises = swarm.map do |particle| Concurrent::Promise.execute do # evaluate target function particle.evaluate(func) end end # wait for all the spawned threads to finish promises.map(&:wait) else # the function to optimize is not thread safe: call it multiple times # in a sequential fashion swarm.each do |particle| # evaluate target function particle.evaluate(func) end end # get swarm attractor (the highest particle) swarm_attractor = swarm.update_attractor # print results if @logger and !@quiet @logger.info "> iter #{iter}, best: #{swarm_attractor[:position]}, #{swarm_attractor[:height]}" end # calculate overall best (that plays the role of swarm attractor) if overall_best.nil? overall_best = swarm_attractor else overall_best = [ overall_best, swarm_attractor ].max_by {|x| x[:height] } end # mutate swarm swarm.mutate end while @exit_condition.nil? or !@exit_condition.call(iter, overall_best) overall_best end |