Task: Particle swarm optimization




Go: package main

import (
    "fmt"
    "math"
    "math/rand"
    "time"
)

type ff = func([]float64) float64

type parameters struct{ omega, phip, phig float64 }

type state struct {
    iter       int
    gbpos      []float64
    gbval      float64
    min        []float64
    max        []float64
    params     parameters
    pos        [][]float64
    vel        [][]float64
    bpos       [][]float64
    bval       []float64
    nParticles int
    nDims      int
}

func (s state) report(testfunc string) {
    fmt.Println("Test Function        :", testfunc)
    fmt.Println("Iterations           :", s.iter)
    fmt.Println("Global Best Position :", s.gbpos)
    fmt.Println("Global Best Value    :", s.gbval)
}

func psoInit(min, max []float64, params parameters, nParticles int) *state {
    nDims := len(min)
    pos := make([][]float64, nParticles)
    vel := make([][]float64, nParticles)
    bpos := make([][]float64, nParticles)
    bval := make([]float64, nParticles)
    for i := 0; i < nParticles; i++ {
        pos[i] = min
        vel[i] = make([]float64, nDims)
        bpos[i] = min
        bval[i] = math.Inf(1)
    }
    iter := 0
    gbpos := make([]float64, nDims)
    for i := 0; i < nDims; i++ {
        gbpos[i] = math.Inf(1)
    }
    gbval := math.Inf(1)
    return &state{iter, gbpos, gbval, min, max, params,
        pos, vel, bpos, bval, nParticles, nDims}
}

func pso(fn ff, y *state) *state {
    p := y.params
    v := make([]float64, y.nParticles)
    bpos := make([][]float64, y.nParticles)
    bval := make([]float64, y.nParticles)
    gbpos := make([]float64, y.nDims)
    gbval := math.Inf(1)
    for j := 0; j < y.nParticles; j++ {
        
        v[j] = fn(y.pos[j])
        
        if v[j] < y.bval[j] {
            bpos[j] = y.pos[j]
            bval[j] = v[j]
        } else {
            bpos[j] = y.bpos[j]
            bval[j] = y.bval[j]
        }
        if bval[j] < gbval {
            gbval = bval[j]
            gbpos = bpos[j]
        }
    }
    rg := rand.Float64()
    pos := make([][]float64, y.nParticles)
    vel := make([][]float64, y.nParticles)
    for j := 0; j < y.nParticles; j++ {
        pos[j] = make([]float64, y.nDims)
        vel[j] = make([]float64, y.nDims)
        
        rp := rand.Float64()
        ok := true
        for z := 0; z < y.nDims; z++ {
            pos[j][z] = 0
            vel[j][z] = 0
        }
        for k := 0; k < y.nDims; k++ {
            vel[j][k] = p.omega*y.vel[j][k] +
                p.phip*rp*(bpos[j][k]-y.pos[j][k]) +
                p.phig*rg*(gbpos[k]-y.pos[j][k])
            pos[j][k] = y.pos[j][k] + vel[j][k]
            ok = ok && y.min[k] < pos[j][k] && y.max[k] > pos[j][k]
        }
        if !ok {
            for k := 0; k < y.nDims; k++ {
                pos[j][k] = y.min[k] + (y.max[k]-y.min[k])*rand.Float64()
            }
        }
    }
    iter := 1 + y.iter
    return &state{iter, gbpos, gbval, y.min, y.max, y.params,
        pos, vel, bpos, bval, y.nParticles, y.nDims}
}

func iterate(fn ff, n int, y *state) *state {
    r := y
    for i := 0; i < n; i++ {
        r = pso(fn, r)
    }
    return r
}

func mccormick(x []float64) float64 {
    a, b := x[0], x[1]
    return math.Sin(a+b) + (a-b)*(a-b) + 1.0 + 2.5*b - 1.5*a
}

func michalewicz(x []float64) float64 {
    m := 10.0
    sum := 0.0
    for i := 1; i <= len(x); i++ {
        j := x[i-1]
        k := math.Sin(float64(i) * j * j / math.Pi)
        sum += math.Sin(j) * math.Pow(k, 2*m)
    }
    return -sum
}

