chore: add all updates, sort out later
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
c3b9ddee27
commit
68b14f9960
@ -316,4 +316,4 @@ def main(ctx):
|
||||
}
|
||||
]
|
||||
|
||||
# vim: ft=bzl.starlark syntax=bzl.starlark noexpandtab ts=4 foldmethod=manual
|
||||
# vim:ft=bzl.starlark:syntax=bzl.starlark:noexpandtab:ts=4:sts=4:sw=4:foldmethod=manual
|
||||
|
2
.envrc
2
.envrc
@ -4,4 +4,6 @@ use flake
|
||||
# comment out if not planning to use this
|
||||
add_extra_vimrc
|
||||
|
||||
# alias gor='go run'
|
||||
|
||||
# vim: ff=unix ft=sh
|
||||
|
@ -13,7 +13,7 @@ issues:
|
||||
linters:
|
||||
enable:
|
||||
- bidichk
|
||||
- dupl
|
||||
# - dupl
|
||||
# The linter 'deadcode' is deprecated (since v1.49.0) due to: The owner
|
||||
# seems to have abandoned the linter. Replaced by unused.
|
||||
# - deadcode
|
||||
|
68
algo/algo.go
68
algo/algo.go
@ -14,6 +14,8 @@ import (
|
||||
"git.dotya.ml/wanderer/math-optim/stats"
|
||||
)
|
||||
|
||||
// var Algos = []string{"Random Search", "Stochastic Hill Climbing"}
|
||||
|
||||
// mu protects access to meanStats.
|
||||
var mu sync.Mutex
|
||||
|
||||
@ -157,6 +159,11 @@ func DoRandomSearch(wg *sync.WaitGroup, m *sync.Mutex) {
|
||||
algoStats[i] = s
|
||||
}
|
||||
|
||||
// save stats to json.
|
||||
// stats.SaveStats(schw, "schwefel")
|
||||
// stats.SaveStats(djg1, "djg1")
|
||||
// stats.SaveStats(djg2, "djg2")
|
||||
|
||||
pCh := make(chan report.PicList, funcCount*len(bench.Dimensions))
|
||||
pMeanCh := make(chan report.PicList, funcCount*len(bench.Dimensions))
|
||||
|
||||
@ -188,6 +195,14 @@ func DoRandomSearch(wg *sync.WaitGroup, m *sync.Mutex) {
|
||||
m.Unlock()
|
||||
}
|
||||
|
||||
// TODO(me): split this package to multiple - package per algo, common code here.
|
||||
// TODO(me): implement Simulated Annaeling.
|
||||
// TODO(me): implement a variant of Stochastic Hill Climber that tweaks its
|
||||
// Neighbourhood size or MaxNeighbourVariancePercent based on the
|
||||
// latest 5 values, if they don't change, params get tweaked to
|
||||
// broaden the search space to make sure it's not stuck in a local
|
||||
// extreme.
|
||||
|
||||
// DoStochasticHillClimbing performs a search using the 'Stochastic Hill
|
||||
// Climbing' method.
|
||||
func DoStochasticHillClimbing(wg *sync.WaitGroup, m *sync.Mutex) {
|
||||
@ -250,3 +265,56 @@ func DoStochasticHillClimbing(wg *sync.WaitGroup, m *sync.Mutex) {
|
||||
stats.SaveTable(algoName, algoStats)
|
||||
m.Unlock()
|
||||
}
|
||||
|
||||
func DoStochasticHillClimbing100Neigh(wg *sync.WaitGroup, m *sync.Mutex) {
|
||||
defer wg.Done()
|
||||
|
||||
printSHC("starting...")
|
||||
|
||||
// funcCount is the number of bench functions available.
|
||||
funcCount := len(bench.Functions)
|
||||
// stats for the current algo (StochasticHillClimber).
|
||||
algoStats := make([][]stats.Stats, funcCount)
|
||||
// ch serves as a way to get the actual computed output.
|
||||
ch := make(chan []stats.Stats, funcCount)
|
||||
|
||||
for i := range algoStats {
|
||||
go HillClimb(10000, 30, 100, bench.Dimensions, bench.FuncNames[i], ch)
|
||||
}
|
||||
|
||||
// get results.
|
||||
for i := range algoStats {
|
||||
s := <-ch
|
||||
|
||||
algoStats[i] = s
|
||||
}
|
||||
|
||||
pCh := make(chan report.PicList, funcCount*len(bench.Dimensions))
|
||||
pMeanCh := make(chan report.PicList, funcCount*len(bench.Dimensions))
|
||||
|
||||
for _, algoStat := range algoStats {
|
||||
go plotAllDims(algoStat, "plot", ".pdf", pCh, pMeanCh)
|
||||
}
|
||||
|
||||
pLs := []report.PicList{}
|
||||
pLsMean := []report.PicList{}
|
||||
|
||||
for range algoStats {
|
||||
pL := <-pCh
|
||||
pLMean := <-pMeanCh
|
||||
|
||||
pLs = append(pLs, pL)
|
||||
pLsMean = append(pLsMean, pLMean)
|
||||
}
|
||||
|
||||
algoName := "Stochastic Hill Climbing 100 Neighbours"
|
||||
|
||||
// protect access to shared data.
|
||||
m.Lock()
|
||||
report.SavePicsToFile(pLs, pLsMean, algoName)
|
||||
// report.SavePicsToFile(pLsMean, pLs, algoName)
|
||||
|
||||
// stats.PrintStatisticTable(algoStats)
|
||||
stats.SaveTable(algoName, algoStats)
|
||||
m.Unlock()
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
package algo
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
@ -16,14 +17,18 @@ var wg sync.WaitGroup
|
||||
var m sync.Mutex
|
||||
|
||||
func TestDoRandomSearchExec(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
// use t.tmpdir
|
||||
go DoRandomSearch(&wg, &m)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
picsDir := report.GetPicsDir() + "-test-rs"
|
||||
|
||||
// attempt to clean up.
|
||||
if err := os.RemoveAll(picsDir); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -34,6 +39,7 @@ func TestDoRandomSearchExec(t *testing.T) {
|
||||
t.Error("picsDir should have already been cleaned up")
|
||||
}
|
||||
|
||||
log.Println("pwd:", os.Getenv("PWD"))
|
||||
// clean up outdir.
|
||||
if err := os.RemoveAll("out"); err != nil {
|
||||
t.Error(err)
|
||||
@ -41,6 +47,8 @@ func TestDoRandomSearchExec(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDoSHCExec(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
wg.Add(1)
|
||||
|
||||
go DoStochasticHillClimbing(&wg, &m)
|
||||
@ -49,6 +57,7 @@ func TestDoSHCExec(t *testing.T) {
|
||||
|
||||
picsDir := report.GetPicsDir() + "-test-shc"
|
||||
|
||||
// attempt to clean up.
|
||||
if err := os.RemoveAll(picsDir); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -59,6 +68,7 @@ func TestDoSHCExec(t *testing.T) {
|
||||
t.Error("picsDir should have already been cleaned up")
|
||||
}
|
||||
|
||||
log.Println("pwd:", os.Getenv("PWD"))
|
||||
// clean up outdir.
|
||||
if err := os.RemoveAll("out"); err != nil {
|
||||
t.Error(err)
|
||||
|
19
algo/plot.go
19
algo/plot.go
@ -121,6 +121,7 @@ func PlotMeanValsMulti(
|
||||
|
||||
// set pic file path and caption.
|
||||
pic.FilePath = filename
|
||||
// pic.Caption = strings.ReplaceAll(filename, " ", "~")
|
||||
pic.Caption = strings.ReplaceAll(
|
||||
fmt.Sprintf("Comparison of Means (%dI) - %s (%dD)",
|
||||
iterations, bench, dimens,
|
||||
@ -157,21 +158,27 @@ func plotMeanVals(meanVals []float64, title string, fes int) *plot.Plot {
|
||||
}
|
||||
|
||||
p := plot.New()
|
||||
// pic := report.NewPic()
|
||||
|
||||
p.Title.Text = "Mean - " + title
|
||||
|
||||
p.X.Label.Text = xAxisLabel
|
||||
// p.X.Label.Padding = 8 * vg.Millimeter
|
||||
p.X.Label.TextStyle.Font.Variant = preferredFont
|
||||
p.X.Label.TextStyle.Font.Weight = 1 // Medium
|
||||
p.X.Tick.Label.Font.Variant = preferredFont
|
||||
// p.X.Padding = 2 * vg.Millimeter
|
||||
p.Y.Label.Text = yAxisLabel
|
||||
// p.Y.Label.Padding = 2 * vg.Millimeter
|
||||
p.Y.Label.TextStyle.Font.Variant = preferredFont
|
||||
p.Y.Label.TextStyle.Font.Weight = 1 // Medium
|
||||
p.Y.Tick.Label.Font.Variant = preferredFont
|
||||
// p.Y.Padding = 1 * vg.Millimeter
|
||||
|
||||
p.Title.TextStyle.Font.Size = 14.5
|
||||
p.Title.TextStyle.Font.Variant = titlePreferredFont
|
||||
p.Title.TextStyle.Font.Weight = 2 // SemiBold
|
||||
// p.Title.Padding = 5 * vg.Millimeter
|
||||
p.Title.Padding = 3 * vg.Millimeter
|
||||
|
||||
// mark the end of the X axis with len(meanVals).
|
||||
@ -255,12 +262,20 @@ func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, ch chan report.P
|
||||
p.Y.Label.TextStyle.Font.Variant = preferredFont
|
||||
p.Y.Label.TextStyle.Font.Weight = 1 // Medium
|
||||
p.Y.Tick.Label.Font.Variant = preferredFont
|
||||
// p.Y.Padding = 1 * vg.Millimeter
|
||||
|
||||
p.Title.TextStyle.Font.Size = 14.5
|
||||
p.Title.TextStyle.Font.Variant = titlePreferredFont
|
||||
p.Title.TextStyle.Font.Weight = 2 // SemiBold
|
||||
// p.Title.Padding = 5 * vg.Millimeter
|
||||
p.Title.Padding = 3 * vg.Millimeter
|
||||
|
||||
// p.Legend.TextStyle.Font.Variant = preferredFontStyle
|
||||
// p.Legend.TextStyle.Font.Size = 8
|
||||
// p.Legend.Top = true
|
||||
// p.Legend.Padding = 0 * vg.Centimeter
|
||||
// p.Add(plotter.NewGrid())
|
||||
|
||||
for _, dim := range s.BenchFuncStats {
|
||||
// infinite thanks to this SO comment for the interface "hack":
|
||||
// https://stackoverflow.com/a/44872993
|
||||
@ -286,6 +301,7 @@ func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, ch chan report.P
|
||||
pts[k].Y = res
|
||||
}
|
||||
|
||||
// lines = append(lines, "#"+fmt.Sprint(j), pts)
|
||||
lines = append(lines, pts)
|
||||
}
|
||||
|
||||
@ -299,6 +315,7 @@ func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, ch chan report.P
|
||||
}
|
||||
|
||||
// TODO(me): add Neighbourhood param
|
||||
// TODO(me): add search space percent param
|
||||
filename := fmt.Sprintf("%s%s-%s-%s-%dD-%dG-%dI",
|
||||
picsDir,
|
||||
fPrefix,
|
||||
@ -333,6 +350,7 @@ func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, ch chan report.P
|
||||
filename, fExt, elapsed,
|
||||
)
|
||||
|
||||
// TODO(me): rework this.
|
||||
if s.Algo == "Random Search" {
|
||||
printRandomSearch(info)
|
||||
} else {
|
||||
@ -347,6 +365,7 @@ func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, ch chan report.P
|
||||
); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// log.Println(filename + fExt)
|
||||
|
||||
// save pic.
|
||||
pics = append(pics, *pic)
|
||||
|
@ -59,6 +59,8 @@ func selectBestNeighbour(neighbours []neighbour, benchFuncName string) ([]float6
|
||||
// f is the actual bench function, based on the name.
|
||||
f := bench.Functions[benchFuncName]
|
||||
|
||||
// fmt.Println("select best\nlen(neighbours)", len(neighbours))
|
||||
|
||||
for i, v := range neighbours {
|
||||
switch i {
|
||||
case 0:
|
||||
@ -92,6 +94,8 @@ func getBenchSearchSpaceSize(benchName string) float64 {
|
||||
// the allowedTweak value should therefore the amount to at most 10% of the
|
||||
// searchSpaceSize. TODO(me): floor this down.
|
||||
func getAllowedTweak(searchSpaceSize float64) float64 {
|
||||
// TODO(me): have this passed to HillClimb and from there into this func.
|
||||
// return (bench.MaxNeighbourVariancePercent * 0.5) * (searchSpaceSize * 0.01)
|
||||
return bench.MaxNeighbourVariancePercent * (searchSpaceSize * 0.01)
|
||||
}
|
||||
|
||||
@ -103,7 +107,9 @@ func genNeighbours(n, dimens int, benchName string, origin []float64, neighbVals
|
||||
// create a new representation of the uniform distribution with the bounds
|
||||
// unset for the moment, since we need to find out what exactly those ought
|
||||
// to be (and we will - a couple of lines later).
|
||||
// uniform := distuv.Uniform{Src: time.Now().UnixMicro()}
|
||||
uniform := distuv.Uniform{}
|
||||
// uniform.Src.Seed(uint64(time.Now().UnixNano()))
|
||||
params := bench.FunctionParams[benchName]
|
||||
// get bench function bounds.
|
||||
benchMin := params.Min()
|
||||
@ -116,6 +122,7 @@ func genNeighbours(n, dimens int, benchName string, origin []float64, neighbVals
|
||||
uniform.Src = rand.NewSource(uint64(time.Now().UnixNano()))
|
||||
|
||||
for _, v := range neighbVals {
|
||||
// for _, v := range neighbVals {
|
||||
for i := 0; i < dimens; i++ {
|
||||
newMin := origin[i] - allowedTweak
|
||||
|
||||
@ -130,7 +137,9 @@ func genNeighbours(n, dimens int, benchName string, origin []float64, neighbVals
|
||||
if newMin > benchMax {
|
||||
uniform.Max = newMax
|
||||
}
|
||||
// fmt.Println("newMin:", newMin, "newMax", newMax)
|
||||
|
||||
// v = append(v, uniform.Rand())
|
||||
v[i] = uniform.Rand()
|
||||
}
|
||||
}
|
||||
@ -236,7 +245,7 @@ func HillClimb(
|
||||
|
||||
funcStats.BenchResults = make([]stats.BenchRound, minIters)
|
||||
|
||||
// create a source of preudo-randomness.
|
||||
// create and seed a source of preudo-randomness
|
||||
src := rand.NewSource(uint64(rand.Int63()))
|
||||
// src := rand.NewSource(uint64(time.Now().UnixNano()))
|
||||
|
||||
@ -249,6 +258,7 @@ func HillClimb(
|
||||
// create and stochastically populate the vals slice.
|
||||
initVals := make([]float64, dimens)
|
||||
|
||||
// reseed using current time.
|
||||
uniDist.Src = src
|
||||
|
||||
var bestResult float64
|
||||
@ -337,6 +347,7 @@ func HillClimb(
|
||||
shcMeans.BenchMeans = append(shcMeans.BenchMeans, *dimXMean)
|
||||
}
|
||||
|
||||
// log.Printf("%+v\n", shcMeans)
|
||||
sort.Sort(shcMeans)
|
||||
|
||||
// export AlgoMeans.
|
||||
|
@ -29,6 +29,8 @@ var FunctionParams = map[string]funcParams{
|
||||
|
||||
// Schwefel computes the value of the Schwefel function for x.
|
||||
func Schwefel(x []float64) float64 {
|
||||
// - Domain is | x_i | < 500
|
||||
// - Global minimum at fmin = -122569.5 at x_i = 420.9687
|
||||
var res float64
|
||||
|
||||
for _, val := range x {
|
||||
|
25
flake.nix
25
flake.nix
@ -20,9 +20,15 @@
|
||||
}: let
|
||||
projname = "math-optim";
|
||||
|
||||
system.configurationRevision =
|
||||
self.rev
|
||||
or throw "Refusing to build from a dirty Git tree!";
|
||||
nix.registry.nixpkgs.flake = nixpkgs;
|
||||
|
||||
# to work with older version of flakes
|
||||
lastModifiedDate =
|
||||
self.lastModifiedDate or self.lastModified or "19700101";
|
||||
# lastModifiedDate = "19700101";
|
||||
|
||||
# Generate a user-friendly version number.
|
||||
version = "v0.0.0";
|
||||
@ -57,8 +63,12 @@
|
||||
pname = "${projname}";
|
||||
buildInputs = [
|
||||
go
|
||||
# gcc
|
||||
# glibc
|
||||
# glibc.static
|
||||
];
|
||||
nativeBuildInputs = [pkgconfig];
|
||||
# nativeBuildInputs = [go glibc.static];
|
||||
|
||||
overrideModAttrs = _: {
|
||||
# GOPROXY = "direct";
|
||||
@ -189,11 +199,22 @@
|
||||
{
|
||||
name = "${projname}-" + version;
|
||||
|
||||
dontAutoPatchelf = "";
|
||||
GOFLAGS = "-buildmode=pie -trimpath -mod=readonly -modcacherw";
|
||||
GOLDFLAGS = "-s -w -X main.version=${version}";
|
||||
CGO_CFLAGS = "-g0 -mtune=native";
|
||||
CGO_CFLAGS = "-g0 -Ofast -mtune=native -flto";
|
||||
CGO_LDFLAGS = "-Wl,-O1,-sort-common,-as-needed,-z,relro,-z,now,-flto -pthread";
|
||||
# GOLDFLAGS = "-s -w -X main.version=${version} -linkmode external -extldflags -static";
|
||||
# CGO_CFLAGS = "-g0 -mtune=native
|
||||
# -I${pkgs.glibc.dev}/include
|
||||
# ";
|
||||
# LDFLAGS = "-L${pkgs.glibc}/lib";
|
||||
# CGO_LDFLAGS = "
|
||||
# -Wl,-O1,-sort-common,-as-needed,-z,relro,-z,now,-flto -pthread
|
||||
# -L${pkgs.glibc}/lib
|
||||
# ";
|
||||
GOPROXY = "direct";
|
||||
# GOMEMLIMIT = "10GiB";
|
||||
|
||||
shellHook = ''
|
||||
echo " -- in math-optim dev shell..."
|
||||
@ -212,6 +233,8 @@
|
||||
statix
|
||||
alejandra
|
||||
|
||||
# glibc.static
|
||||
|
||||
## ad-hoc cmds
|
||||
gob
|
||||
gota
|
||||
|
@ -10,7 +10,7 @@
|
||||
\section{Per-algo benchmark comparison statistics}
|
||||
{{ range $i, $v := .AllTables.TexFiles }}
|
||||
{{- range $j, $u := $v.FilePaths }}
|
||||
\input{ {{- $u -}} }
|
||||
\input{ {{- printf "{%s}" $u -}} }
|
||||
\newpage
|
||||
{{- end -}}
|
||||
{{ end }}
|
||||
|
@ -64,7 +64,7 @@ func NewPicList() *PicList {
|
||||
// SavePicsToFile saves each pic list for all bench funcs of a specified algo
|
||||
// to a file.
|
||||
func SavePicsToFile(pls, plsMean []PicList, algoName string) {
|
||||
var paths []string
|
||||
paths := make([]string, 0, len(pls))
|
||||
|
||||
ptf := picTexFiles{Algo: algoName}
|
||||
|
||||
|
@ -19,8 +19,10 @@
|
||||
{\includegraphics[scale=0.45]{ {{- printf "%s" $v.FilePath -}} }}
|
||||
\caption{ {{- printf "\\scriptsize{%s}" $v.Caption -}} }
|
||||
\end{subfigure}
|
||||
% \hspace{1.3em}
|
||||
\hfill
|
||||
{{- end -}}
|
||||
% \newline
|
||||
{{ range $k, $w := .PicsMean }}
|
||||
\begin{subfigure}{0.30\textwidth}
|
||||
\vspace{2em}
|
||||
@ -29,6 +31,7 @@
|
||||
{\includegraphics[scale=0.45]{ {{- printf "%s" $w.FilePath -}} }}
|
||||
\caption{ {{- printf "\\scriptsize{%s}" $w.Caption -}} }
|
||||
\end{subfigure}
|
||||
% \hspace{1.3em}
|
||||
\hfill
|
||||
{{- end }}
|
||||
\caption{ {{- printf "%s - %s" .Algo .Bench -}} }
|
||||
|
@ -28,6 +28,10 @@ var (
|
||||
tmplReportFile []byte
|
||||
)
|
||||
|
||||
func GetOutPrefix() string {
|
||||
return outPrefix
|
||||
}
|
||||
|
||||
// GetPicsDirPrefix returns the path to the folder meant for tex files.
|
||||
func GetTexDir() string {
|
||||
return outPrefix + texDir
|
||||
|
@ -7,11 +7,14 @@
|
||||
left=12mm,
|
||||
right=12mm,
|
||||
}
|
||||
% \usepackage{lmodern}
|
||||
\usepackage[utf8]{inputenc}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage[fleqn]{amsmath}
|
||||
\usepackage{amssymb}
|
||||
\usepackage{amsfonts}
|
||||
% \usepackage{fontspec}
|
||||
% \usefonttheme[onlymath]{serif}
|
||||
\usepackage{multirow}
|
||||
\usepackage{graphicx}
|
||||
\usepackage{textcomp}
|
||||
@ -24,6 +27,7 @@
|
||||
% inkscapelatex=false is important to not have jumbled plot labels as a result of latex trying to render plot/axis labels with the default latex fonts.
|
||||
\svgsetup{inkscapelatex=false,clean=true,inkscapepath=svgsubdir}
|
||||
\pdfsuppresswarningpagegroup=1 % pdflatex complains svg-turned-pdf files
|
||||
\pdfinclusioncopyfonts=1
|
||||
\usepackage{meta}
|
||||
\usepackage[affil-it]{authblk}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
\subsection{ {{- .Algo -}} }
|
||||
|
||||
\begin{table}[!htb]
|
||||
% \begin{tabular}[t]{ |l|{{- range $i, $v := .ColLayout }}{{$v}}| {{- end}} }
|
||||
\resizebox{\columnwidth}{!}{\begin{tabular}[t]{r||{{- range $i, $v := .ColLayout }}{{$v}}| {{- end -}} }
|
||||
\textbf{params} & {{ range $i, $v := .ColNames }}{{ printf "\\textbf{%s}" $v }} & {{ end}}\\
|
||||
{{- range $j, $v := .Rs }}
|
||||
|
2
run.go
2
run.go
@ -19,6 +19,7 @@ func run() {
|
||||
|
||||
doPrint := flag.Bool("printreport", true, "print report.tex to console")
|
||||
generate := flag.Bool("generate", true, "run algos and generate plot pics/statistical tables (anew)")
|
||||
// TODO(me): add flag for plot output format: -plotout=(svg,eps,pdf)
|
||||
flag.Parse()
|
||||
|
||||
if *generate {
|
||||
@ -33,6 +34,7 @@ func run() {
|
||||
|
||||
go algo.DoRandomSearch(&wg, &m)
|
||||
go algo.DoStochasticHillClimbing(&wg, &m)
|
||||
// go algo.DoStochasticHillClimbing100Neigh(&wg, &m)
|
||||
|
||||
wg.Wait()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user