// Copyright 2023 wanderer // 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))) }