2022-06-14 22:34:52 +02:00
|
|
|
// Copyright 2022 wanderer <a_mirre at utb dot cz>
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
package algo
|
|
|
|
|
|
|
|
import (
|
2022-08-03 21:28:43 +02:00
|
|
|
"fmt"
|
|
|
|
"log"
|
2022-08-03 21:25:37 +02:00
|
|
|
"sort"
|
2022-06-14 22:34:52 +02:00
|
|
|
"sync"
|
2022-06-24 00:45:43 +02:00
|
|
|
|
|
|
|
"git.dotya.ml/wanderer/math-optim/bench"
|
2022-07-13 23:47:37 +02:00
|
|
|
"git.dotya.ml/wanderer/math-optim/report"
|
2022-06-24 00:45:43 +02:00
|
|
|
"git.dotya.ml/wanderer/math-optim/stats"
|
2022-06-14 22:34:52 +02:00
|
|
|
)
|
|
|
|
|
2022-07-19 21:56:49 +02:00
|
|
|
// mu protects access to meanStats.
|
|
|
|
var mu sync.Mutex
|
|
|
|
|
2022-08-03 21:17:19 +02:00
|
|
|
// mCoMPL protexts access to comparisonOfMeansPicList.
|
|
|
|
var mCoMPL sync.Mutex
|
|
|
|
|
2022-07-19 21:56:49 +02:00
|
|
|
var meanStats = &stats.MeanStats{}
|
|
|
|
|
2022-08-03 21:17:19 +02:00
|
|
|
var comparisonOfMeansPicList = &report.PicList{Algo: "Comparison of Means"}
|
|
|
|
|
2022-08-03 21:28:43 +02:00
|
|
|
// getComparisonOfMeansPics returns a sorted slice of pics field from the
|
|
|
|
// package global 'algoMeanPics'.
|
|
|
|
func getComparisonOfMeansPics() []report.Pic {
|
|
|
|
// note: sorting by filename (dimens value being 0-padded at generation
|
|
|
|
// time), relying on this as a hack so that we didn't have to implement our
|
|
|
|
// own natural-order sorter.
|
|
|
|
sort.Sort(comparisonOfMeansPicList.Pics)
|
|
|
|
|
|
|
|
return comparisonOfMeansPicList.Pics
|
|
|
|
}
|
|
|
|
|
2022-08-03 21:25:37 +02:00
|
|
|
// GetMeanStats returns a pointer of type stats.MeanStats to a sorted package
|
|
|
|
// global 'meanStats'.
|
|
|
|
func GetMeanStats() *stats.MeanStats {
|
|
|
|
sort.Sort(meanStats)
|
|
|
|
|
|
|
|
return meanStats
|
|
|
|
}
|
|
|
|
|
2022-08-03 21:28:43 +02:00
|
|
|
func PrepComparisonOfMeans(wg *sync.WaitGroup) (*report.PicList, int) {
|
|
|
|
pL := report.NewPicList()
|
|
|
|
meanStats := GetMeanStats()
|
|
|
|
algos := make([]string, 0)
|
|
|
|
|
|
|
|
// learn how many algos were processed based on the data.
|
|
|
|
for _, v := range meanStats.AlgoMeans {
|
|
|
|
// if algos is empty just add the value directly, else determine if
|
|
|
|
// it's already been added or not.
|
|
|
|
if len(algos) > 0 {
|
|
|
|
alreadyadded := false
|
|
|
|
|
|
|
|
for _, algoName := range algos {
|
|
|
|
if algoName == v.Algo {
|
|
|
|
// early bail if already added.
|
|
|
|
alreadyadded = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !alreadyadded {
|
|
|
|
algos = append(algos, v.Algo)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
algos = append(algos, v.Algo)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// construct title consisting of names of all involved algorithms.
|
|
|
|
for _, v := range algos {
|
|
|
|
switch pL.Algo {
|
|
|
|
case "":
|
|
|
|
pL.Algo = v
|
|
|
|
default:
|
|
|
|
pL.Algo += " vs " + v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Println(`generating "Comparison of Means" plots`)
|
|
|
|
|
|
|
|
algoCount := len(algos)
|
|
|
|
dimLen := len(bench.Dimensions)
|
|
|
|
benchCount := len(bench.Functions)
|
|
|
|
|
|
|
|
// note: this is a wee bit ugly.
|
|
|
|
for d := 0; d < dimLen; d++ {
|
|
|
|
for i := 0; i < benchCount; i++ {
|
|
|
|
dimXAlgoMeanVals := make([]stats.AlgoMeanVals, 0, algoCount)
|
|
|
|
|
|
|
|
for j := 0; j < algoCount*benchCount; j += benchCount {
|
|
|
|
neighbInfo := ""
|
|
|
|
|
|
|
|
// only add info about neighbours if it was changed (from
|
|
|
|
// the default of -1).
|
|
|
|
if n := meanStats.AlgoMeans[d+j].BenchMeans[i].Neighbours; n != -1 {
|
|
|
|
neighbInfo = fmt.Sprintf(" (N: %d)", n)
|
|
|
|
}
|
|
|
|
|
|
|
|
ms := &stats.AlgoMeanVals{
|
|
|
|
Title: meanStats.AlgoMeans[d+j].Algo + neighbInfo,
|
|
|
|
MeanVals: meanStats.AlgoMeans[d+j].BenchMeans[i].MeanVals,
|
|
|
|
}
|
|
|
|
dimXAlgoMeanVals = append(dimXAlgoMeanVals, *ms)
|
|
|
|
}
|
|
|
|
|
|
|
|
dimens := meanStats.AlgoMeans[d].BenchMeans[i].Dimens
|
|
|
|
iterations := meanStats.AlgoMeans[d].BenchMeans[i].Iterations
|
|
|
|
bench := meanStats.AlgoMeans[d].BenchMeans[i].Bench
|
|
|
|
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
// construct plots concurrently.
|
|
|
|
go PlotMeanValsMulti(
|
|
|
|
wg, dimens, iterations, bench, "plot-", ".svg",
|
|
|
|
dimXAlgoMeanVals...,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// wait for all the plotting to conclude.
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
pL.Pics = getComparisonOfMeansPics()
|
|
|
|
|
|
|
|
return pL, benchCount
|
|
|
|
}
|
|
|
|
|
2022-06-14 22:34:52 +02:00
|
|
|
// DoRandomSearch executes a search using the 'Random search' method.
|
2022-07-16 22:05:15 +02:00
|
|
|
func DoRandomSearch(wg *sync.WaitGroup, m *sync.Mutex) {
|
2022-06-14 22:34:52 +02:00
|
|
|
defer wg.Done()
|
|
|
|
|
2022-06-17 19:55:23 +02:00
|
|
|
printRandomSearch("starting...")
|
2022-06-20 03:32:48 +02:00
|
|
|
|
2022-06-24 00:45:43 +02:00
|
|
|
// funcCount is the number of bench functions available.
|
|
|
|
funcCount := len(bench.Functions)
|
|
|
|
// stats for the current algo (RandomSearch).
|
|
|
|
algoStats := make([][]stats.Stats, funcCount)
|
2022-07-11 20:59:18 +02:00
|
|
|
// ch serves as a way to get the actual computed output.
|
|
|
|
ch := make(chan []stats.Stats, funcCount)
|
2022-06-24 00:45:43 +02:00
|
|
|
|
2022-08-05 17:23:10 +02:00
|
|
|
defer close(ch)
|
|
|
|
|
2022-06-24 00:56:10 +02:00
|
|
|
for i := range algoStats {
|
|
|
|
// ng y'all.
|
2022-07-17 11:57:40 +02:00
|
|
|
go RandomSearchNG(10000, 30, bench.Dimensions, bench.FuncNames[i], ch)
|
2022-07-11 20:59:18 +02:00
|
|
|
}
|
2022-07-09 16:19:56 +02:00
|
|
|
|
2022-07-11 20:59:18 +02:00
|
|
|
// get results.
|
|
|
|
for i := range algoStats {
|
|
|
|
s := <-ch
|
2022-07-09 16:19:56 +02:00
|
|
|
|
2022-07-11 20:59:18 +02:00
|
|
|
algoStats[i] = s
|
2022-06-24 00:56:10 +02:00
|
|
|
}
|
2022-06-24 00:45:43 +02:00
|
|
|
|
2022-07-13 23:47:37 +02:00
|
|
|
pCh := make(chan report.PicList, funcCount*len(bench.Dimensions))
|
2022-07-18 22:36:47 +02:00
|
|
|
pMeanCh := make(chan report.PicList, funcCount*len(bench.Dimensions))
|
2022-07-13 23:47:37 +02:00
|
|
|
|
2022-08-05 17:23:10 +02:00
|
|
|
defer close(pCh)
|
|
|
|
defer close(pMeanCh)
|
|
|
|
|
2022-06-24 00:45:43 +02:00
|
|
|
for i := range algoStats {
|
2022-07-18 22:36:47 +02:00
|
|
|
go plotAllDims(algoStats[i], "plot", ".svg", pCh, pMeanCh)
|
2022-07-13 23:47:37 +02:00
|
|
|
}
|
2022-07-08 22:51:31 +02:00
|
|
|
|
2022-07-16 21:40:53 +02:00
|
|
|
pLs := []report.PicList{}
|
2022-07-18 22:36:47 +02:00
|
|
|
pLsMean := []report.PicList{}
|
2022-07-16 21:40:53 +02:00
|
|
|
|
2022-07-13 23:47:37 +02:00
|
|
|
for range algoStats {
|
|
|
|
pL := <-pCh
|
2022-07-18 22:36:47 +02:00
|
|
|
pLMean := <-pMeanCh
|
2022-07-13 23:47:37 +02:00
|
|
|
|
2022-07-16 21:40:53 +02:00
|
|
|
pLs = append(pLs, pL)
|
2022-07-18 22:36:47 +02:00
|
|
|
pLsMean = append(pLsMean, pLMean)
|
2022-06-24 00:45:43 +02:00
|
|
|
}
|
2022-06-20 03:32:48 +02:00
|
|
|
|
2022-07-18 00:23:53 +02:00
|
|
|
algoName := "Random Search"
|
|
|
|
|
2022-07-16 22:05:15 +02:00
|
|
|
// protect access to shared data.
|
|
|
|
m.Lock()
|
2022-07-18 22:36:47 +02:00
|
|
|
report.SavePicsToFile(pLs, pLsMean, algoName)
|
2022-07-16 21:40:53 +02:00
|
|
|
|
2022-07-18 00:23:53 +02:00
|
|
|
stats.SaveTable(algoName, algoStats)
|
2022-07-16 23:30:56 +02:00
|
|
|
m.Unlock()
|
2022-06-14 22:34:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// DoStochasticHillClimbing performs a search using the 'Stochastic Hill
|
|
|
|
// Climbing' method.
|
2022-07-16 22:05:15 +02:00
|
|
|
func DoStochasticHillClimbing(wg *sync.WaitGroup, m *sync.Mutex) {
|
2022-06-14 22:34:52 +02:00
|
|
|
defer wg.Done()
|
|
|
|
|
2022-06-17 19:55:23 +02:00
|
|
|
printSHC("starting...")
|
2022-07-08 21:40:04 +02:00
|
|
|
|
|
|
|
// funcCount is the number of bench functions available.
|
|
|
|
funcCount := len(bench.Functions)
|
|
|
|
// stats for the current algo (StochasticHillClimber).
|
|
|
|
algoStats := make([][]stats.Stats, funcCount)
|
2022-07-11 20:59:18 +02:00
|
|
|
// ch serves as a way to get the actual computed output.
|
|
|
|
ch := make(chan []stats.Stats, funcCount)
|
2022-07-08 21:40:04 +02:00
|
|
|
|
2022-08-05 17:23:10 +02:00
|
|
|
defer close(ch)
|
|
|
|
|
2022-07-08 21:40:04 +02:00
|
|
|
for i := range algoStats {
|
2022-08-05 17:11:39 +02:00
|
|
|
// params:
|
|
|
|
// maxFES, benchMinIters, neighbours int,
|
|
|
|
// theD []int,
|
|
|
|
// benchFunc string,
|
|
|
|
// ch chan []stats.Stats
|
|
|
|
go HillClimb(10000, 30, 10, bench.Dimensions, bench.FuncNames[i], ch)
|
2022-07-11 20:59:18 +02:00
|
|
|
}
|
2022-07-09 16:19:56 +02:00
|
|
|
|
2022-07-11 20:59:18 +02:00
|
|
|
// get results.
|
|
|
|
for i := range algoStats {
|
|
|
|
s := <-ch
|
2022-07-09 16:19:56 +02:00
|
|
|
|
2022-07-11 20:59:18 +02:00
|
|
|
algoStats[i] = s
|
2022-07-08 21:40:04 +02:00
|
|
|
}
|
|
|
|
|
2022-07-13 23:47:37 +02:00
|
|
|
pCh := make(chan report.PicList, funcCount*len(bench.Dimensions))
|
2022-07-18 22:36:47 +02:00
|
|
|
pMeanCh := make(chan report.PicList, funcCount*len(bench.Dimensions))
|
2022-07-13 23:47:37 +02:00
|
|
|
|
2022-08-05 17:23:10 +02:00
|
|
|
defer close(pCh)
|
|
|
|
defer close(pMeanCh)
|
|
|
|
|
2022-07-08 21:40:04 +02:00
|
|
|
for _, algoStat := range algoStats {
|
2022-07-18 22:36:47 +02:00
|
|
|
go plotAllDims(algoStat, "plot", ".svg", pCh, pMeanCh)
|
2022-07-13 23:47:37 +02:00
|
|
|
}
|
2022-07-08 22:51:31 +02:00
|
|
|
|
2022-07-16 21:40:53 +02:00
|
|
|
pLs := []report.PicList{}
|
2022-07-18 22:36:47 +02:00
|
|
|
pLsMean := []report.PicList{}
|
2022-07-16 21:40:53 +02:00
|
|
|
|
2022-07-13 23:47:37 +02:00
|
|
|
for range algoStats {
|
|
|
|
pL := <-pCh
|
2022-07-18 22:36:47 +02:00
|
|
|
pLMean := <-pMeanCh
|
2022-07-13 23:47:37 +02:00
|
|
|
|
2022-07-16 21:40:53 +02:00
|
|
|
pLs = append(pLs, pL)
|
2022-07-18 22:36:47 +02:00
|
|
|
pLsMean = append(pLsMean, pLMean)
|
2022-07-08 21:40:04 +02:00
|
|
|
}
|
|
|
|
|
2022-07-18 00:23:53 +02:00
|
|
|
algoName := "Stochastic Hill Climbing"
|
|
|
|
|
2022-07-16 22:05:15 +02:00
|
|
|
// protect access to shared data.
|
|
|
|
m.Lock()
|
2022-07-18 22:36:47 +02:00
|
|
|
report.SavePicsToFile(pLs, pLsMean, algoName)
|
2022-07-16 21:40:53 +02:00
|
|
|
|
2022-07-18 00:23:53 +02:00
|
|
|
stats.SaveTable(algoName, algoStats)
|
2022-07-16 23:30:56 +02:00
|
|
|
m.Unlock()
|
2022-06-14 22:34:52 +02:00
|
|
|
}
|