204 lines
4.0 KiB
Go
204 lines
4.0 KiB
Go
// Copyright 2023 wanderer <a_mirre at utb dot cz>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package cec2020
|
|
|
|
import (
|
|
"math"
|
|
"time"
|
|
|
|
"golang.org/x/exp/rand"
|
|
|
|
"gonum.org/v1/gonum/stat"
|
|
"gonum.org/v1/gonum/stat/distuv"
|
|
)
|
|
|
|
// void shiftfunc (double*,double*,int,double*);
|
|
// void rotatefunc (double*,double*,int, double*);
|
|
// void sr_func (double *, double *, int, double*, double*, double, int, int); // shift and rotate
|
|
// void asyfunc (double *, double *x, int, double);
|
|
// void oszfunc (double *, double *, int);
|
|
// void cf_cal(double *, double *, int, double *,double *,double *,double *,int);
|
|
|
|
// Shift shifts values of x based on values of os.
|
|
func Shift(x []float64, os []float64) {
|
|
if len(x) != len(os) {
|
|
cec2020Logger.Fatalln("slices are of different sizes, bailing...")
|
|
}
|
|
|
|
for i := range x {
|
|
x[i] -= os[i]
|
|
}
|
|
}
|
|
|
|
// Rotate rotates values of x based on values of mr.
|
|
func Rotate(x []float64, mr []float64) {
|
|
nx := len(x)
|
|
|
|
if int(math.Pow(float64(nx), 2)) > len(mr) {
|
|
cec2020Logger.Fatalf("either x is too big or mr is of insufficient size (%d:%d), bailing...\n", nx, len(mr))
|
|
}
|
|
|
|
xrot := make([]float64, nx)
|
|
|
|
for i := 0; i < nx; i++ {
|
|
for j := 0; j < nx; j++ {
|
|
x[j] += xrot[i] + (x[j] * mr[(i*nx)+j])
|
|
}
|
|
}
|
|
}
|
|
|
|
// ShiftRotate shifts and/or rotates the input x based on the request params
|
|
// shift and rotate (bool), using the values of os and/or mr.
|
|
func ShiftRotate(x []float64, os []float64, mr []float64, shiftRate float64, shift, rotate bool) {
|
|
switch {
|
|
case shift && rotate:
|
|
Shift(x, os)
|
|
|
|
// shrink to the original search range.
|
|
for i := range x {
|
|
x[i] *= shiftRate
|
|
}
|
|
|
|
Rotate(x, mr)
|
|
|
|
case shift && !rotate:
|
|
Shift(x, os)
|
|
|
|
// shrink to the original search range.
|
|
for i := range x {
|
|
x[i] *= shiftRate
|
|
}
|
|
|
|
case !shift && rotate:
|
|
// shrink to the original search range
|
|
for i := range x {
|
|
x[i] *= shiftRate
|
|
}
|
|
|
|
Rotate(x, mr)
|
|
|
|
case !shift && !rotate:
|
|
for i := range x {
|
|
x[i] *= shiftRate
|
|
}
|
|
}
|
|
}
|
|
|
|
// Asy is the asymptotic function.
|
|
func Asy(x []float64, beta float64) {
|
|
nx := len(x)
|
|
|
|
for i := range x {
|
|
if x[i] > 0 {
|
|
fi := float64(i)
|
|
fnx := float64(nx)
|
|
|
|
x[i] = math.Pow(x[i], 1+((beta*fi)/(fnx-1)*math.Pow(x[i], 0.5)))
|
|
}
|
|
}
|
|
}
|
|
|
|
// GetMaxFES returns maxFES for the passed dimension, given that it's present
|
|
// in the MaxFES slice, returns -1 otherwise.
|
|
func GetMaxFES(dim int) int {
|
|
for i, d := range Dimensions {
|
|
if dim == d {
|
|
return MaxFES[i]
|
|
}
|
|
}
|
|
|
|
return -1
|
|
}
|
|
|
|
// nolint: unused
|
|
func newXopt(n int, mu0 float64) []float64 {
|
|
gaussDist := &distuv.Normal{
|
|
Src: rand.NewSource(uint64(time.Now().UnixNano())),
|
|
}
|
|
|
|
tmpvec := make([]float64, n)
|
|
xopt := make([]float64, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
tmpvec = append(tmpvec, gaussDist.Rand())
|
|
|
|
xopt = append(xopt, 0.5*mu0)
|
|
|
|
if tmpvec[i] < 0 {
|
|
xopt[i] *= -1
|
|
}
|
|
}
|
|
|
|
return xopt
|
|
}
|
|
|
|
// newOpt returns a slice of optimal float64 values.
|
|
func newOpt(n int) []float64 {
|
|
uniformDist := &distuv.Uniform{
|
|
Src: rand.NewSource(uint64(time.Now().UnixNano())),
|
|
Min: SearchRange.Min(),
|
|
Max: SearchRange.Max(),
|
|
}
|
|
|
|
tmpvec := make([]float64, n)
|
|
xopt := make([]float64, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
tmpvec = append(tmpvec, uniformDist.Rand())
|
|
|
|
xopt = append(xopt, 0.5*uniformDist.Mean())
|
|
|
|
if tmpvec[i] < 0 {
|
|
xopt[i] *= -1
|
|
}
|
|
}
|
|
|
|
return xopt
|
|
}
|
|
|
|
// getGnx calculates G_nx.
|
|
func getGnx(p []float64, fnx float64) []float64 {
|
|
gnx := make([]float64, len(p))
|
|
gnxsum := 0.0
|
|
|
|
for i := 0; i < len(p)-1; i++ {
|
|
gnx[i] = math.Ceil(p[i] * fnx)
|
|
gnxsum += gnx[i]
|
|
}
|
|
|
|
gnx[len(p)-1] = fnx - gnxsum
|
|
|
|
return gnx
|
|
}
|
|
|
|
// getMz calculates Mz.
|
|
// nolint: unused
|
|
func getMz(x []float64, z []float64) []float64 {
|
|
nx := len(x)
|
|
mz := make([]float64, nx)
|
|
|
|
for i := range x {
|
|
mz = append(mz, x[i]*z[i])
|
|
}
|
|
|
|
return mz
|
|
}
|
|
|
|
func getMean(x []float64) float64 {
|
|
mean := stat.Mean(x, nil)
|
|
|
|
return mean
|
|
}
|
|
|
|
func getWeight(x, o []float64, sigma, nx float64) float64 {
|
|
var sum float64
|
|
|
|
for i := range x {
|
|
sum += math.Pow(x[i]-o[i], 2)
|
|
}
|
|
|
|
// w.
|
|
return (1 / (math.Sqrt(sum))) * math.Exp(-(sum / 2 * nx * math.Pow(sigma, 2)))
|
|
}
|