2022-06-18 05:27:10 +02:00
|
|
|
// Copyright 2022 wanderer <a_mirre at utb dot cz>
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
|
|
|
|
package algo
|
2022-06-20 03:32:48 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
2022-07-08 22:51:31 +02:00
|
|
|
"sync"
|
2022-07-08 19:22:09 +02:00
|
|
|
"time"
|
2022-06-20 03:32:48 +02:00
|
|
|
|
2022-07-12 16:56:49 +02:00
|
|
|
"git.dotya.ml/wanderer/math-optim/report"
|
2022-06-20 03:32:48 +02:00
|
|
|
"git.dotya.ml/wanderer/math-optim/stats"
|
2022-07-10 20:54:48 +02:00
|
|
|
"git.dotya.ml/wanderer/math-optim/util"
|
2022-07-08 03:32:07 +02:00
|
|
|
"gonum.org/v1/gonum/floats"
|
2022-06-20 03:32:48 +02:00
|
|
|
"gonum.org/v1/plot"
|
|
|
|
"gonum.org/v1/plot/plotter"
|
|
|
|
"gonum.org/v1/plot/plotutil"
|
|
|
|
"gonum.org/v1/plot/vg"
|
|
|
|
)
|
|
|
|
|
2022-07-05 22:56:01 +02:00
|
|
|
const preferredFontStyle = "Mono"
|
|
|
|
|
2022-07-08 19:20:21 +02:00
|
|
|
// violating the limit of 30, TODO(me): split this up.
|
|
|
|
// nolint: gocognit
|
2022-07-08 22:51:31 +02:00
|
|
|
func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, wg *sync.WaitGroup) {
|
|
|
|
defer wg.Done() // does this work with panic in the mix? TODO(me): find out.
|
|
|
|
|
2022-07-08 19:22:09 +02:00
|
|
|
start := time.Now()
|
2022-07-12 16:56:49 +02:00
|
|
|
|
|
|
|
picsDir := report.GetPicsDir()
|
|
|
|
|
|
|
|
if err := util.CreatePath(picsDir); err != nil {
|
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
|
2022-06-20 03:32:48 +02:00
|
|
|
pWidth := 13 * vg.Centimeter
|
|
|
|
pHeight := 13 * vg.Centimeter
|
|
|
|
|
2022-07-08 19:00:11 +02:00
|
|
|
plotter.DefaultFont.Typeface = preferredFontStyle
|
2022-07-08 19:01:21 +02:00
|
|
|
plotter.DefaultLineStyle.Width = vg.Points(1.5)
|
2022-07-08 19:00:11 +02:00
|
|
|
|
2022-07-08 18:16:51 +02:00
|
|
|
for _, s := range algoStats {
|
2022-06-20 03:32:48 +02:00
|
|
|
p := plot.New()
|
|
|
|
p.Title.Text = s.Algo + ", D=" + fmt.Sprint(s.Dimens) +
|
|
|
|
", func=" + s.BenchFuncStats[0].BenchName +
|
|
|
|
", G=" + fmt.Sprint(s.Generations) +
|
|
|
|
", I=" + fmt.Sprint(s.Iterations)
|
|
|
|
p.X.Label.Text = "Generations"
|
2022-07-05 22:56:01 +02:00
|
|
|
p.X.Label.TextStyle.Font.Variant = preferredFontStyle
|
|
|
|
p.X.Label.TextStyle.Font.Weight = 1 // Medium
|
2022-07-08 17:55:15 +02:00
|
|
|
p.X.Tick.Label.Font.Variant = preferredFontStyle
|
2022-06-20 03:32:48 +02:00
|
|
|
p.Y.Label.Text = "CF value"
|
2022-07-05 22:56:01 +02:00
|
|
|
p.Y.Label.TextStyle.Font.Variant = preferredFontStyle
|
|
|
|
p.Y.Label.TextStyle.Font.Weight = 1 // Medium
|
2022-07-08 17:55:15 +02:00
|
|
|
p.Y.Tick.Label.Font.Variant = preferredFontStyle
|
2022-07-05 22:56:01 +02:00
|
|
|
|
2022-07-08 17:50:57 +02:00
|
|
|
p.Title.TextStyle.Font.Size = 11.5
|
|
|
|
p.Title.TextStyle.Font.Variant = "Sans"
|
2022-07-05 22:56:01 +02:00
|
|
|
p.Title.TextStyle.Font.Weight = 2 // SemiBold
|
2022-07-08 17:50:57 +02:00
|
|
|
p.Title.Padding = 5 * vg.Millimeter
|
2022-06-20 03:32:48 +02:00
|
|
|
|
|
|
|
for _, dim := range s.BenchFuncStats {
|
|
|
|
// infinite thanks to this SO comment for the interface "hack":
|
|
|
|
// https://stackoverflow.com/a/44872993
|
|
|
|
lines := make([]interface{}, 0)
|
|
|
|
|
2022-07-08 17:17:25 +02:00
|
|
|
for _, iter := range dim.Solution {
|
2022-06-20 03:32:48 +02:00
|
|
|
// mark the end of the X axis with len(iter.Results).
|
|
|
|
p.X.Max = float64(len(iter.Results))
|
|
|
|
|
2022-07-08 19:04:05 +02:00
|
|
|
if floats.Min(iter.Results) < p.Y.Min {
|
|
|
|
p.Y.Min = floats.Min(iter.Results)
|
|
|
|
}
|
|
|
|
|
|
|
|
if floats.Max(iter.Results) > p.Y.Max {
|
|
|
|
p.Y.Max = floats.Max(iter.Results)
|
|
|
|
}
|
2022-07-08 03:32:07 +02:00
|
|
|
|
2022-06-20 03:32:48 +02:00
|
|
|
pts := make(plotter.XYs, len(iter.Results))
|
|
|
|
|
|
|
|
// fill the plotter with datapoints.
|
|
|
|
for k, res := range iter.Results {
|
|
|
|
pts[k].X = float64(k)
|
|
|
|
pts[k].Y = res
|
|
|
|
}
|
|
|
|
|
2022-07-08 17:17:25 +02:00
|
|
|
lines = append(lines, pts)
|
2022-06-20 03:32:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
err := plotutil.AddLines(
|
|
|
|
p,
|
|
|
|
lines...,
|
|
|
|
)
|
|
|
|
if err != nil {
|
2022-07-08 22:51:31 +02:00
|
|
|
// panic (don't panic, I know) instead of a hard exit.
|
|
|
|
log.Panic(err)
|
2022-06-20 03:32:48 +02:00
|
|
|
}
|
|
|
|
|
2022-07-12 16:56:49 +02:00
|
|
|
filename := picsDir +
|
2022-06-20 03:32:48 +02:00
|
|
|
fPrefix + "-" +
|
2022-07-10 20:54:48 +02:00
|
|
|
util.SanitiseFName(s.Algo) + "-" +
|
|
|
|
util.SanitiseFName(dim.BenchName) + "-" +
|
2022-06-20 03:32:48 +02:00
|
|
|
fmt.Sprint(s.Dimens) + "D-" +
|
|
|
|
fmt.Sprint(s.Generations) + "G-" +
|
2022-07-11 21:41:05 +02:00
|
|
|
fmt.Sprint(len(dim.Solution)) + "I"
|
2022-06-20 03:32:48 +02:00
|
|
|
|
2022-07-08 19:22:09 +02:00
|
|
|
elapsed := time.Since(start)
|
2022-07-11 21:41:05 +02:00
|
|
|
info := "saving img to file: " + filename + fExt +
|
2022-07-08 19:22:09 +02:00
|
|
|
" [generated in " + fmt.Sprint(elapsed) + "]"
|
2022-07-08 19:20:21 +02:00
|
|
|
|
|
|
|
if s.Algo == "Random Search" {
|
|
|
|
printRandomSearch(info)
|
|
|
|
} else {
|
|
|
|
printSHC(info)
|
|
|
|
}
|
2022-06-20 03:32:48 +02:00
|
|
|
|
|
|
|
// Save the plot to a file using the above-constructed 'filename'.
|
|
|
|
if err := p.Save(
|
|
|
|
pWidth,
|
|
|
|
pHeight,
|
2022-07-11 21:41:05 +02:00
|
|
|
filename+fExt,
|
2022-06-20 03:32:48 +02:00
|
|
|
); err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|