File: hogsvd_test.go

package info (click to toggle)
golang-gonum-v1-gonum 0.15.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 18,792 kB
  • sloc: asm: 6,252; fortran: 5,271; sh: 377; ruby: 211; makefile: 98
file content (91 lines) | stat: -rw-r--r-- 2,123 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// 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
}