stat: make CCA and PCA analysis reuse allocations
MODIFY
cca_example_test.go
cca_example_test.go
@@ -78,17 +78,18 @@ func ExampleCanonicalCorrelations() {
fmt.Printf("corRaw = %.4f", mat64.Formatted(corRaw, mat64.Prefix(" ")))
// Calculate the canonical correlations.
- cc, err := stat.CanonicalCorrelations(xdata, ydata, nil)
+ var cc stat.CC
+ err := cc.CanonicalCorrelations(xdata, ydata, nil)
if err != nil {
log.Fatal(err)
}
// Unpack cc.
ccors := cc.Corrs(nil)
- pVecs := cc.Left(true)
- qVecs := cc.Right(true)
- phiVs := cc.Left(false)
- psiVs := cc.Right(false)
+ pVecs := cc.Left(nil, true)
+ qVecs := cc.Right(nil, true)
+ phiVs := cc.Left(nil, false)
+ psiVs := cc.Right(nil, false)
// Canonical Correlation Matrix, or the correlations between the sphered
// data.

MODIFY
cca_test.go
cca_test.go
@@ -13,6 +13,7 @@ import (
)
func TestCanonicalCorrelations(t *testing.T) {
+tests:
for i, test := range []struct {
xdata mat64.Matrix
ydata mat64.Matrix
@@ -148,36 +149,43 @@ func TestCanonicalCorrelations(t *testing.T) {
epsilon: 1e-12,
},
} {
- cc, err := stat.CanonicalCorrelations(test.xdata, test.ydata, test.weights)
+ var cc stat.CC
+ var corrs []float64
+ var pVecs, qVecs *mat64.Dense
+ var phiVs, psiVs *mat64.Dense
+ for j := 0; j < 2; j++ {
+ err := cc.CanonicalCorrelations(test.xdata, test.ydata, test.weights)
if err != nil {
- t.Errorf("%d: unexpected error: %v", i, err)
- continue
+ t.Errorf("%d use %d: unexpected error: %v", i, j, err)
+ continue tests
}
- corrs := cc.Corrs(nil)
- pVecs := cc.Left(true)
- qVecs := cc.Right(true)
- phiVs := cc.Left(false)
- psiVs := cc.Right(false)
+ corrs = cc.Corrs(corrs)
+ pVecs = cc.Left(pVecs, true)
+ qVecs = cc.Right(qVecs, true)
+ phiVs = cc.Left(phiVs, false)
+ psiVs = cc.Right(psiVs, false)
if !floats.EqualApprox(corrs, test.wantCorrs, test.epsilon) {
- t.Errorf("%d: unexpected variance result got:%v, want:%v", i, corrs, test.wantCorrs)
+ t.Errorf("%d use %d: unexpected variance result got:%v, want:%v",
+ i, j, corrs, test.wantCorrs)
}
if !mat64.EqualApprox(pVecs, test.wantpVecs, test.epsilon) {
- t.Errorf("%d: unexpected CCA result got:\n%v\nwant:\n%v",
- i, mat64.Formatted(pVecs), mat64.Formatted(test.wantpVecs))
+ t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
+ i, j, mat64.Formatted(pVecs), mat64.Formatted(test.wantpVecs))
}
if !mat64.EqualApprox(qVecs, test.wantqVecs, test.epsilon) {
- t.Errorf("%d: unexpected CCA result got:\n%v\nwant:\n%v",
- i, mat64.Formatted(qVecs), mat64.Formatted(test.wantqVecs))
+ t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
+ i, j, mat64.Formatted(qVecs), mat64.Formatted(test.wantqVecs))
}
if !mat64.EqualApprox(phiVs, test.wantphiVs, test.epsilon) {
- t.Errorf("%d: unexpected CCA result got:\n%v\nwant:\n%v",
- i, mat64.Formatted(phiVs), mat64.Formatted(test.wantphiVs))
+ t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
+ i, j, mat64.Formatted(phiVs), mat64.Formatted(test.wantphiVs))
}
if !mat64.EqualApprox(psiVs, test.wantpsiVs, test.epsilon) {
- t.Errorf("%d: unexpected CCA result got:\n%v\nwant:\n%v",
- i, mat64.Formatted(psiVs), mat64.Formatted(test.wantpsiVs))
+ t.Errorf("%d use %d: unexpected CCA result got:\n%v\nwant:\n%v",
+ i, j, mat64.Formatted(psiVs), mat64.Formatted(test.wantpsiVs))
+ }
}
}
}

