Skip to content

Instantly share code, notes, and snippets.

@xoolive
Created September 30, 2014 21:16
Show Gist options
  • Save xoolive/d685ec63a80acda860ec to your computer and use it in GitHub Desktop.
Save xoolive/d685ec63a80acda860ec to your computer and use it in GitHub Desktop.
Swarm algorithm visualised in gnuplot
#! /bin/ruby
# swarm algorithm
require 'gnuplot'
class Particule
attr_reader :x, :y
def initialize(size_x, size_y)
@size_x = size_x
@size_y = size_y
@x = rand(@size_x)
@y = rand(@size_y)
@vx = rand(@size_x)/20.to_f
@vy = rand(@size_y)/20.to_f
@ox = @x
@oy = @y
end
def objective(x, y)
(x - @size_x / 2.to_f)**2 + (y - @size_y / 2.to_f)**2
end
def iterate(delta, ogx, ogy, w)
@x += delta * @vx
@y += delta * @vy
@x = -@x if @x < 0
@x = 2 * @size_x - @x if @x > @size_x
@y = -@y if @y < 0
@y = 2 * @size_y - @y if @y > @size_y
if (objective(@x, @y) < objective(@ox, @oy))
@ox = @x
@oy = @y
end
r1 = rand(200) / 200.to_f
r2 = rand(200) / 200.to_f
@vx = w * @vx + r1 * (@ox - @x) / delta + r2 * (ogx - @x) + delta
@vy = w * @vy + r1 * (@oy - @y) / delta + r2 * (ogy - @y) + delta
end
end
class Swarm
def initialize
@delta = 0.5
@w = 1.4
@size = 50
@swarm = []
@size_x = 20
@size_y = 20
@size.times { |i| @swarm.push(Particule.new(@size_x, @size_y)) }
@xg = @swarm.map { |i| i.x }.inject(0) { |sum, i| sum += i } / @size
@yg = @swarm.map { |i| i.y }.inject(0) { |sum, i| sum += i } / @size
@ox = @xg
@oy = @yg
end
def objective(x, y)
(x - @size_x / 2.to_f)**2 + (y - @size_y / 2.to_f)**2
end
def iterate
@swarm.each { |i| i.iterate(@delta, @ox, @oy, @w) }
@xg = @swarm.map { |i| i.x }.inject(0) { |sum, i| sum += i } / @size
@yg = @swarm.map { |i| i.y }.inject(0) { |sum, i| sum += i } / @size
if (objective(@xg, @yg) < objective(@ox, @oy))
@ox = @xg
@oy = @yg
end
@w *= 0.95
end
def go(iter)
Gnuplot.open do |gp|
iter.times do |_|
iterate
x = @swarm.map { |i| i.x }
y = @swarm.map { |i| i.y }
sleep 0.1
Gnuplot::Plot.new( gp ) do |plot|
plot.title "Swarm algorithm"
plot.xrange "[0:20]"
plot.yrange "[0:20]"
plot.data << Gnuplot::DataSet.new( [x, y] ) do |ds|
ds.with = "points"
ds.notitle
end
end
end
end
end
end
Swarm.new.go(100)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment