| // Copyright ©2017 The Gonum Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package mat |
| |
| import ( |
| "testing" |
| |
| "golang.org/x/exp/rand" |
| ) |
| |
| func TestHOGSVD(t *testing.T) { |
| t.Parallel() |
| const tol = 1e-10 |
| rnd := rand.New(rand.NewSource(1)) |
| for cas, test := range []struct { |
| r, c int |
| }{ |
| {5, 3}, |
| {5, 5}, |
| {150, 150}, |
| {200, 150}, |
| |
| // Calculating A_i*A_jᵀ and A_j*A_iᵀ fails for wide matrices. |
| {3, 5}, |
| } { |
| r := test.r |
| c := test.c |
| for n := 3; n < 6; n++ { |
| data := make([]Matrix, n) |
| dataCopy := make([]*Dense, n) |
| for trial := 0; trial < 10; trial++ { |
| for i := range data { |
| d := NewDense(r, c, nil) |
| for j := range d.mat.Data { |
| d.mat.Data[j] = rnd.Float64() |
| } |
| data[i] = d |
| dataCopy[i] = DenseCopyOf(d) |
| } |
| |
| var gsvd HOGSVD |
| ok := gsvd.Factorize(data...) |
| if r >= c { |
| if !ok { |
| t.Errorf("HOGSVD factorization failed for %d %d×%d matrices: %v", n, r, c, gsvd.Err()) |
| continue |
| } |
| } else { |
| if ok { |
| t.Errorf("HOGSVD factorization unexpectedly succeeded for %d %d×%d matrices", n, r, c) |
| } |
| continue |
| } |
| for i := range data { |
| if !Equal(data[i], dataCopy[i]) { |
| t.Errorf("A changed during call to HOGSVD.Factorize") |
| } |
| } |
| u, s, v := extractHOGSVD(&gsvd) |
| for i, want := range data { |
| var got Dense |
| sigma := NewDense(c, c, nil) |
| for j := 0; j < c; j++ { |
| sigma.Set(j, j, s[i][j]) |
| } |
| |
| got.Product(u[i], sigma, v.T()) |
| if !EqualApprox(&got, want, tol) { |
| t.Errorf("test %d n=%d trial %d: unexpected answer\nU_%[4]d * S_%[4]d * Vᵀ:\n% 0.2f\nD_%d:\n% 0.2f", |
| cas, n, trial, i, Formatted(&got, Excerpt(5)), i, Formatted(want, Excerpt(5))) |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| func extractHOGSVD(gsvd *HOGSVD) (u []*Dense, s [][]float64, v *Dense) { |
| u = make([]*Dense, gsvd.Len()) |
| s = make([][]float64, gsvd.Len()) |
| for i := 0; i < gsvd.Len(); i++ { |
| u[i] = &Dense{} |
| gsvd.UTo(u[i], i) |
| s[i] = gsvd.Values(nil, i) |
| } |
| v = &Dense{} |
| gsvd.VTo(v) |
| return u, s, v |
| } |