1 // Copyright ©2017 The Gonum 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.
12 "golang.org/x/exp/rand"
14 "gonum.org/v1/gonum/blas"
15 "gonum.org/v1/gonum/blas/blas64"
18 type Dlatrser interface {
19 Dlatrs(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, normin bool, n int, a []float64, lda int, x []float64, cnorm []float64) (scale float64)
22 func DlatrsTest(t *testing.T, impl Dlatrser) {
23 rnd := rand.New(rand.NewSource(1))
24 for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} {
25 for _, trans := range []blas.Transpose{blas.Trans, blas.NoTrans} {
26 for _, n := range []int{0, 1, 2, 3, 4, 5, 6, 7, 10, 20, 50, 100} {
27 for _, lda := range []int{n, 2*n + 1} {
29 imats := []int{7, 11, 12, 13, 14, 15, 16, 17, 18}
31 imats = append(imats, 19)
33 for _, imat := range imats {
34 testDlatrs(t, impl, imat, uplo, trans, n, lda, rnd)
42 func testDlatrs(t *testing.T, impl Dlatrser, imat int, uplo blas.Uplo, trans blas.Transpose, n, lda int, rnd *rand.Rand) {
45 a := nanSlice(n * lda)
47 work := make([]float64, 3*n)
49 // Generate triangular test matrix and right hand side.
50 diag := dlattr(imat, uplo, trans, n, a, lda, b, work, rnd)
52 // b has not been generated.
57 x := make([]float64, n)
59 // Call Dlatrs with normin=false.
61 scale := impl.Dlatrs(uplo, trans, diag, false, n, a, lda, x, cnorm)
62 prefix := fmt.Sprintf("Case imat=%v (n=%v,lda=%v,trans=%v,uplo=%v,diag=%v", imat, n, lda, trans, uplo, diag)
63 for i, v := range cnorm {
65 t.Errorf("%v: cnorm[%v] not computed (scale=%v,normin=false)", prefix, i, scale)
68 resid, hasNaN := dlatrsResidual(uplo, trans, diag, n, a, lda, scale, cnorm, x, b, work[:n])
70 t.Errorf("%v: unexpected NaN (scale=%v,normin=false)", prefix, scale)
71 } else if resid > tol {
72 t.Errorf("%v: residual %v too large (scale=%v,normin=false)", prefix, resid, scale)
75 // Call Dlatrs with normin=true because cnorm has been filled.
77 scale = impl.Dlatrs(uplo, trans, diag, true, n, a, lda, x, cnorm)
78 resid, hasNaN = dlatrsResidual(uplo, trans, diag, n, a, lda, scale, cnorm, x, b, work[:n])
80 t.Errorf("%v: unexpected NaN (scale=%v,normin=true)", prefix, scale)
81 } else if resid > tol {
82 t.Errorf("%v: residual %v too large (scale=%v,normin=true)", prefix, resid, scale)
86 // dlatrsResidual returns norm(trans(A)*x-scale*b) / (norm(trans(A))*norm(x)*eps)
87 // and whether NaN has been encountered in the process.
88 func dlatrsResidual(uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n int, a []float64, lda int, scale float64, cnorm []float64, x, b, work []float64) (resid float64, hasNaN bool) {
93 // Compute the norm of the triangular matrix A using the column norms
94 // already computed by Dlatrs.
96 if diag == blas.NonUnit {
97 for j := 0; j < n; j++ {
98 tnorm = math.Max(tnorm, math.Abs(a[j*lda+j])+cnorm[j])
101 for j := 0; j < n; j++ {
102 tnorm = math.Max(tnorm, 1+cnorm[j])
108 bi := blas64.Implementation()
110 // Compute norm(trans(A)*x-scale*b) / (norm(trans(A))*norm(x)*eps)
112 ix := bi.Idamax(n, work, 1)
113 xnorm := math.Max(1, math.Abs(work[ix]))
114 xscal := 1 / xnorm / float64(n)
115 bi.Dscal(n, xscal, work, 1)
116 bi.Dtrmv(uplo, trans, diag, n, a, lda, work, 1)
117 bi.Daxpy(n, -scale*xscal, b, 1, work, 1)
118 for _, v := range work {
123 ix = bi.Idamax(n, work, 1)
124 resid = math.Abs(work[ix])
125 ix = bi.Idamax(n, x, 1)
126 xnorm = math.Abs(x[ix])
127 if resid*smlnum <= xnorm {
131 } else if resid > 0 {
134 if resid*smlnum <= tnorm {
138 } else if resid > 0 {