MODIFY
pca_example_test.go
pca_example_test.go
@@ -30,16 +30,17 @@ func ExamplePrincipalComponents() {
// Calculate the principal component direction vectors
// and variances.
- vecs, vars, ok := stat.PrincipalComponents(iris, nil)
+ var pc stat.PC
+ ok := pc.PrincipalComponents(iris, nil)
if !ok {
return
}
- fmt.Printf("variances = %.4f\n\n", vars)
+ fmt.Printf("variances = %.4f\n\n", pc.Vars(nil))
// Project the data onto the first 2 principal components.
k := 2
var proj mat64.Dense
- proj.Mul(iris, vecs.View(0, 0, d, k))
+ proj.Mul(iris, pc.Vectors(nil).Slice(0, d, 0, k))
fmt.Printf("proj = %.4f", mat64.Formatted(&proj, mat64.Prefix(" ")))

MODIFY
pca_test.go
pca_test.go
@@ -12,6 +12,7 @@ import (
)
func TestPrincipalComponents(t *testing.T) {
+tests:
for i, test := range []struct {
data mat64.Matrix
weights []float64
@@ -56,6 +57,21 @@ func TestPrincipalComponents(t *testing.T) {
wantVars: []float64{0.1665786313282786, 0.02065509475412993, 0.007944620317765855, 0.0019327647109368329},
epsilon: 1e-12,
},
+ { // Truncated iris data to form wide matrix.
+ data: mat64.NewDense(3, 4, []float64{
+ 5.1, 3.5, 1.4, 0.2,
+ 4.9, 3.0, 1.4, 0.2,
+ 4.7, 3.2, 1.3, 0.2,
+ }),
+ wantVecs: mat64.NewDense(4, 3, []float64{
+ -0.5705187254552365, -0.7505979435049239, 0.08084520834544455,
+ -0.8166537769529318, 0.5615147645527523, -0.032338083338177705,
+ -0.08709186238359454, -0.3482870890450082, -0.22636658336724505,
+ 0, 0, -0.9701425001453315,
+ }),
+ wantVars: []float64{0.0844692361537822, 0.022197430512884326, 0},
+ epsilon: 1e-12,
+ },
{ // Truncated iris data transposed to check for operation on fat input.
data: mat64.NewDense(10, 4, []float64{
5.1, 3.5, 1.4, 0.2,
@@ -131,17 +147,25 @@ func TestPrincipalComponents(t *testing.T) {
epsilon: 1e-12,
},
} {
- vecs, vars, ok := PrincipalComponents(test.data, test.weights)
+ var pc PC
+ var vecs *mat64.Dense
+ var vars []float64
+ for j := 0; j < 2; j++ {
+ ok := pc.PrincipalComponents(test.data, test.weights)
+ vecs = pc.Vectors(vecs)
+ vars = pc.Vars(vars)
if !ok {
- t.Errorf("unexpected SVD failure for test %d", i)
- continue
+ t.Errorf("unexpected SVD failure for test %d use %d", i, j)
+ continue tests
}
if !mat64.EqualApprox(vecs, test.wantVecs, test.epsilon) {
- t.Errorf("%d: unexpected PCA result got:\n%v\nwant:\n%v",
- i, mat64.Formatted(vecs), mat64.Formatted(test.wantVecs))
+ t.Errorf("%d use %d: unexpected PCA result got:\n%v\nwant:\n%v",
+ i, j, mat64.Formatted(vecs), mat64.Formatted(test.wantVecs))
}
if !approxEqual(vars, test.wantVars, test.epsilon) {
- t.Errorf("%d: unexpected variance result got:%v, want:%v", i, vars, test.wantVars)
+ t.Errorf("%d use %d: unexpected variance result got:%v, want:%v",
+ i, j, vars, test.wantVars)
+ }
}
}
}

stat: make CCA and PCA analysis reuse allocations