diff --git a/algo/algo.go b/algo/algo.go index 9ca26e1..cbeb8a4 100644 --- a/algo/algo.go +++ b/algo/algo.go @@ -7,6 +7,7 @@ import ( "sync" "git.dotya.ml/wanderer/math-optim/bench" + "git.dotya.ml/wanderer/math-optim/report" "git.dotya.ml/wanderer/math-optim/stats" ) @@ -14,8 +15,6 @@ import ( // methods over it. type Values []float64 -var plotWg sync.WaitGroup - // DoRandomSearch executes a search using the 'Random search' method. func DoRandomSearch(wg *sync.WaitGroup) { defer wg.Done() @@ -41,15 +40,19 @@ func DoRandomSearch(wg *sync.WaitGroup) { algoStats[i] = s } - for i := range algoStats { - plotWg.Add(1) + pCh := make(chan report.PicList, funcCount*len(bench.Dimensions)) - go plotAllDims(algoStats[i], "plot", ".svg", &plotWg) + for i := range algoStats { + go plotAllDims(algoStats[i], "plot", ".svg", pCh) + } + + for range algoStats { + pL := <-pCh + + report.SavePicsToFile(pL, "Random Search") } stats.SaveTable("Random Search", algoStats) - - plotWg.Wait() } // DoStochasticHillClimbing performs a search using the 'Stochastic Hill @@ -77,15 +80,19 @@ func DoStochasticHillClimbing(wg *sync.WaitGroup) { algoStats[i] = s } - for _, algoStat := range algoStats { - plotWg.Add(1) + pCh := make(chan report.PicList, funcCount*len(bench.Dimensions)) - go plotAllDims(algoStat, "plot", ".svg", &plotWg) + for _, algoStat := range algoStats { + go plotAllDims(algoStat, "plot", ".svg", pCh) + } + + for range algoStats { + pL := <-pCh + + report.SavePicsToFile(pL, "Stochastic Hill Climbing") } stats.SaveTable("Stochastic Hill CLimbing", algoStats) - - plotWg.Wait() } func newValues() *Values { diff --git a/algo/plot.go b/algo/plot.go index 37fc4eb..2832a37 100644 --- a/algo/plot.go +++ b/algo/plot.go @@ -6,7 +6,6 @@ package algo import ( "fmt" "log" - "sync" "time" "git.dotya.ml/wanderer/math-optim/report" @@ -21,19 +20,25 @@ import ( const preferredFontStyle = "Mono" -// violating the limit of 30, TODO(me): split this up. -// nolint: gocognit -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. - +// edit: now not violating gocognit limit of 30, TODO(me): still split this up. +func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, ch chan report.PicList) { start := time.Now() picsDir := report.GetPicsDir() + // create picsDir (if not exists), fail on error, no point in going on + // parsing algoStats and computing images if we cannot save them. if err := util.CreatePath(picsDir); err != nil { - log.Println(err) + log.Fatalln("went to create picsDir, there was an issue: ", err) } + pL := report.NewPicList() + pics := make([]report.Pic, 0) + + // since the algoStats only contains results of a single algo, it's safe to + // set the value like this. + pL.Algo = algoStats[0].Algo + pWidth := 13 * vg.Centimeter pHeight := 13 * vg.Centimeter @@ -42,10 +47,18 @@ func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, wg *sync.WaitGro for _, s := range algoStats { p := plot.New() + pic := report.NewPic() + 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) + + pic.Caption = p.Title.Text + // since a single stat slice of algoStats only contains results of a + // single bench func, it's safe to set the value like this. + pL.Bench = s.BenchFuncStats[0].BenchName + p.X.Label.Text = "Generations" p.X.Label.TextStyle.Font.Variant = preferredFontStyle p.X.Label.TextStyle.Font.Weight = 1 // Medium @@ -105,6 +118,9 @@ func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, wg *sync.WaitGro fmt.Sprint(s.Generations) + "G-" + fmt.Sprint(len(dim.Solution)) + "I" + // set pic file path (later used in tmpl generation) + pic.FilePath = filename + elapsed := time.Since(start) info := "saving img to file: " + filename + fExt + " [generated in " + fmt.Sprint(elapsed) + "]" @@ -123,6 +139,13 @@ func plotAllDims(algoStats []stats.Stats, fPrefix, fExt string, wg *sync.WaitGro ); err != nil { panic(err) } + + // save pic. + pics = append(pics, *pic) } } + + pL.Pics = pics + + ch <- *pL } diff --git a/report/pic.go b/report/pic.go index 2fa4884..ccffaee 100644 --- a/report/pic.go +++ b/report/pic.go @@ -40,6 +40,16 @@ func SavePicsToFile(p PicList, algoName string) { safeName := util.SanitiseFName(p.Algo + "-" + p.Bench) texPicsFile := GetTexDir() + "pics-" + safeName + ".tex" tmplPicsFile := "report/pics.tmpl" + + if _, err := os.Stat(tmplPicsFile); err != nil { + // TODO(me): fix this, same as in table.go. + // this block is relevant for the unit test path, somehow the file is + // not found as defined above. + log.Println(err, `, weird test behaviour , prepending "../"`) + + tmplPicsFile = "../" + tmplPicsFile + } + tmplPics := template.Must(template.ParseFiles(tmplPicsFile)) // make sure the output dir exists, else die early.