From 63da28a8f06d90bf238df975562525781f60bd91 Mon Sep 17 00:00:00 2001 From: surtur Date: Fri, 24 Jun 2022 00:45:43 +0200 Subject: [PATCH] go: add a way to print statistic table --- algo/algo.go | 24 +++++++++---- stats/table.go | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 7 deletions(-) create mode 100644 stats/table.go diff --git a/algo/algo.go b/algo/algo.go index 6763d3a..50fa8ef 100644 --- a/algo/algo.go +++ b/algo/algo.go @@ -5,6 +5,9 @@ package algo import ( "sync" + + "git.dotya.ml/wanderer/math-optim/bench" + "git.dotya.ml/wanderer/math-optim/stats" ) // Values type is just a fancy named []float64 that will allow us to define @@ -19,14 +22,21 @@ func DoRandomSearch(wg *sync.WaitGroup) { printRandomSearch("starting...") - // ng y'all. - schw := RandomSearchNG(10000, 30, []int{5, 10, 20}, "Schwefel") - djg1 := RandomSearchNG(10000, 30, []int{5, 10, 20}, "De Jong 1st") - djg2 := RandomSearchNG(10000, 30, []int{5, 10, 20}, "De Jong 2nd") + // funcCount is the number of bench functions available. + funcCount := len(bench.Functions) + // stats for the current algo (RandomSearch). + algoStats := make([][]stats.Stats, funcCount) - plotAllDims(schw, "plot", ".svg") - plotAllDims(djg1, "plot", ".svg") - plotAllDims(djg2, "plot", ".svg") + // ng y'all. + algoStats[0] = RandomSearchNG(10000, 30, []int{5, 10, 20}, "Schwefel") + algoStats[1] = RandomSearchNG(10000, 30, []int{5, 10, 20}, "De Jong 1st") + algoStats[2] = RandomSearchNG(10000, 30, []int{5, 10, 20}, "De Jong 2nd") + + for i := range algoStats { + plotAllDims(algoStats[i], "plot", ".svg") + } + + stats.PrintStatisticTable(algoStats) } // DoStochasticHillClimbing performs a search using the 'Stochastic Hill diff --git a/stats/table.go b/stats/table.go new file mode 100644 index 0000000..d52893f --- /dev/null +++ b/stats/table.go @@ -0,0 +1,96 @@ +// Copyright 2022 wanderer +// SPDX-License-Identifier: GPL-3.0-or-later + +package stats + +import ( + "fmt" + "os" + + "gonum.org/v1/gonum/floats" + "gonum.org/v1/gonum/stat" +) + +type statsHdr struct { + Algo string + BenchFuncName string + Dimens int + Generations int + Iterations int +} + +type statsRow struct { + Min float64 + Max float64 + Mean float64 + Median float64 + StdDev float64 +} + +// PrintStatisticTable prints to console computed statistics for current algo. +func PrintStatisticTable(algoStats [][]Stats) { + fmt.Fprintln(os.Stderr, "printing statistic table data (min, max, mean, median, stddev)") + + for _, singleFunc := range algoStats { + statsSingleFunc(singleFunc) + } +} + +// statsSingleFunc computes statistics out of results of a single bench func. +func statsSingleFunc(singleFuncStats []Stats) { + var ( + // hdr is the table header as determined based on the data being dealt with. + hdr statsHdr + // row contains the data of the statistic properties being tracked. + row statsRow + ) + + for _, s := range singleFuncStats { + for _, dim := range s.BenchFuncStats { + hdr = makeTableHdr( + s.Algo, + s.BenchFuncStats[0].BenchName, + s.Dimens, + s.Generations, + s.Iterations, + ) + fmt.Fprintln(os.Stderr, hdr) + + // collect the best. + var best []float64 + + for _, iter := range dim.Solution { + last := s.Generations - 1 + + best = append(best, iter.Results[last]) + } + + row.Min = floats.Min(best) + row.Max = floats.Max(best) + row.Mean = stat.Mean(best, nil) + row.Median = stat.Mean(best, nil) + row.StdDev = stat.StdDev(best, nil) + + fmt.Fprintln(os.Stderr, row) + } + } +} + +func makeTableHdr( + algo, benchFuncName string, + dimens, generations, iterations int, +) statsHdr { + hdr := newStatsHdr() + + hdr.Algo = algo + hdr.BenchFuncName = benchFuncName + hdr.Dimens = dimens + hdr.Generations = generations + hdr.Iterations = iterations + + return *hdr +} + +func newStatsHdr() *statsHdr { + return &statsHdr{} +}