gonum.org/v1/gonum@v0.14.0/lapack/testlapack/dlaln2.go (about) 1 // Copyright ©2016 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. 4 5 package testlapack 6 7 import ( 8 "fmt" 9 "math" 10 "math/cmplx" 11 "testing" 12 13 "golang.org/x/exp/rand" 14 ) 15 16 type Dlaln2er interface { 17 Dlaln2(trans bool, na, nw int, smin, ca float64, a []float64, lda int, d1, d2 float64, b []float64, ldb int, wr, wi float64, x []float64, ldx int) (scale, xnorm float64, ok bool) 18 } 19 20 func Dlaln2Test(t *testing.T, impl Dlaln2er) { 21 rnd := rand.New(rand.NewSource(1)) 22 for _, trans := range []bool{true, false} { 23 for _, na := range []int{1, 2} { 24 for _, nw := range []int{1, 2} { 25 for _, extra := range []int{0, 1, 2, 13} { 26 for cas := 0; cas < 1000; cas++ { 27 testDlaln2(t, impl, trans, na, nw, extra, rnd) 28 } 29 } 30 } 31 } 32 } 33 } 34 35 func testDlaln2(t *testing.T, impl Dlaln2er, trans bool, na, nw, extra int, rnd *rand.Rand) { 36 const tol = 1e-11 37 38 // Generate random input scalars. 39 ca := rnd.NormFloat64() 40 d1 := rnd.NormFloat64() 41 d2 := rnd.NormFloat64() 42 43 var w complex128 44 if nw == 1 { 45 w = complex(rand.NormFloat64(), 0) 46 } else { 47 w = complex(rand.NormFloat64(), rand.NormFloat64()) 48 } 49 smin := dlamchP * (math.Abs(real(w)) + math.Abs(imag(w))) 50 51 // Generate random input matrices. 52 a := randomGeneral(na, na, na+extra, rnd) 53 b := randomGeneral(na, nw, nw+extra, rnd) 54 x := randomGeneral(na, nw, nw+extra, rnd) 55 56 scale, xnormGot, ok := impl.Dlaln2(trans, na, nw, smin, ca, a.Data, a.Stride, d1, d2, b.Data, b.Stride, real(w), imag(w), x.Data, x.Stride) 57 58 prefix := fmt.Sprintf("Case trans=%t, na=%v, nw=%v, extra=%v", trans, na, nw, extra) 59 60 if !generalOutsideAllNaN(a) { 61 t.Errorf("%v: out-of-range write to A\n%v", prefix, a.Data) 62 } 63 if !generalOutsideAllNaN(b) { 64 t.Errorf("%v: out-of-range write to B\n%v", prefix, b.Data) 65 } 66 if !generalOutsideAllNaN(x) { 67 t.Errorf("%v: out-of-range write to X\n%v", prefix, x.Data) 68 } 69 70 // Scale is documented to be <= 1. 71 if scale <= 0 || 1 < scale { 72 t.Errorf("%v: invalid value of scale=%v", prefix, scale) 73 } 74 75 // Calculate the infinity norm of X explicitly. 76 var xnormWant float64 77 for i := 0; i < na; i++ { 78 var rowsum float64 79 for j := 0; j < nw; j++ { 80 rowsum += math.Abs(x.Data[i*x.Stride+j]) 81 } 82 if rowsum > xnormWant { 83 xnormWant = rowsum 84 } 85 } 86 if xnormWant != xnormGot { 87 t.Errorf("Case %v: unexpected xnorm with scale=%v. Want %v, got %v", prefix, scale, xnormWant, xnormGot) 88 } 89 90 if !ok { 91 // If ok is false, the matrix has been perturbed but we don't 92 // know how. Return without comparing both sides of the 93 // equation. 94 return 95 } 96 97 // Compute a complex matrix 98 // M := ca * A - w * D 99 // or 100 // M := ca * Aᵀ - w * D. 101 m := make([]complex128, na*na) 102 if trans { 103 // M = ca * Aᵀ 104 for i := 0; i < na; i++ { 105 for j := 0; j < na; j++ { 106 m[i*na+j] = complex(ca*a.Data[j*a.Stride+i], 0) 107 } 108 } 109 } else { 110 // M = ca * Aᵀ 111 for i := 0; i < na; i++ { 112 for j := 0; j < na; j++ { 113 m[i*na+j] = complex(ca*a.Data[i*a.Stride+j], 0) 114 } 115 } 116 } 117 // Subtract the diagonal matrix w * D. 118 m[0] -= w * complex(d1, 0) 119 if na == 2 { 120 m[3] -= w * complex(d2, 0) 121 } 122 123 // Convert real na×2 matrices X and scale*B into complex na-vectors. 124 cx := make([]complex128, na) 125 cb := make([]complex128, na) 126 switch nw { 127 case 1: 128 for i := 0; i < na; i++ { 129 cx[i] = complex(x.Data[i*x.Stride], 0) 130 cb[i] = complex(scale*b.Data[i*x.Stride], 0) 131 } 132 case 2: 133 for i := 0; i < na; i++ { 134 cx[i] = complex(x.Data[i*x.Stride], x.Data[i*x.Stride+1]) 135 cb[i] = complex(scale*b.Data[i*b.Stride], scale*b.Data[i*b.Stride+1]) 136 } 137 } 138 139 // Compute M * X. 140 mx := make([]complex128, na) 141 for i := 0; i < na; i++ { 142 for j := 0; j < na; j++ { 143 mx[i] += m[i*na+j] * cx[j] 144 } 145 } 146 // Check whether |M * X - scale * B|_max <= tol. 147 for i := 0; i < na; i++ { 148 if cmplx.Abs(mx[i]-cb[i]) > tol { 149 t.Errorf("Case %v: unexpected value of left-hand side at row %v with scale=%v. Want %v, got %v", prefix, i, scale, cb[i], mx[i]) 150 } 151 } 152 }