From b3787da640dafbc7f83f3d7e77a672fc0e73dad2 Mon Sep 17 00:00:00 2001 From: surtur Date: Fri, 17 Jun 2022 01:54:30 +0200 Subject: [PATCH] go: implement RandomSearch (wip) --- algo/randomSearch.go | 93 ++++++++++++++++++++++++++++++++++++++++++++ bench/bench.go | 10 ++--- bench/functions.go | 2 + flake.nix | 2 +- go.mod | 4 ++ go.sum | 23 +++++++++++ 6 files changed, 128 insertions(+), 6 deletions(-) diff --git a/algo/randomSearch.go b/algo/randomSearch.go index de704d6..06bc896 100644 --- a/algo/randomSearch.go +++ b/algo/randomSearch.go @@ -5,7 +5,11 @@ package algo import ( "fmt" + "log" "os" + + "git.dotya.ml/wanderer/math-optim/bench" + "gonum.org/v1/gonum/stat/distuv" ) func getRandomSearchLogPrefix() string { @@ -21,3 +25,92 @@ func printRandomSearch(input string) error { return err } + +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+1, "Schwefel", bench.SchwefelParams.Min(), bench.SchwefelParams.Max()) + valsSchwefel = append(valsSchwefel, v) + resultsSchwefel = append(resultsSchwefel, r) + + // run De Jong 1st. + vDJ1, rDJ1 := singleRandomSearch(dimens+1, "DeJong1st", bench.DeJong1Params.Min(), bench.DeJong1Params.Max()) + valsDeJong1st = append(valsDeJong1st, vDJ1) + resultsDeJong1st = append(resultsDeJong1st, rDJ1) + // run De Jong 2nd. + vDJ2, rDJ2 := singleRandomSearch(dimens+1, "DeJong2nd", 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) +} diff --git a/bench/bench.go b/bench/bench.go index 122eed5..62cc46a 100644 --- a/bench/bench.go +++ b/bench/bench.go @@ -16,7 +16,7 @@ const ( var ( // Dimensions to compute for (spatial complexity..?). - Dimensions = []int{5, 10, 20} + Dimensions = []uint{5, 10, 20} SchwefelParams = funcParams{min: -500.0, max: 500.0} DeJong1Params = funcParams{min: -5.0, max: 5.0} @@ -24,11 +24,11 @@ var ( ) // Min returns the non-exported "min" field of a funcParams struct. -func (*funcParams) Min(self *funcParams) float64 { - return self.max +func (f *funcParams) Min() float64 { + return f.min } // Max returns the non-exported 'max' field of a funcParams struct. -func (*funcParams) Max(self *funcParams) float64 { - return self.max +func (f *funcParams) Max() float64 { + return f.max } diff --git a/bench/functions.go b/bench/functions.go index 1638132..442449d 100644 --- a/bench/functions.go +++ b/bench/functions.go @@ -5,6 +5,8 @@ package bench import "math" +var Functions = []string{"Schwefel", "De Jong 1st", "De Jong 2nd"} + // Schwefel computes a value of the Schwefel function for x. func Schwefel(x []float64) float64 { var res float64 diff --git a/flake.nix b/flake.nix index d54c0b0..fd74c0c 100644 --- a/flake.nix +++ b/flake.nix @@ -80,7 +80,7 @@ modSha256 = lib.fakeSha256; # dont't forget to update vendorSha256 whenever go.mod or go.sum change - vendorSha256 = "sha256-pQpattmS9VmO3ZIQUFn66az8GSmB4IvYhTTCFn6SUmo="; + vendorSha256 = "sha256-NpZWn2yASg7HXr4sG849QSgUetouj8qjwS+p5jhlum0="; # In 'nix develop', we don't need a copy of the source tree # in the Nix store. diff --git a/go.mod b/go.mod index c5e38df..48a6e44 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,7 @@ module git.dotya.ml/wanderer/math-optim go 1.18 + +require gonum.org/v1/gonum v0.11.0 + +require golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3 // indirect diff --git a/go.sum b/go.sum index e69de29..93d541c 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,23 @@ +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3 h1:n9HxLrNxWWtEb1cA950nuEEj3QnKbtsCJ6KjcgisNUs= +golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.11.0 h1:f1IJhK4Km5tBJmaiJXtk/PkL4cdVX6J+tGiM187uT5E= +gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA=