Skip to content

Commit

Permalink
cnf ran: reorganize powermanagement helpers (#160)
Browse files Browse the repository at this point in the history
This moves the powermanagement stats file to be a package under ran and adds unit tests for it. Additionally, the metric collections helpers have been moved to their own package under powermanagement.
  • Loading branch information
klaskosk authored Aug 16, 2024
1 parent 41ac393 commit 9988223
Show file tree
Hide file tree
Showing 6 changed files with 432 additions and 361 deletions.
58 changes: 58 additions & 0 deletions tests/cnf/ran/internal/stats/stats.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package stats

import (
"fmt"
"math"
"slices"
)

// Mean computes the arithmetic mean of the input array.
func Mean(input []float64) (float64, error) {
if len(input) < 1 {
return math.NaN(), fmt.Errorf("input array must have at least 1 element")
}

sum := 0.0
for _, x := range input {
sum += x
}

return sum / float64(len(input)), nil
}

// StdDev computes the population standard deviation of the input array.
func StdDev(input []float64) (float64, error) {
if len(input) < 1 {
return math.NaN(), fmt.Errorf("input array must have at least 1 element")
}

mean, _ := Mean(input)

sum := 0.0
for _, x := range input {
sum += (x - mean) * (x - mean)
}

return math.Sqrt(sum / float64(len(input))), nil
}

// Median computes the median value of the input array.
func Median(input []float64) (float64, error) {
if len(input) < 1 {
return math.NaN(), fmt.Errorf("input array must have at least 1 element")
}

numElements := len(input)

// sort a copy of the input array
inputCopy := make([]float64, numElements)
copy(inputCopy, input)

slices.Sort(inputCopy)

if numElements%2 == 1 {
return inputCopy[numElements/2], nil
}

return (inputCopy[numElements/2] + inputCopy[numElements/2-1]) / 2, nil
}
95 changes: 95 additions & 0 deletions tests/cnf/ran/internal/stats/stats_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package stats

import (
"fmt"
"math"
"testing"

"github.com/stretchr/testify/assert"
)

const epsilon float64 = 1e-9

func TestMean(t *testing.T) {
testCases := []struct {
input []float64
expectedOutput float64
expectedError error
}{
{
input: []float64{1, 2, 3, 4, 5},
expectedOutput: 3,
expectedError: nil,
},
{
input: []float64{},
expectedOutput: math.NaN(),
expectedError: fmt.Errorf("input array must have at least 1 element"),
},
}

for _, testCase := range testCases {
output, err := Mean(testCase.input)
assert.Equal(t, testCase.expectedError, err)

if testCase.expectedError == nil {
assert.InDelta(t, testCase.expectedOutput, output, epsilon)
}
}
}

func TestStdDev(t *testing.T) {
testCases := []struct {
input []float64
expectedOutput float64
expectedError error
}{
{
input: []float64{1, 2, 3, 4, 5},
expectedOutput: math.Sqrt2,
expectedError: nil,
},
{
input: []float64{},
expectedOutput: math.NaN(),
expectedError: fmt.Errorf("input array must have at least 1 element"),
},
}

for _, testCase := range testCases {
output, err := StdDev(testCase.input)
assert.Equal(t, testCase.expectedError, err)

if testCase.expectedError == nil {
assert.InDelta(t, testCase.expectedOutput, output, epsilon)
}
}
}

func TestMedian(t *testing.T) {
testCases := []struct {
input []float64
expectedOutput float64
expectedError error
}{
{
input: []float64{1, 2, 3, 4, 5},
expectedOutput: 3,
expectedError: nil,
},
{
input: []float64{},
expectedOutput: math.NaN(),
expectedError: fmt.Errorf("input array must have at least 1 element"),
},
}

for _, testCase := range testCases {
output, err := Median(testCase.input)
assert.Equal(t, testCase.expectedError, err)

if testCase.expectedError == nil {
assert.InDelta(t, testCase.expectedOutput, output, epsilon)
}
}
}
Loading

0 comments on commit 9988223

Please sign in to comment.