blas/testblas: document implementation of some L2 complex tests
MODIFY
blas/testblas/zgbmv.go
blas/testblas/zgbmv.go
package testblas
import (
+ "fmt"
"testing"
"golang.org/x/exp/rand"
@@ -20,9 +21,12 @@ type Zgbmver interface {
func ZgbmvTest(t *testing.T, impl Zgbmver) {
rnd := rand.New(rand.NewSource(1))
for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans, blas.ConjTrans} {
+ // Generate all possible size combinations.
for _, mn := range allPairs([]int{1, 2, 3, 5}, []int{1, 2, 3, 5}) {
m := mn[0]
n := mn[1]
+ // Generate all possible numbers of lower and upper
+ // diagonals. Use slices to reduce indentation.
kLs := make([]int, max(1, m))
for i := range kLs {
kLs[i] = i
@@ -38,6 +42,8 @@ func ZgbmvTest(t *testing.T, impl Zgbmver) {
alpha complex128
beta complex128
}{
+ // All potentially relevant values of
+ // alpha and beta.
{0, 0},
{0, 1},
{0, complex(rnd.NormFloat64(), rnd.NormFloat64())},
@@ -58,16 +64,21 @@ func ZgbmvTest(t *testing.T, impl Zgbmver) {
}
}
+// testZgbmv tests Zgbmv by comparing its output to that of Zgemv.
func testZgbmv(t *testing.T, impl Zgbmver, rnd *rand.Rand, trans blas.Transpose, m, n, kL, kU int, alpha, beta complex128, ldab, incX, incY int) {
const tol = 1e-13
+ // Allocate a dense-storage band matrix filled with NaNs that will be
+ // used as the reference matrix for Zgemv.
lda := max(1, n)
a := makeZGeneral(nil, m, n, lda)
+ // Fill the matrix with zeros.
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
a[i*lda+j] = 0
}
}
+ // Fill the band with random data.
for i := 0; i < m; i++ {
for j := max(0, i-kL); j < min(n, i+kU+1); j++ {
re := rnd.NormFloat64()
@@ -75,10 +86,12 @@ func testZgbmv(t *testing.T, impl Zgbmver, rnd *rand.Rand, trans blas.Transpose,
a[i*lda+j] = complex(re, im)
}
}
+ // Create the actual band matrix.
ab := zPackBand(kL, kU, ldab, m, n, a, lda)
abCopy := make([]complex128, len(ab))
copy(abCopy, ab)
+ // Compute correct lengths of vectors x and y.
var lenX, lenY int
switch trans {
case blas.NoTrans:
@@ -89,6 +102,7 @@ func testZgbmv(t *testing.T, impl Zgbmver, rnd *rand.Rand, trans blas.Transpose,
lenY = n
}
+ // Generate a random complex vector x.
xtest := make([]complex128, lenX)
for i := range xtest {
re := rnd.NormFloat64()
@@ -99,6 +113,7 @@ func testZgbmv(t *testing.T, impl Zgbmver, rnd *rand.Rand, trans blas.Transpose,
xCopy := make([]complex128, len(x))
copy(xCopy, x)
+ // Generate a random complex vector y.
ytest := make([]complex128, lenY)
for i := range ytest {
re := rnd.NormFloat64()
@@ -110,19 +125,23 @@ func testZgbmv(t *testing.T, impl Zgbmver, rnd *rand.Rand, trans blas.Transpose,
want := make([]complex128, len(y))
copy(want, y)
+ // Compute the reference result of alpha*op(A)*x + beta*y, storing it
+ // into want.
impl.Zgemv(trans, m, n, alpha, a, lda, x, incX, beta, want, incY)
+ // Compute alpha*op(A)*x + beta*y, storing the result in-place into y.
impl.Zgbmv(trans, m, n, kL, kU, alpha, ab, ldab, x, incX, beta, y, incY)
+ name := fmt.Sprintf("trans=%v,m=%v,n=%v,kL=%v,kU=%v,lda=%v,incX=%v,incY=%v", trans, m, n, kL, kU, lda, incX, incY)
if !zsame(ab, abCopy) {
- t.Errorf("Case trans=%v,m=%v,n=%v,kL=%v,kU=%v,lda=%v,incX=%v,incY=%v: unexpected modification of ab", trans, m, n, kL, kU, lda, incX, incY)
+ t.Errorf("%v: unexpected modification of ab", name)
}
if !zsame(x, xCopy) {
- t.Errorf("Case trans=%v,m=%v,n=%v,kL=%v,kU=%v,lda=%v,incX=%v,incY=%v: unexpected modification of x", trans, m, n, kL, kU, lda, incX, incY)
+ t.Errorf("%v: unexpected modification of x", name)
}
if !zSameAtNonstrided(y, want, incY) {
- t.Errorf("Case trans=%v,m=%v,n=%v,kL=%v,kU=%v,lda=%v,incX=%v,incY=%v: unexpected modification of y", trans, m, n, kL, kU, lda, incX, incY)
+ t.Errorf("%v: unexpected modification of y", name)
}
if !zEqualApproxAtStrided(y, want, incY, tol) {
- t.Errorf("Case trans=%v,m=%v,n=%v,kL=%v,kU=%v,lda=%v,incX=%v,incY=%v: unexpected result\ngot %v\nwant %v\n", trans, m, n, kL, kU, lda, incX, incY, y, want)
+ t.Errorf("%v: unexpected result\ngot %v\nwant %v\n", name, y, want)
}
}

MODIFY
blas/testblas/zhbmv.go
blas/testblas/zhbmv.go
@@ -25,6 +25,8 @@ func ZhbmvTest(t *testing.T, impl Zhbmver) {
for _, n := range []int{0, 1, 2, 3, 5} {
for k := 0; k < n; k++ {
for _, ldab := range []int{k + 1, k + 1 + 10} {
+ // Generate all possible combinations of given increments.
+ // Use slices to reduce indentation.
for _, inc := range allPairs([]int{-11, 1, 7}, []int{-3, 1, 5}) {
incX := inc[0]
incY := inc[1]
@@ -32,6 +34,8 @@ func ZhbmvTest(t *testing.T, impl Zhbmver) {
alpha complex128
beta complex128
}{
+ // All potentially relevant values of
+ // alpha and beta.
{0, 0},
{0, 1},
{0, complex(rnd.NormFloat64(), rnd.NormFloat64())},
@@ -48,16 +52,23 @@ func ZhbmvTest(t *testing.T, impl Zhbmver) {
}
}
+// testZhbmv tests Zhbmv by comparing its output to that of Zhemv.
func testZhbmv(t *testing.T, impl Zhbmver, rnd *rand.Rand, uplo blas.Uplo, n, k int, alpha, beta complex128, ldab, incX, incY int) {
const tol = 1e-13
+ // Allocate a dense-storage Hermitian band matrix filled with NaNs that will be
+ // used as the reference matrix for Zhemv.
lda := max(1, n)
a := makeZGeneral(nil, n, n, lda)
+ // Fill the matrix with zeros.
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
a[i*lda+j] = 0
}
}
+ // Fill the triangle band with random data, invalidating the imaginary
+ // part of diagonal elements because it should not be referenced by
+ // Zhbmv and Zhemv.
if uplo == blas.Upper {
for i := 0; i < n; i++ {
a[i*lda+i] = complex(rnd.NormFloat64(), math.NaN())
@@ -77,10 +88,12 @@ func testZhbmv(t *testing.T, impl Zhbmver, rnd *rand.Rand, uplo blas.Uplo, n, k
a[i*lda+i] = complex(rnd.NormFloat64(), math.NaN())
}
}
+ // Create the actual Hermitian band matrix.
ab := zPackTriBand(k, ldab, uplo, n, a, lda)
abCopy := make([]complex128, len(ab))
copy(abCopy, ab)
+ // Generate a random complex vector x.
xtest := make([]complex128, n)
for i := range xtest {
re := rnd.NormFloat64()
@@ -91,6 +104,7 @@ func testZhbmv(t *testing.T, impl Zhbmver, rnd *rand.Rand, uplo blas.Uplo, n, k
xCopy := make([]complex128, len(x))
copy(xCopy, x)
+ // Generate a random complex vector y.
ytest := make([]complex128, n)
for i := range ytest {
re := rnd.NormFloat64()
@@ -102,10 +116,13 @@ func testZhbmv(t *testing.T, impl Zhbmver, rnd *rand.Rand, uplo blas.Uplo, n, k
want := make([]complex128, len(y))
copy(want, y)
+ // Compute the reference result of alpha*op(A)*x + beta*y, storing it
+ // into want.
impl.Zhemv(uplo, n, alpha, a, lda, x, incX, beta, want, incY)
+ // Compute alpha*op(A)*x + beta*y, storing the result in-place into y.
impl.Zhbmv(uplo, n, k, alpha, ab, ldab, x, incX, beta, y, incY)
- prefix := fmt.Sprintf("Case uplo=%v,n=%v,k=%v,incX=%v,incY=%v,ldab=%v", uplo, n, k, incX, incY, ldab)
+ prefix := fmt.Sprintf("uplo=%v,n=%v,k=%v,incX=%v,incY=%v,ldab=%v", uplo, n, k, incX, incY, ldab)
if !zsame(x, xCopy) {
t.Errorf("%v: unexpected modification of x", prefix)
}

MODIFY
blas/testblas/ztbmv.go
blas/testblas/ztbmv.go
@@ -37,11 +37,16 @@ func ZtbmvTest(t *testing.T, impl Ztbmver) {
}
}
+// testZtbmv tests Ztbmv by comparing its output to that of Ztrmv.
func testZtbmv(t *testing.T, impl Ztbmver, rnd *rand.Rand, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k, ldab, incX int) {
const tol = 1e-13
+ // Allocate a dense-storage triangular band matrix filled with NaNs that
+ // will be used as the reference matrix for Ztrmv.
lda := max(1, n)
a := makeZGeneral(nil, n, n, lda)
+ // Fill the referenced triangle with random data within the band and
+ // with zeros outside.
if uplo == blas.Upper {
for i := 0; i < n; i++ {
for j := i; j < min(n, i+k+1); j++ {
@@ -66,14 +71,18 @@ func testZtbmv(t *testing.T, impl Ztbmver, rnd *rand.Rand, uplo blas.Uplo, trans
}
}
if diag == blas.Unit {
+ // The diagonal should not be referenced by Ztbmv and Ztrmv, so
+ // invalidate it with NaNs.
for i := 0; i < n; i++ {
a[i*lda+i] = znan
}
}
+ // Create the triangular band matrix.
ab := zPackTriBand(k, ldab, uplo, n, a, lda)
abCopy := make([]complex128, len(ab))
copy(abCopy, ab)
+ // Generate a random complex vector x.
xtest := make([]complex128, n)
for i := range xtest {
re := rnd.NormFloat64()
@@ -87,7 +96,9 @@ func testZtbmv(t *testing.T, impl Ztbmver, rnd *rand.Rand, uplo blas.Uplo, trans
want := make([]complex128, len(x))
copy(want, x)
+ // Compute the reference result of op(A)*x, storing it into want.
impl.Ztrmv(uplo, trans, diag, n, a, lda, want, incX)
+ // Compute op(A)*x, storing the result in-place into x.
impl.Ztbmv(uplo, trans, diag, n, k, ab, ldab, x, incX)
name := fmt.Sprintf("uplo=%v,trans=%v,diag=%v,n=%v,k=%v,ldab=%v,incX=%v", uplo, trans, diag, n, k, ldab, incX)

MODIFY
blas/testblas/ztbsv.go
blas/testblas/ztbsv.go
@@ -37,11 +37,17 @@ func ZtbsvTest(t *testing.T, impl Ztbsver) {
}
}
+// ztbsvTest tests Ztbsv by checking whether Ztbmv followed by Ztbsv
+// round-trip.
func ztbsvTest(t *testing.T, impl Ztbsver, rnd *rand.Rand, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, k, ldab, incX int) {
const tol = 1e-10
+ // Allocate a dense-storage triangular band matrix filled with NaNs that
+ // will be used as a for creating the actual triangular band matrix.
lda := max(1, n)
a := makeZGeneral(nil, n, n, lda)
+ // Fill the referenced triangle of A with random data within the band
+ // and with zeros outside.
if uplo == blas.Upper {
for i := 0; i < n; i++ {
for j := i; j < min(n, i+k+1); j++ {
@@ -66,14 +72,18 @@ func ztbsvTest(t *testing.T, impl Ztbsver, rnd *rand.Rand, uplo blas.Uplo, trans
}
}
if diag == blas.Unit {
+ // The diagonal should not be referenced by Ztbmv and Ztbsv, so
+ // invalidate it with NaNs.
for i := 0; i < n; i++ {
a[i*lda+i] = znan
}
}
+ // Create the triangular band matrix.
ab := zPackTriBand(k, ldab, uplo, n, a, lda)
abCopy := make([]complex128, len(ab))
copy(abCopy, ab)
+ // Generate a random complex vector x.
xtest := make([]complex128, n)
for i := range xtest {
re := rnd.NormFloat64()
@@ -82,16 +92,17 @@ func ztbsvTest(t *testing.T, impl Ztbsver, rnd *rand.Rand, uplo blas.Uplo, trans
}
x := makeZVector(xtest, incX)
+ // Store a copy of x as the correct result that we want.
want := make([]complex128, len(x))
copy(want, x)
- // b <- A*x.
+ // Compute A*x, denoting the result by b and storing it in x.
impl.Ztbmv(uplo, trans, diag, n, k, ab, ldab, x, incX)
- // x <- A^{-1}*b.
+ // Solve A*x = b, that is, x = A^{-1}*b = A^{-1}*A*x.
impl.Ztbsv(uplo, trans, diag, n, k, ab, ldab, x, incX)
+ // If Ztbsv is correct, A^{-1}*A = I and x contains again its original value.
name := fmt.Sprintf("uplo=%v,trans=%v,diag=%v,n=%v,k=%v,ldab=%v,incX=%v", uplo, trans, diag, n, k, ldab, incX)
-
if !zsame(ab, abCopy) {
t.Errorf("%v: unexpected modification of A", name)
}

MODIFY
blas/testblas/ztpsv.go
blas/testblas/ztpsv.go
package testblas
import (
+ "fmt"
"testing"
"golang.org/x/exp/rand"
@@ -32,11 +33,17 @@ func ZtpsvTest(t *testing.T, impl Ztpsver) {
}
}
+// ztpsvTest tests Ztpsv by checking whether Ztpmv followed by Ztpsv
+// round-trip.
func ztpsvTest(t *testing.T, impl Ztpsver, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, incX int, rnd *rand.Rand) {
const tol = 1e-10
+ // Allocate a dense-storage triangular matrix filled with NaNs that
+ // will be used as a for creating the actual triangular matrix in packed
+ // storage.
lda := n
a := makeZGeneral(nil, n, n, max(1, lda))
+ // Fill the referenced triangle of A with random data.
if uplo == blas.Upper {
for i := 0; i < n; i++ {
for j := i; j < n; j++ {
@@ -55,14 +62,18 @@ func ztpsvTest(t *testing.T, impl Ztpsver, uplo blas.Uplo, trans blas.Transpose,
}
}
if diag == blas.Unit {
+ // The diagonal should not be referenced by Ztpmv and Ztpsv, so
+ // invalidate it with NaNs.
for i := 0; i < n; i++ {
a[i*lda+i] = znan
}
}
+ // Create the triangular matrix in packed storage.
ap := zPack(uplo, n, a, n)
apCopy := make([]complex128, len(ap))
copy(apCopy, ap)
+ // Generate a random complex vector x.
xtest := make([]complex128, n)
for i := range xtest {
re := rnd.NormFloat64()
@@ -70,19 +81,25 @@ func ztpsvTest(t *testing.T, impl Ztpsver, uplo blas.Uplo, trans blas.Transpose,
xtest[i] = complex(re, im)
}
x := makeZVector(xtest, incX)
+
+ // Store a copy of x as the correct result that we want.
want := make([]complex128, len(x))
copy(want, x)
+ // Compute A*x, denoting the result by b and storing it in x.
impl.Ztpmv(uplo, trans, diag, n, ap, x, incX)
+ // Solve A*x = b, that is, x = A^{-1}*b = A^{-1}*A*x.
impl.Ztpsv(uplo, trans, diag, n, ap, x, incX)
+ // If Ztpsv is correct, A^{-1}*A = I and x contains again its original value.
+ name := fmt.Sprintf("uplo=%v,trans=%v,diag=%v,n=%v,incX=%v", uplo, trans, diag, n, incX)
if !zsame(ap, apCopy) {
- t.Errorf("Case uplo=%v,trans=%v,diag=%v,n=%v,incX=%v: unexpected modification of ap", uplo, trans, diag, n, incX)
+ t.Errorf("%v: unexpected modification of ap", name)
}
if !zSameAtNonstrided(x, want, incX) {
- t.Errorf("Case uplo=%v,trans=%v,diag=%v,n=%v,incX=%v: unexpected modification of x\nwant %v\ngot %v", uplo, trans, diag, n, incX, want, x)
+ t.Errorf("%v: unexpected modification of x\nwant %v\ngot %v", name, want, x)
}
if !zEqualApproxAtStrided(x, want, incX, tol) {
- t.Errorf("Case uplo=%v,trans=%v,diag=%v,n=%v,incX=%v: unexpected result\nwant %v\ngot %v", uplo, trans, diag, n, incX, want, x)
+ t.Errorf("%v: unexpected result\nwant %v\ngot %v", name, want, x)
}
}

MODIFY
blas/testblas/ztrsv.go
blas/testblas/ztrsv.go
package testblas
import (
+ "fmt"
"testing"
"golang.org/x/exp/rand"
@@ -34,10 +35,14 @@ func ZtrsvTest(t *testing.T, impl Ztrsver) {
}
}
+// ztrsvTest tests Ztrsv by checking whether Ztrmv followed by Ztrsv
+// round-trip.
func ztrsvTest(t *testing.T, impl Ztrsver, uplo blas.Uplo, trans blas.Transpose, diag blas.Diag, n, lda, incX int, rnd *rand.Rand) {
const tol = 1e-10
+ // Allocate a dense-storage triangular matrix A filled with NaNs.
a := makeZGeneral(nil, n, n, lda)
+ // Fill the referenced triangle of A with random data.
if uplo == blas.Upper {
for i := 0; i < n; i++ {
for j := i; j < n; j++ {
@@ -56,6 +61,8 @@ func ztrsvTest(t *testing.T, impl Ztrsver, uplo blas.Uplo, trans blas.Transpose,
}
}
if diag == blas.Unit {
+ // The diagonal should not be referenced by Ztrmv and Ztrsv, so
+ // invalidate it with NaNs.
for i := 0; i < n; i++ {
a[i*lda+i] = znan
}
@@ -63,6 +70,7 @@ func ztrsvTest(t *testing.T, impl Ztrsver, uplo blas.Uplo, trans blas.Transpose,
aCopy := make([]complex128, len(a))
copy(aCopy, a)
+ // Generate a random complex vector x.
xtest := make([]complex128, n)
for i := range xtest {
re := rnd.NormFloat64()
@@ -70,19 +78,25 @@ func ztrsvTest(t *testing.T, impl Ztrsver, uplo blas.Uplo, trans blas.Transpose,
xtest[i] = complex(re, im)
}
x := makeZVector(xtest, incX)
+
+ // Store a copy of x as the correct result that we want.
want := make([]complex128, len(x))
copy(want, x)
+ // Compute A*x, denoting the result by b and storing it in x.
impl.Ztrmv(uplo, trans, diag, n, a, lda, x, incX)
+ // Solve A*x = b, that is, x = A^{-1}*b = A^{-1}*A*x.
impl.Ztrsv(uplo, trans, diag, n, a, lda, x, incX)
+ // If Ztrsv is correct, A^{-1}*A = I and x contains again its original value.
+ name := fmt.Sprintf("uplo=%v,trans=%v,diag=%v,n=%v,lda=%v,incX=%v", uplo, trans, diag, n, lda, incX)
if !zsame(a, aCopy) {
- t.Errorf("Case uplo=%v,trans=%v,diag=%v,n=%v,lda=%v,incX=%v: unexpected modification of A", uplo, trans, diag, n, lda, incX)
+ t.Errorf("%v: unexpected modification of A", name)
}
if !zSameAtNonstrided(x, want, incX) {
- t.Errorf("Case uplo=%v,trans=%v,diag=%v,n=%v,lda=%v,incX=%v: unexpected modification of x\nwant %v\ngot %v", uplo, trans, diag, n, lda, incX, want, x)
+ t.Errorf("%v: unexpected modification of x\nwant %v\ngot %v", name, want, x)
}
if !zEqualApproxAtStrided(x, want, incX, tol) {
- t.Errorf("Case uplo=%v,trans=%v,diag=%v,n=%v,lda=%v,incX=%v: unexpected result\nwant %v\ngot %v", uplo, trans, diag, n, lda, incX, want, x)
+ t.Errorf("%v: unexpected result\nwant %v\ngot %v", name, want, x)
}
}

blas/testblas: document implementation of some L2 complex tests