func main() {
    rand.Seed(time.Now().UnixNano())
    st := psoInit(
        []float64{-1.5, -3.0},
        []float64{4.0, 4.0},
        parameters{0.0, 0.6, 0.3},
        100,
    )
    st = iterate(mccormick, 40, st)
    st.report("McCormick")
    fmt.Println("f(-.54719, -1.54719) :", mccormick([]float64{-.54719, -1.54719}))
    fmt.Println()
    st = psoInit(
        []float64{0.0, 0.0},
        []float64{math.Pi, math.Pi},
        parameters{0.3, 0.3, 0.3},
        1000,
    )
    st = iterate(michalewicz, 30, st)
    st.report("Michalewicz (2D)")
    fmt.Println("f(2.20, 1.57)        :", michalewicz([]float64{2.2, 1.57}))




Python: import math
import random

INFINITY = 1 << 127
MAX_INT = 1 << 31

class Parameters:
    def __init__(self, omega, phip, phig):
        self.omega = omega
        self.phip = phip
        self.phig = phig

class State:
    def __init__(self, iter, gbpos, gbval, min, max, parameters, pos, vel, bpos, bval, nParticles, nDims):
        self.iter = iter
        self.gbpos = gbpos
        self.gbval = gbval
        self.min = min
        self.max = max
        self.parameters = parameters
        self.pos = pos
        self.vel = vel
        self.bpos = bpos
        self.bval = bval
        self.nParticles = nParticles
        self.nDims = nDims

    def report(self, testfunc):
        print "Test Function :", testfunc
        print "Iterations    :", self.iter
        print "Global Best Position :", self.gbpos
        print "Global Best Value    : %.16f" % self.gbval

def uniform01():
    v = random.random()
    assert 0.0 <= v and v < 1.0
    return v

def psoInit(min, max, parameters, nParticles):
    nDims = len(min)
    pos = [min[:]] * nParticles
    vel = [[0.0] * nDims] * nParticles
    bpos = [min[:]] * nParticles
    bval = [INFINITY] * nParticles
    iter = 0
    gbpos = [INFINITY] * nDims
    gbval = INFINITY
    return State(iter, gbpos, gbval, min, max, parameters, pos, vel, bpos, bval, nParticles, nDims);

def pso(fn, y):
    p = y.parameters
    v = [0.0] * (y.nParticles)
    bpos = [y.min[:]] * (y.nParticles)
    bval = [0.0] * (y.nParticles)
    gbpos = [0.0] * (y.nDims)
    gbval = INFINITY
    for j in xrange(0, y.nParticles):
        
        v[j] = fn(y.pos[j])
        
        if v[j] < y.bval[j]:
            bpos[j] = y.pos[j][:]
            bval[j] = v[j]
        else:
            bpos[j] = y.bpos[j][:]
            bval[j] = y.bval[j]
        if bval[j] < gbval:
            gbval = bval[j]
            gbpos = bpos[j][:]
    rg = uniform01()
    pos = [[None] * (y.nDims)] * (y.nParticles)
    vel = [[None] * (y.nDims)] * (y.nParticles)
    for j in xrange(0, y.nParticles):
        
        rp = uniform01()
        ok = True
        vel[j] = [0.0] * (len(vel[j]))
        pos[j] = [0.0] * (len(pos[j]))
        for k in xrange(0, y.nDims):
            vel[j][k] = p.omega * y.vel[j][k] \
                      + p.phip * rp * (bpos[j][k] - y.pos[j][k]) \
                      + p.phig * rg * (gbpos[k] - y.pos[j][k])
            pos[j][k] = y.pos[j][k] + vel[j][k]
            ok = ok and y.min[k] < pos[j][k] and y.max[k] > pos[j][k]
        if not ok:
            for k in xrange(0, y.nDims):
                pos[j][k] = y.min[k] + (y.max[k] - y.min[k]) * uniform01()
    iter = 1 + y.iter
    return State(iter, gbpos, gbval, y.min, y.max, y.parameters, pos, vel, bpos, bval, y.nParticles, y.nDims);

def iterate(fn, n, y):
    r = y
    old = y
    if n == MAX_INT:
        while True:
            r = pso(fn, r)
            if r == old:
                break
            old = r
    else:
        for _ in xrange(0, n):
            r = pso(fn, r)
    return r

def mccormick(x):
    (a, b) = x
    return math.sin(a + b) + (a - b) * (a - b) + 1.0 + 2.5 * b - 1.5 * a

def michalewicz(x):
    m = 10
    d = len(x)
    sum = 0.0
    for i in xrange(1, d):
        j = x[i - 1]
        k = math.sin(i * j * j / math.pi)
        sum += math.sin(j) * k ** (2.0 * m)
    return -sum

def main():
    state = psoInit([-1.5, -3.0], [4.0, 4.0], Parameters(0.0, 0.6, 0.3), 100)
    state = iterate(mccormick, 40, state)
    state.report("McCormick")
    print "f(-.54719, -1.54719) : %.16f" % (mccormick([-.54719, -1.54719]))

    print

    state = psoInit([0.0, 0.0], [math.pi, math.pi], Parameters(0.3, 0.3, 0.3), 1000)
    state = iterate(michalewicz, 30, state)
    state.report("Michalewicz (2D)")
    print "f(2.20, 1.57)        : %.16f" % (michalewicz([2.2, 1.57]))

main()