chore: add all updates, sort out later
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
leo 2022-12-24 11:30:22 +01:00
parent c3b9ddee27
commit 68b14f9960
Signed by: wanderer
SSH Key Fingerprint: SHA256:Dp8+iwKHSlrMEHzE3bJnPng70I7LEsa3IJXRH/U+idQ
16 changed files with 155 additions and 6 deletions

@ -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

@ -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

@ -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)

@ -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 {

@ -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

@ -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()