Skip to content

Commit 7ca54ed

Browse files
committed
fit: add Poly to fit polynomials
Signed-off-by: Sebastien Binet <[email protected]>
1 parent 0591db6 commit 7ca54ed

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

fit/poly.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright ©2025 The go-hep Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package fit // import "go-hep.org/x/hep/fit"
6+
7+
import (
8+
"fmt"
9+
"slices"
10+
11+
"gonum.org/v1/gonum/mat"
12+
)
13+
14+
// Poly fits a polynomial p of degree `degree` to points (x, y):
15+
//
16+
// p(x) = p[0] * x^deg + ... + p[deg]
17+
func Poly(xs, ys []float64, degree int) ([]float64, error) {
18+
var (
19+
a = vandermonde(xs, degree+1)
20+
b = mat.NewDense(len(ys), 1, ys)
21+
o = make([]float64, degree+1)
22+
c = mat.NewDense(degree+1, 1, o)
23+
)
24+
25+
var qr mat.QR
26+
qr.Factorize(a)
27+
28+
const trans = false
29+
err := qr.SolveTo(c, trans, b)
30+
if err != nil {
31+
return nil, fmt.Errorf("could not solve QR: %w", err)
32+
}
33+
34+
slices.Reverse(o)
35+
return o, nil
36+
}
37+
38+
func vandermonde(a []float64, d int) *mat.Dense {
39+
x := mat.NewDense(len(a), d, nil)
40+
for i := range a {
41+
for j, p := 0, 1.0; j < d; j, p = j+1, p*a[i] {
42+
x.Set(i, j, p)
43+
}
44+
}
45+
return x
46+
}

fit/poly_example_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright ©2025 The go-hep Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package fit_test
6+
7+
import (
8+
"fmt"
9+
"log"
10+
11+
"go-hep.org/x/hep/fit"
12+
)
13+
14+
func ExamplePoly() {
15+
var (
16+
xs = []float64{0.0, 1.0, 2.0, 3.0, +4.0, +5.0}
17+
ys = []float64{0.0, 0.8, 0.9, 0.1, -0.8, -1.0}
18+
degree = 3
19+
zs, err = fit.Poly(xs, ys, degree)
20+
)
21+
22+
if err != nil {
23+
log.Fatalf("could not fit polynomial: %v", err)
24+
}
25+
26+
fmt.Printf("z = %+.5f\n", zs)
27+
// Output:
28+
// z = [+0.08704 -0.81349 +1.69312 -0.03968]
29+
}

0 commit comments

Comments
 (0)