Skip to content

Commit

Permalink
feat: Added NewHyperbolicVCurve() *VCurveParams to vcurve IRIS module…
Browse files Browse the repository at this point in the history
…. Includes associated test suite for expected output and API struct definitions.

feat: Added NewHyperbolicVCurve() *VCurveParams to vcurve IRIS module. Includes associated test suite for expected output and API struct definitions.
  • Loading branch information
michealroberts committed Dec 17, 2023
1 parent fcf0ebe commit b546d13
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 0 deletions.
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
module github.com/observerly/iris

go 1.19

require gonum.org/v1/gonum v0.14.0

require (
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/tools v0.7.0 // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
44 changes: 44 additions & 0 deletions pkg/vcurve/vcurve.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package vcurve

import (
"math"

"gonum.org/v1/gonum/floats"
"gonum.org/v1/gonum/stat"
)

// Point is a data point with x and y coordinates.
type Point struct {
x float64
Expand All @@ -20,3 +27,40 @@ type VCurveParams struct {
x []float64
y []float64
}

/*
NewHyperbolicVCurve
Creates a new VCurve object ready for applying the Levenberg-Marquardt iterative optimization technique.
The VCurve object is initialized with the data points, and initial guesses for the parameters are calculated from the input data.
*/
func NewHyperbolicVCurve(data VCurve) *VCurveParams {
// Preallocate slices with the exact required capacity
dataX := make([]float64, 0, len(data.Points))
dataY := make([]float64, 0, len(data.Points))

// A single loop to populate the slices
for _, point := range data.Points {
dataX = append(dataX, point.x)
dataY = append(dataY, point.y)
}

// Get the initial guess for the parameter, for A, we take the mean value of the yData:
A := stat.Mean(dataY, nil)

// Get the initial guess for B, for B, we take the min value of the yData:
B := floats.Min(dataY)

// Get the initial guess for C, for C, we take the mean value of the xData:
C := stat.Mean(dataX, nil)

return &VCurveParams{
A: math.Round(A),
B: B,
C: C,
D: 0,
x: dataX,
y: dataY,
}
}
60 changes: 60 additions & 0 deletions pkg/vcurve/vcurve_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package vcurve

import (
"testing"
)

var (
points = []Point{
{x: 29000, y: 40.5},
{x: 29100, y: 36.2},
{x: 29200, y: 31.4},
{x: 29300, y: 28.6},
{x: 29400, y: 23.1},
{x: 29500, y: 21.2},
{x: 29600, y: 16.6},
{x: 29700, y: 13.7},
{x: 29800, y: 6.21},
{x: 29900, y: 4.21},
{x: 30000, y: 3.98},
{x: 30100, y: 4.01},
{x: 30200, y: 4.85},
{x: 30300, y: 11.1},
{x: 30400, y: 15.3},
{x: 30500, y: 22.1},
{x: 30600, y: 21.9},
{x: 30700, y: 27.4},
{x: 30800, y: 32.1},
{x: 30900, y: 36.5},
{x: 31000, y: 39.7},
}
)

func TestNewHyperbolicVCurve(t *testing.T) {
v := NewHyperbolicVCurve(VCurve{
Points: points,
})

// Deconstruct the VCurveParams struct
a, b, c, d := v.A, v.B, v.C, v.D

// Expect the initial guess for A to be the mean value of the yData:
if a != 21 {
t.Errorf("A should be 21, but got %v", a)
}

// Expect the initial guess for B to be the min value of the yData:
if b != 3.98 {
t.Errorf("B should be 3.98, but got %v", b)
}

// Expect the initial guess for C to be the mean value of the xData:
if c != 30000 {
t.Errorf("C should be 30000, but got %v", c)
}

// Expect the initial guess for D to be 0:
if d != 0 {
t.Errorf("D should be 0, but got %v", d)
}
}

0 comments on commit b546d13

Please sign in to comment.