137 lines
3.5 KiB
Go
137 lines
3.5 KiB
Go
// Copyright 2022 wanderer <a_mirre at utb dot cz>
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package algo
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
|
|
"git.dotya.ml/wanderer/math-optim/bench"
|
|
"gonum.org/v1/gonum/stat/distuv"
|
|
)
|
|
|
|
func getRandomSearchLogPrefix() string {
|
|
return " *** random search:"
|
|
}
|
|
|
|
func fmtRandomSearchOut(input string) string {
|
|
return getRandomSearchLogPrefix() + " " + input
|
|
}
|
|
|
|
func printRandomSearch(input string) {
|
|
if _, err := fmt.Fprintln(os.Stderr, fmtRandomSearchOut(input)); err != nil {
|
|
fmt.Fprintf(
|
|
os.Stdout,
|
|
getRandomSearchLogPrefix(),
|
|
"error while printing to stderr: %q\n * original message was: %q",
|
|
err, input,
|
|
)
|
|
}
|
|
}
|
|
|
|
func genValsRandomSearch(dimens uint, vals []float64, uniform *distuv.Uniform) {
|
|
for i := uint(0); i < dimens; i++ {
|
|
// using Uniform.Rand from gonum's stat/distuv package.
|
|
// https://pkg.go.dev/gonum.org/v1/gonum/stat/distuv#Uniform.Rand
|
|
// boundaries are already set at this point.
|
|
vals[i] = uniform.Rand()
|
|
}
|
|
}
|
|
|
|
// singleRandomSearch performs a single iteration of the 'RandomSearch' algorithm.
|
|
// it takes a couple of arguments:
|
|
// * dimens uint: number of dimensions of the objective function
|
|
// * f string: name of the bench func to optimise (see bench/functions)
|
|
// * min/max float64: the upper/lower limit of the uniform distribution span,
|
|
// which is relevant to the objective function.
|
|
// nolint
|
|
func singleRandomSearch(dimens uint, f string, min, max float64) ([]float64, float64) {
|
|
var vals []float64
|
|
|
|
var res float64
|
|
|
|
// create a continuous uniform distribution representation within min/max bounds
|
|
uniformDist := distuv.Uniform{Min: min, Max: max}
|
|
|
|
genValsRandomSearch(dimens, vals, &uniformDist)
|
|
|
|
// result of the benchmarking function computation over vals
|
|
switch f {
|
|
// Schwefel
|
|
case bench.Functions[0]:
|
|
res = bench.Schwefel(vals)
|
|
// "DeJong1st"
|
|
case bench.Functions[1]:
|
|
res = bench.DeJong1st(vals)
|
|
// "DeJong2nd"
|
|
case bench.Functions[2]:
|
|
res = bench.DeJong2nd(vals)
|
|
}
|
|
|
|
return vals, res
|
|
}
|
|
|
|
func RandomSearch(fes uint) {
|
|
if fes == 0 {
|
|
log.Fatalln(" random search: fes set to 0, bailing")
|
|
}
|
|
|
|
var valsSchwefel []Values
|
|
|
|
var valsDeJong1st []Values
|
|
|
|
var valsDeJong2nd []Values
|
|
|
|
var resultsSchwefel Values
|
|
|
|
var resultsDeJong1st Values
|
|
|
|
var resultsDeJong2nd Values
|
|
|
|
// iterations needed to establish a minimal viable statistical baseline
|
|
minIters := 30
|
|
|
|
for _, dimens := range bench.Dimensions {
|
|
for j := 0; j < minIters; j++ {
|
|
// run Schwefel.
|
|
v, r := singleRandomSearch(
|
|
dimens,
|
|
bench.Functions[0],
|
|
bench.SchwefelParams.Min(),
|
|
bench.SchwefelParams.Max(),
|
|
)
|
|
valsSchwefel = append(valsSchwefel, v)
|
|
resultsSchwefel = append(resultsSchwefel, r)
|
|
|
|
// run De Jong 1st.
|
|
vDJ1, rDJ1 := singleRandomSearch(
|
|
dimens,
|
|
bench.Functions[1],
|
|
bench.DeJong1Params.Min(),
|
|
bench.DeJong1Params.Max(),
|
|
)
|
|
valsDeJong1st = append(valsDeJong1st, vDJ1)
|
|
resultsDeJong1st = append(resultsDeJong1st, rDJ1)
|
|
// run De Jong 2nd.
|
|
vDJ2, rDJ2 := singleRandomSearch(
|
|
dimens,
|
|
bench.Functions[2],
|
|
bench.DeJong2Params.Min(),
|
|
bench.DeJong2Params.Max(),
|
|
)
|
|
valsDeJong2nd = append(valsDeJong2nd, vDJ2)
|
|
resultsDeJong2nd = append(resultsDeJong2nd, rDJ2)
|
|
}
|
|
}
|
|
|
|
fmt.Fprintln(os.Stderr, "vals schw:", valsSchwefel)
|
|
fmt.Fprintln(os.Stderr, "vals dj1", valsDeJong1st)
|
|
fmt.Fprintln(os.Stderr, "vals dj2", valsDeJong2nd)
|
|
|
|
fmt.Fprintln(os.Stderr, "res schw:", resultsSchwefel)
|
|
fmt.Fprintln(os.Stderr, "res dj1", resultsDeJong1st)
|
|
fmt.Fprintln(os.Stderr, "res dj2", resultsDeJong2nd)
|
|
}
|