ga: implement SOMA T3A algorithm
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
f4f5f366e9
commit
74109521b0
28
algo/ga/error.go
Normal file
28
algo/ga/error.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2023 wanderer <a_mirre at utb dot cz>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package ga
|
||||||
|
|
||||||
|
type gaError struct {
|
||||||
|
s string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errGenerationsIsZero = newGAError("Generations cannot be 0")
|
||||||
|
errBenchMinItersIsLTOne = newGAError("Minimum bench iterations cannot be less than 1")
|
||||||
|
errNPIsZero = newGAError("NP cannot be 0")
|
||||||
|
errKIsZero = newGAError("K cannot be 0")
|
||||||
|
errMIsZero = newGAError("M cannot be 0")
|
||||||
|
errNIsZero = newGAError("N cannot be 0")
|
||||||
|
errNjumpsIsZero = newGAError("Njumps cannot be 0")
|
||||||
|
errDimensionsUnset = newGAError("Dimensions cannot be unset")
|
||||||
|
errBenchUnset = newGAError("Bench cannot be unset")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *gaError) Error() string {
|
||||||
|
return e.s
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGAError(text string) error {
|
||||||
|
return &gaError{s: text}
|
||||||
|
}
|
@ -4,7 +4,12 @@
|
|||||||
package ga
|
package ga
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.dotya.ml/wanderer/math-optim/bench/cec2020"
|
||||||
"git.dotya.ml/wanderer/math-optim/stats"
|
"git.dotya.ml/wanderer/math-optim/stats"
|
||||||
|
"golang.org/x/exp/rand"
|
||||||
"gonum.org/v1/gonum/stat/distuv"
|
"gonum.org/v1/gonum/stat/distuv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,6 +26,17 @@ type SOMAT3A struct {
|
|||||||
Dimensions []int
|
Dimensions []int
|
||||||
// NP is the initial population size.
|
// NP is the initial population size.
|
||||||
NP int
|
NP int
|
||||||
|
// K is the number of individuals to choose the leader from.
|
||||||
|
K int
|
||||||
|
// M denotes how many individuals are picked from the population to form a
|
||||||
|
// `team` during the organisation phase, can be thought of as "team size".
|
||||||
|
M int
|
||||||
|
// N is the number of best individuals in each team selected for actual
|
||||||
|
// migration.
|
||||||
|
N int
|
||||||
|
// Njumps is the fixed number of jumps that each chosen migrating
|
||||||
|
// individual performs on their way to the leader.
|
||||||
|
Njumps int
|
||||||
// BenchName is the human-friendly name of the benchmarking function.
|
// BenchName is the human-friendly name of the benchmarking function.
|
||||||
BenchName string
|
BenchName string
|
||||||
// ch is a channel for writing back computed results.
|
// ch is a channel for writing back computed results.
|
||||||
@ -34,3 +50,230 @@ type SOMAT3A struct {
|
|||||||
// initialised denotes the initialisation state of the struct.
|
// initialised denotes the initialisation state of the struct.
|
||||||
initialised bool
|
initialised bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var somat3aLogger = newLogger(" *** SOMA T3A")
|
||||||
|
|
||||||
|
// Init performs checks on the input params and initialises an instance of
|
||||||
|
// SOMAT3A.
|
||||||
|
func (s *SOMAT3A) Init(
|
||||||
|
generations, benchMinIters, np, k, m, n, njumps int,
|
||||||
|
dimensions []int,
|
||||||
|
bench string,
|
||||||
|
ch chan []stats.Stats,
|
||||||
|
chAlgoMeans chan *stats.AlgoBenchMean,
|
||||||
|
) error {
|
||||||
|
switch {
|
||||||
|
case generations == 0:
|
||||||
|
return errGenerationsIsZero
|
||||||
|
|
||||||
|
case generations == -1:
|
||||||
|
somat3aLogger.Println("Generations is '-1', disabling generation limits")
|
||||||
|
|
||||||
|
case benchMinIters < 1:
|
||||||
|
return errBenchMinItersIsLTOne
|
||||||
|
|
||||||
|
case np == 0:
|
||||||
|
return errNPIsZero
|
||||||
|
|
||||||
|
case k == 0:
|
||||||
|
return errKIsZero
|
||||||
|
|
||||||
|
case m == 0:
|
||||||
|
return errMIsZero
|
||||||
|
|
||||||
|
case n == 0:
|
||||||
|
return errNIsZero
|
||||||
|
|
||||||
|
case njumps == 0:
|
||||||
|
return errNjumpsIsZero
|
||||||
|
|
||||||
|
case len(dimensions) == 0:
|
||||||
|
return errDimensionsUnset
|
||||||
|
|
||||||
|
case bench == "":
|
||||||
|
return errBenchUnset
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Generations = generations
|
||||||
|
s.BenchMinIters = benchMinIters
|
||||||
|
s.NP = np
|
||||||
|
s.K = k
|
||||||
|
s.M = m
|
||||||
|
s.N = n
|
||||||
|
s.Njumps = njumps
|
||||||
|
|
||||||
|
s.Dimensions = dimensions
|
||||||
|
s.BenchName = bench
|
||||||
|
s.ch = ch
|
||||||
|
s.chAlgoMeans = chAlgoMeans
|
||||||
|
|
||||||
|
s.initialised = true
|
||||||
|
|
||||||
|
gaLogger.Printf("%s init done for bench %s", s.getAlgoName(), s.BenchName)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run runs the SOMA T3A algo for each of `s.Dimensions` with benchmarking
|
||||||
|
// function `s.BenchName`, repeats the run `s.BenchMinIters` times and returns
|
||||||
|
// the stats via chans.
|
||||||
|
func (s *SOMAT3A) Run() {
|
||||||
|
if !s.initialised {
|
||||||
|
somat3aLogger.Fatalln(s.getAlgoName(), "needs to be initialised before calling Run(), exiting..")
|
||||||
|
}
|
||||||
|
|
||||||
|
var somat3aStats []stats.Stats
|
||||||
|
// testing purposes.
|
||||||
|
// s.BenchMinIters = 5
|
||||||
|
|
||||||
|
somat3aMeans := &stats.AlgoBenchMean{
|
||||||
|
Algo: s.getAlgoName(),
|
||||||
|
BenchMeans: make([]stats.BenchMean, 0, len(s.Dimensions)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, dim := range s.Dimensions {
|
||||||
|
maxFES := cec2020.GetMaxFES(dim)
|
||||||
|
// TODO(me): check the slides for the formula to calculate this.
|
||||||
|
// 4 fes per member per njump.
|
||||||
|
// fesPerIter := int(float64(maxFES / (4 * s.NP * s.Njumps)))
|
||||||
|
fesPerIter := int(float64(maxFES / (4 * s.NP)))
|
||||||
|
somat3aStatDimX := &stats.Stats{
|
||||||
|
Algo: s.getAlgoName(),
|
||||||
|
Dimens: dim,
|
||||||
|
Iterations: s.BenchMinIters,
|
||||||
|
Generations: maxFES,
|
||||||
|
NP: s.NP,
|
||||||
|
}
|
||||||
|
funcStats := &stats.FuncStats{BenchName: s.BenchName}
|
||||||
|
dimXMean := &stats.BenchMean{
|
||||||
|
Bench: s.BenchName,
|
||||||
|
Dimens: dim,
|
||||||
|
Iterations: s.BenchMinIters,
|
||||||
|
Generations: maxFES,
|
||||||
|
Neighbours: -1,
|
||||||
|
}
|
||||||
|
uniDist := distuv.Uniform{
|
||||||
|
Min: cec2020.SearchRange.Min(),
|
||||||
|
Max: cec2020.SearchRange.Max(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxFES == -1 {
|
||||||
|
somat3aLogger.Fatalf("could not get maxFES for current dim (%d), bailing", dim)
|
||||||
|
}
|
||||||
|
|
||||||
|
somat3aLogger.Printf("running bench \"%s\" for %dD, maxFES: %d\n",
|
||||||
|
s.BenchName, dim, maxFES,
|
||||||
|
)
|
||||||
|
|
||||||
|
funcStats.BenchResults = make([]stats.BenchRound, s.BenchMinIters)
|
||||||
|
|
||||||
|
// rand.Seed(uint64(time.Now().UnixNano()))
|
||||||
|
// create and seed a source of pseudo-randomness
|
||||||
|
src := rand.NewSource(uint64(rand.Int63()))
|
||||||
|
|
||||||
|
// track execution duration.
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
for iter := 0; iter < s.BenchMinIters; iter++ {
|
||||||
|
somat3aLogger.Printf("run: %d, bench: %s, %dD, started at %s",
|
||||||
|
iter, s.BenchName, dim, start,
|
||||||
|
)
|
||||||
|
|
||||||
|
funcStats.BenchResults[iter].Iteration = iter
|
||||||
|
|
||||||
|
uniDist.Src = src
|
||||||
|
// uniDist.Src = rand.NewSource(uint64(rand.Int63()))
|
||||||
|
|
||||||
|
// create a population with known params.
|
||||||
|
pop := newSOMAT3APopulation(s.BenchName, s.NP, s.K, s.M, s.N, s.Njumps, dim)
|
||||||
|
|
||||||
|
// set population seed.
|
||||||
|
pop.Seed = uint64(time.Now().UnixNano())
|
||||||
|
// initialise the population.
|
||||||
|
pop.Init()
|
||||||
|
|
||||||
|
bestResult := s.evaluate(pop)
|
||||||
|
|
||||||
|
// the core.
|
||||||
|
for i := 0; i < fesPerIter; i++ {
|
||||||
|
funcStats.BenchResults[iter].Results = append(
|
||||||
|
funcStats.BenchResults[iter].Results,
|
||||||
|
bestResult,
|
||||||
|
)
|
||||||
|
|
||||||
|
// call evolve where the inner workngs of SOMA T3A run.
|
||||||
|
s.evolve(pop)
|
||||||
|
|
||||||
|
// take measurements of current population fitness.
|
||||||
|
r := s.evaluate(pop)
|
||||||
|
|
||||||
|
// save if better.
|
||||||
|
if r < bestResult {
|
||||||
|
bestResult = r
|
||||||
|
}
|
||||||
|
|
||||||
|
// this block makes sure we properly count func evaluations for
|
||||||
|
// the purpose of correctly comparable plot comparison. i.e.
|
||||||
|
// append the winning (current best) value 4*NP-1 (the first
|
||||||
|
// best is already saved at this point) times to represent the
|
||||||
|
// fact that while evaluating (and comparing) other population
|
||||||
|
// individuals to the current best value is taking place in the
|
||||||
|
// background, the current best value itself is kept around and
|
||||||
|
// symbolically saved as the best of the Generation.
|
||||||
|
for x := 0; x < 4*s.NP-1; x++ {
|
||||||
|
funcStats.BenchResults[iter].Results = append(
|
||||||
|
funcStats.BenchResults[iter].Results,
|
||||||
|
bestResult,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
|
||||||
|
somat3aLogger.Printf("completed: bench: %s, %dD, computing took %s\n",
|
||||||
|
s.BenchName, dim, elapsed,
|
||||||
|
)
|
||||||
|
|
||||||
|
// get mean vals.
|
||||||
|
dimXMean.MeanVals = stats.GetMeanVals(funcStats.BenchResults, maxFES)
|
||||||
|
funcStats.MeanVals = dimXMean.MeanVals
|
||||||
|
|
||||||
|
somat3aStatDimX.BenchFuncStats = append(
|
||||||
|
somat3aStatDimX.BenchFuncStats, *funcStats,
|
||||||
|
)
|
||||||
|
|
||||||
|
somat3aStats = append(somat3aStats, *somat3aStatDimX)
|
||||||
|
|
||||||
|
somat3aMeans.BenchMeans = append(somat3aMeans.BenchMeans, *dimXMean)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(somat3aMeans)
|
||||||
|
|
||||||
|
s.chAlgoMeans <- somat3aMeans
|
||||||
|
s.ch <- somat3aStats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SOMAT3A) evaluate(pop *SOMAT3APopulation) float64 {
|
||||||
|
bestIndividual := pop.Population[pop.GetBestIdx()]
|
||||||
|
|
||||||
|
return pop.ProblemFunc(bestIndividual.CurX)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SOMAT3A) evolve(pop *SOMAT3APopulation) {
|
||||||
|
// organise.
|
||||||
|
leader, migrants := pop.organise()
|
||||||
|
// migrate.
|
||||||
|
pop.migrate(leader, migrants)
|
||||||
|
// actualise (position, best values..).
|
||||||
|
pop.actualise(migrants)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SOMAT3A) getAlgoName() string {
|
||||||
|
return "SOMA T3A"
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSOMAT3A returns a pointer to a new, uninitialised SOMAT3A instance.
|
||||||
|
func NewSOMAT3A() *SOMAT3A {
|
||||||
|
return &SOMAT3A{}
|
||||||
|
}
|
||||||
|
31
algo/ga/somat3aActualisation.go
Normal file
31
algo/ga/somat3aActualisation.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright 2023 wanderer <a_mirre at utb dot cz>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package ga
|
||||||
|
|
||||||
|
func (p *SOMAT3APopulation) actualise(migrants []int) {
|
||||||
|
f := p.ProblemFunc
|
||||||
|
|
||||||
|
for _, i := range migrants {
|
||||||
|
bestJump := p.Population[i].Jumps[0]
|
||||||
|
|
||||||
|
for j := 1; j < p.Njumps; j++ {
|
||||||
|
jump := p.Population[i].Jumps[j]
|
||||||
|
|
||||||
|
// incrementing fes for the following is done in
|
||||||
|
// somat3aMigration.go.
|
||||||
|
if f(jump) < f(bestJump) {
|
||||||
|
bestJump = jump
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f(bestJump) < f(p.Population[i].CurX) {
|
||||||
|
p.Population[i].CurX = bestJump
|
||||||
|
}
|
||||||
|
|
||||||
|
p.fes += 2
|
||||||
|
|
||||||
|
// clean jump history
|
||||||
|
p.Population[i].Jumps = nil
|
||||||
|
}
|
||||||
|
}
|
80
algo/ga/somat3aMigration.go
Normal file
80
algo/ga/somat3aMigration.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2023 wanderer <a_mirre at utb dot cz>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package ga
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.dotya.ml/wanderer/math-optim/bench/cec2020"
|
||||||
|
)
|
||||||
|
|
||||||
|
// migration is used in SOMA-type algos.
|
||||||
|
|
||||||
|
func (p *SOMAT3APopulation) migrate(leader int, migrants []int) {
|
||||||
|
for _, i := range migrants {
|
||||||
|
jumps := make([][]float64, p.Njumps)
|
||||||
|
|
||||||
|
// jump zero.
|
||||||
|
// jumps[0] = p.jump(i, leader, getStep(0, maxFES))
|
||||||
|
|
||||||
|
// bestJump of this migrant is now the jump zero.
|
||||||
|
// bestJump := jumps[0]
|
||||||
|
|
||||||
|
for j := 0; j < p.Njumps; j++ {
|
||||||
|
step := p.getStep()
|
||||||
|
jump := p.jump(i, leader, step)
|
||||||
|
|
||||||
|
p.fes += 2
|
||||||
|
|
||||||
|
jumps[j] = jump
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Population[i].Jumps = jumps
|
||||||
|
|
||||||
|
p.Population[i].PRTVector = p.getPrtVector()
|
||||||
|
}
|
||||||
|
|
||||||
|
p.PRT = p.getPrt()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SOMAT3APopulation) jump(migrant, leader int, step float64) []float64 {
|
||||||
|
m := p.Population[migrant]
|
||||||
|
l := p.Population[leader]
|
||||||
|
prtv := m.PRTVector
|
||||||
|
t := step
|
||||||
|
jumpPosition := make([]float64, len(m.CurX))
|
||||||
|
|
||||||
|
for i := range m.CurX {
|
||||||
|
jumpPosition[i] = m.CurX[i] + ((l.CurX[i] - m.CurX[i]) * t * prtv[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return jumpPosition
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPrtVector creates and returns the perturbation vector.
|
||||||
|
func (p *SOMAT3APopulation) getPrtVector() []float64 {
|
||||||
|
prtv := make([]float64, p.Dimen)
|
||||||
|
|
||||||
|
for i := range prtv {
|
||||||
|
r := p.zeroToOneRNG.Rand()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case r < p.PRT:
|
||||||
|
prtv[i] = 1
|
||||||
|
|
||||||
|
case r > p.PRT:
|
||||||
|
prtv[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prtv
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPrt calculates the adaptive PRT.
|
||||||
|
func (p *SOMAT3APopulation) getPrt() float64 {
|
||||||
|
return 0.05 + 0.9*float64(p.fes/cec2020.GetMaxFES(p.Dimen))
|
||||||
|
}
|
||||||
|
|
||||||
|
// getStep calculates the step size.
|
||||||
|
func (p *SOMAT3APopulation) getStep() float64 {
|
||||||
|
return 0.15 + 0.08*float64(p.fes/cec2020.GetMaxFES(p.Dimen))
|
||||||
|
}
|
76
algo/ga/somat3aOrganisation.go
Normal file
76
algo/ga/somat3aOrganisation.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// Copyright 2023 wanderer <a_mirre at utb dot cz>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package ga
|
||||||
|
|
||||||
|
import "golang.org/x/exp/rand"
|
||||||
|
|
||||||
|
func (p *SOMAT3APopulation) organise() (int, []int) {
|
||||||
|
leader := p.selectLeader()
|
||||||
|
migrants := p.selectMigrants(leader)
|
||||||
|
|
||||||
|
return leader, migrants
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SOMAT3APopulation) selectMigrants(leader int) []int {
|
||||||
|
m := make([]int, p.M)
|
||||||
|
n := make([]int, p.N)
|
||||||
|
popCount := len(p.Population)
|
||||||
|
|
||||||
|
m[0] = rand.Intn(popCount)
|
||||||
|
|
||||||
|
for i := 1; i < p.M; i++ {
|
||||||
|
mgen:
|
||||||
|
candidateM := rand.Intn(popCount)
|
||||||
|
|
||||||
|
for _, v := range m {
|
||||||
|
if candidateM == v {
|
||||||
|
goto mgen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m[i] = candidateM
|
||||||
|
}
|
||||||
|
|
||||||
|
n[0] = rand.Intn(p.M)
|
||||||
|
|
||||||
|
for i := 1; i < p.N; i++ {
|
||||||
|
ngen:
|
||||||
|
candidateN := rand.Intn(p.M)
|
||||||
|
|
||||||
|
for _, v := range n {
|
||||||
|
if candidateN == v || candidateN == leader {
|
||||||
|
goto ngen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n[i] = candidateN
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SOMAT3APopulation) selectLeader() int {
|
||||||
|
k := make([]int, p.K)
|
||||||
|
popCount := len(p.Population)
|
||||||
|
|
||||||
|
k[0] = rand.Intn(popCount)
|
||||||
|
|
||||||
|
for i := 1; i < p.K; i++ {
|
||||||
|
kgen:
|
||||||
|
candidate := rand.Intn(popCount)
|
||||||
|
|
||||||
|
for _, v := range k {
|
||||||
|
if candidate == v {
|
||||||
|
goto kgen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
k[i] = candidate
|
||||||
|
}
|
||||||
|
|
||||||
|
// choose one of K to become the leader.
|
||||||
|
leader := k[rand.Intn(p.K)]
|
||||||
|
|
||||||
|
return leader
|
||||||
|
}
|
174
algo/ga/somat3aPopulation.go
Normal file
174
algo/ga/somat3aPopulation.go
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
// Copyright 2023 wanderer <a_mirre at utb dot cz>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
package ga
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.dotya.ml/wanderer/math-optim/bench/cec2020"
|
||||||
|
"golang.org/x/exp/rand"
|
||||||
|
|
||||||
|
"gonum.org/v1/gonum/stat/distuv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PopulationIndividual represents a single population individual.
|
||||||
|
type SOMAT3APopulationIndividual struct {
|
||||||
|
CurX DecisionVector
|
||||||
|
PRTVector []float64
|
||||||
|
Jumps [][]float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChampionIndividual is a representation of the best individual currently
|
||||||
|
// available in the population.
|
||||||
|
type SOMAT3AChampionIndividual struct {
|
||||||
|
X DecisionVector
|
||||||
|
}
|
||||||
|
|
||||||
|
// Population groups population individuals (agents) with metadata about the population.
|
||||||
|
type SOMAT3APopulation struct {
|
||||||
|
// Population is a slice of population individuals.
|
||||||
|
Population []SOMAT3APopulationIndividual
|
||||||
|
// Champion represents the best individual of the population.
|
||||||
|
Champion SOMAT3AChampionIndividual
|
||||||
|
// Problem is the current benchmarking function this population is attempting to optimise.
|
||||||
|
Problem string
|
||||||
|
// ProblemFunction is the actual function to optimise.
|
||||||
|
ProblemFunc func([]float64) float64
|
||||||
|
// Dimen is the dimensionality of the problem being optimised.
|
||||||
|
Dimen int
|
||||||
|
// fes is the current number of function evaluations.
|
||||||
|
fes int
|
||||||
|
// Seed is the value used to (re)init population.
|
||||||
|
Seed uint64
|
||||||
|
zeroToOneRNG distuv.Uniform
|
||||||
|
|
||||||
|
// PRT is the perturbation parameter.
|
||||||
|
PRT float64
|
||||||
|
// K is the number of individuals to choose the leader from.
|
||||||
|
K int
|
||||||
|
// M denotes how many individuals are picked from the population to form a
|
||||||
|
// `team` during the organisation phase, can be thought of as "team size".
|
||||||
|
M int
|
||||||
|
// N is the number of best individuals in each team selected for actual
|
||||||
|
// migration.
|
||||||
|
N int
|
||||||
|
// Njumps is the fixed number of jumps that each chosen migrating
|
||||||
|
// individual performs on their way to the leader.
|
||||||
|
Njumps int
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIndividual returns a reference to individual at position n.
|
||||||
|
func (p *SOMAT3APopulation) GetIndividual(n uint) *PopulationIndividual {
|
||||||
|
return &PopulationIndividual{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBestIdx returns the index of the best population individual.
|
||||||
|
func (p *SOMAT3APopulation) GetBestIdx() int {
|
||||||
|
f := p.ProblemFunc
|
||||||
|
|
||||||
|
bestIndividual := 0
|
||||||
|
// the first one is the best one.
|
||||||
|
bestVal := f(p.Population[0].CurX)
|
||||||
|
|
||||||
|
for i, v := range p.Population {
|
||||||
|
current := f(v.CurX)
|
||||||
|
|
||||||
|
if current < bestVal {
|
||||||
|
bestIndividual = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestIndividual
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWorstIdx returns the index of the worst population individual.
|
||||||
|
func (p *SOMAT3APopulation) GetWorstIdx() int {
|
||||||
|
f := p.ProblemFunc
|
||||||
|
|
||||||
|
worstIndividual := 0
|
||||||
|
// the first one is the worst one.
|
||||||
|
worstVal := f(p.Population[0].CurX)
|
||||||
|
|
||||||
|
for i, v := range p.Population {
|
||||||
|
current := f(v.CurX)
|
||||||
|
|
||||||
|
if current > worstVal {
|
||||||
|
worstIndividual = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return worstIndividual
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init initialises all individuals to random values.
|
||||||
|
func (p *SOMAT3APopulation) Init() {
|
||||||
|
low := cec2020.SearchRange.Min()
|
||||||
|
high := cec2020.SearchRange.Max()
|
||||||
|
// zeroToOneRNG := distuv.Uniform{
|
||||||
|
p.zeroToOneRNG = distuv.Uniform{
|
||||||
|
Min: 0,
|
||||||
|
Max: 1,
|
||||||
|
Src: rand.NewSource(p.Seed),
|
||||||
|
}
|
||||||
|
|
||||||
|
// gaLogger.Printf("population initialisation - popCount: %d, seed: %d\n",
|
||||||
|
// len(p.Population), p.Seed,
|
||||||
|
// )
|
||||||
|
|
||||||
|
p.PRT = p.getPrt()
|
||||||
|
|
||||||
|
// for i,v := range p.Population {
|
||||||
|
for i := range p.Population {
|
||||||
|
v := SOMAT3APopulationIndividual{}
|
||||||
|
|
||||||
|
v.CurX = make([]float64, p.Dimen)
|
||||||
|
|
||||||
|
for j := 0; j < p.Dimen; j++ {
|
||||||
|
// with current settings, this will always be `low + 0` since
|
||||||
|
// `high - low = 0`.
|
||||||
|
v.CurX[j] = low + p.zeroToOneRNG.Rand()*(high-low)
|
||||||
|
}
|
||||||
|
|
||||||
|
v.PRTVector = p.getPrtVector()
|
||||||
|
|
||||||
|
v.Jumps = make([][]float64, p.Njumps)
|
||||||
|
|
||||||
|
p.Population[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
p.Champion = SOMAT3AChampionIndividual{X: p.Population[p.GetBestIdx()].CurX}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reinit reinitialises all individuals.
|
||||||
|
func (p *SOMAT3APopulation) Reinit() {
|
||||||
|
p.Init()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear sets all vectors to 0.
|
||||||
|
func (p *SOMAT3APopulation) Clear() {
|
||||||
|
if p.Population != nil {
|
||||||
|
for _, v := range p.Population {
|
||||||
|
v.CurX = make([]float64, p.Dimen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the number of population individuals.
|
||||||
|
func (p *SOMAT3APopulation) Size() int {
|
||||||
|
return len(p.Population)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newPopulation returns a pointer to a new, uninitialised population.
|
||||||
|
func newSOMAT3APopulation(benchProblem string, np, k, m, n, nj, dimen int) *SOMAT3APopulation {
|
||||||
|
p := &SOMAT3APopulation{
|
||||||
|
Problem: benchProblem,
|
||||||
|
ProblemFunc: cec2020.Functions[benchProblem],
|
||||||
|
K: k,
|
||||||
|
M: m,
|
||||||
|
N: n,
|
||||||
|
Njumps: nj,
|
||||||
|
Dimen: dimen,
|
||||||
|
Population: make([]SOMAT3APopulationIndividual, np),
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user