185 lines
4.7 KiB
Go
185 lines
4.7 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.
|
|
func singleRandomSearch(dimens uint, f string, min, max float64) ([]float64, float64) {
|
|
vals := make([]float64, dimens)
|
|
|
|
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
|
|
}
|
|
|
|
// TODO(me): split this up
|
|
// nolint: gocognit
|
|
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
|
|
|
|
var bestResultsSchwefel []float64
|
|
|
|
var bestResultsDeJong1st []float64
|
|
|
|
var bestResultsDeJong2nd []float64
|
|
|
|
// iterations needed to establish a minimal viable statistical baseline
|
|
minIters := 30
|
|
|
|
for _, dimens := range bench.Dimensions {
|
|
// current iteration is named iter
|
|
for iter := 0; iter < minIters; iter++ {
|
|
var bestResult float64
|
|
|
|
for j := 0; j < int(fes); j++ {
|
|
// run Schwefel.
|
|
v, r := singleRandomSearch(
|
|
dimens,
|
|
bench.Functions[0],
|
|
bench.SchwefelParams.Min(),
|
|
bench.SchwefelParams.Max(),
|
|
)
|
|
valsSchwefel = append(valsSchwefel, v)
|
|
resultsSchwefel = append(resultsSchwefel, r)
|
|
|
|
switch j {
|
|
// first iteration
|
|
case 0:
|
|
bestResult = r
|
|
default:
|
|
// any other than the first iteration and a better solution
|
|
if r < bestResult {
|
|
bestResult = r
|
|
}
|
|
}
|
|
|
|
bestResultsSchwefel = append(bestResultsSchwefel, bestResult)
|
|
}
|
|
|
|
for k := 0; k < int(fes); k++ {
|
|
// run De Jong 1st.
|
|
v, r := singleRandomSearch(
|
|
dimens,
|
|
bench.Functions[1],
|
|
bench.DeJong1Params.Min(),
|
|
bench.DeJong1Params.Max(),
|
|
)
|
|
valsDeJong1st = append(valsDeJong1st, v)
|
|
resultsDeJong1st = append(resultsDeJong1st, r)
|
|
|
|
// first iteration or better solution
|
|
if k == 0 || r < bestResult {
|
|
bestResult = r
|
|
}
|
|
|
|
bestResultsDeJong1st = append(bestResultsDeJong1st, bestResult)
|
|
}
|
|
|
|
for l := 0; l < int(fes); l++ {
|
|
// run De Jong 2nd.
|
|
v, r := singleRandomSearch(
|
|
dimens,
|
|
bench.Functions[2],
|
|
bench.DeJong2Params.Min(),
|
|
bench.DeJong2Params.Max(),
|
|
)
|
|
valsDeJong2nd = append(valsDeJong2nd, v)
|
|
resultsDeJong2nd = append(resultsDeJong2nd, r)
|
|
|
|
// first iteration or better solution
|
|
if l == 0 || r < bestResult {
|
|
bestResult = r
|
|
}
|
|
|
|
bestResultsDeJong2nd = append(bestResultsDeJong2nd, bestResult)
|
|
}
|
|
}
|
|
}
|
|
|
|
fmt.Fprintln(os.Stderr, "vals schw len", len(valsSchwefel))
|
|
fmt.Fprintln(os.Stderr, "vals dj1 len", len(valsDeJong1st))
|
|
fmt.Fprintln(os.Stderr, "vals dj2 len", len(valsDeJong2nd))
|
|
|
|
fmt.Fprintln(os.Stderr, "res schw len", len(resultsSchwefel))
|
|
fmt.Fprintln(os.Stderr, "res dj1 len", len(resultsDeJong1st))
|
|
fmt.Fprintln(os.Stderr, "res dj2 len", len(resultsDeJong2nd))
|
|
|
|
fmt.Fprintln(os.Stderr, "best res schw len", len(bestResultsSchwefel))
|
|
fmt.Fprintln(os.Stderr, "best res dj1 len", len(bestResultsDeJong1st))
|
|
fmt.Fprintln(os.Stderr, "best res dj2 len", len(bestResultsDeJong2nd))
|
|
}
|