// 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" ) // statsRow represents the header in the table. type statsHdr struct { Algo string BenchFuncName string Dimens int Generations int Iterations int } // statsRow represents a single row in the table. 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 { fmt.Fprintf(os.Stderr, "%+v\n", statsSingleFunc(singleFunc)) } } // statsSingleFunc computes statistics out of results of a single bench func // and returns the statistic table as a []interface{} because it contains // multiple table headers and rows. perhaps a table struct could be returned in // the future. func statsSingleFunc(singleFuncStats []Stats) []interface{} { 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 ) // out contains the constructed table and is returned at the end of // this func. out := make([]interface{}, 0) for _, s := range singleFuncStats { for _, dim := range s.BenchFuncStats { hdr = makeTableHdr( s.Algo, s.BenchFuncStats[0].BenchName, s.Dimens, s.Generations, s.Iterations, ) out = append(out, "\n", hdr, "\n") // 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) out = append(out, row) } } out = append(out, "\n") return out } // makeTableHdr fills the table header with passed information. // TODO(me): add checks to assert only valid inputs are passed in. 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 } // newStatsHdr returns a pointer to a newly created statsHdr instance. func newStatsHdr() *statsHdr { return &statsHdr{} }