View Source PSO example
Mix.install([
{:bia, github: "matiascr/bia"},
{:kino, "~> 0.10.0"},
{:kino_vega_lite, "~> 0.1.10"},
{:vega_lite, "~> 0.1.8"},
{:explorer, "~> 0.7.1"}
])Setup
We start by defining aliases for the libraries we'll use for visualizing the PSO
alias VegaLite, as: Vl
require Kino.VegaLite, as: KVlNow, we define a Visualizer module that contains a callback
defmodule Visualizer do
def callback(args) do
widget = args[:opts][:widget]
widget
|> KVl.clear()
widget
|> KVl.push_many(
Enum.map(args[:particles], &GenServer.call(&1, :get_position))
|> Nx.stack()
|> Nx.to_list()
|> Enum.map(fn [x, y] -> %{x: x, y: y} end)
)
Process.sleep(250)
end
endand create it with the parameters we want for the graph
bound_up = 10.0
bound_down = -10.0
widget = fn ->
Vl.new(width: 400, height: 400)
|> Vl.mark(:circle)
|> Vl.encode_field(:x, "x", type: :quantitative, scale: [domain: [bound_down, bound_up]])
|> Vl.encode_field(:y, "y", type: :quantitative, scale: [domain: [bound_down, bound_up]])
|> KVl.new()
|> Kino.render()
endWe add some functions for the PSO to optimize
defmodule OptimizationFunctions do
import Nx.Defn
defn unimodal(t) do
0.26 * (t[0] ** 2 + t[1] ** 2) - 0.48 * t[0] * t[1]
end
defn inverted_pyramid(t) do
Nx.abs(t[0]) + Nx.abs(t[1])
end
endRunning the PSO
Finally, we run the PSO algorithm.
In the first step, we add the parameters of the heuristic, along with other optional parameters for in the callback and widget parameters. These will allow us to inject actions that will be performed after each iteration of the PSO. In this case, we have created a graph, and it will be updated each iteration with the position of the particles.
PSO.new(
population_size: 50,
num_iterations: 20,
bound_up: bound_up,
bound_down: bound_down,
inertia: 0.1,
coeff_p: 2.0,
coeff_g: 1.0,
callback: &Visualizer.callback/1,
widget: widget.(),
fun: &OptimizationFunctions.inverted_pyramid/1
)
|> PSO.run()