gonum.org/v1/gonum@v0.14.0/blas/testblas/zsyrk.go (about)

     1  // Copyright ©2019 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 testblas
     6  
     7  import (
     8  	"fmt"
     9  	"math/cmplx"
    10  	"testing"
    11  
    12  	"golang.org/x/exp/rand"
    13  
    14  	"gonum.org/v1/gonum/blas"
    15  )
    16  
    17  type Zsyrker interface {
    18  	Zsyrk(uplo blas.Uplo, trans blas.Transpose, n, k int, alpha complex128, a []complex128, lda int, beta complex128, c []complex128, ldc int)
    19  }
    20  
    21  func ZsyrkTest(t *testing.T, impl Zsyrker) {
    22  	for _, uplo := range []blas.Uplo{blas.Upper, blas.Lower} {
    23  		for _, trans := range []blas.Transpose{blas.NoTrans, blas.Trans} {
    24  			name := uploString(uplo) + "-" + transString(trans)
    25  			t.Run(name, func(t *testing.T) {
    26  				for _, n := range []int{0, 1, 2, 3, 4, 5} {
    27  					for _, k := range []int{0, 1, 2, 3, 4, 5, 7} {
    28  						zsyrkTest(t, impl, uplo, trans, n, k)
    29  					}
    30  				}
    31  			})
    32  		}
    33  	}
    34  }
    35  
    36  func zsyrkTest(t *testing.T, impl Zsyrker, uplo blas.Uplo, trans blas.Transpose, n, k int) {
    37  	const tol = 1e-13
    38  
    39  	rnd := rand.New(rand.NewSource(1))
    40  
    41  	rowA, colA := n, k
    42  	if trans == blas.Trans {
    43  		rowA, colA = k, n
    44  	}
    45  	for _, lda := range []int{max(1, colA), colA + 2} {
    46  		for _, ldc := range []int{max(1, n), n + 4} {
    47  			for _, alpha := range []complex128{0, 1, complex(0.7, -0.9)} {
    48  				for _, beta := range []complex128{0, 1, complex(1.3, -1.1)} {
    49  					for _, nanC := range []bool{false, true} {
    50  						if nanC && beta != 0 {
    51  							// Skip tests with C containing NaN values
    52  							// unless beta would zero out the NaNs.
    53  							continue
    54  						}
    55  
    56  						// Allocate the matrix A and fill it with random numbers.
    57  						a := make([]complex128, rowA*lda)
    58  						for i := range a {
    59  							a[i] = rndComplex128(rnd)
    60  						}
    61  						// Create a copy of A for checking that
    62  						// Zsyrk does not modify A.
    63  						aCopy := make([]complex128, len(a))
    64  						copy(aCopy, a)
    65  
    66  						// Allocate the matrix C and fill it with random numbers.
    67  						c := make([]complex128, n*ldc)
    68  						for i := range c {
    69  							c[i] = rndComplex128(rnd)
    70  						}
    71  						if nanC {
    72  							for i := 0; i < n; i++ {
    73  								for j := 0; j < n; j++ {
    74  									c[i+j*ldc] = cmplx.NaN()
    75  								}
    76  							}
    77  						}
    78  
    79  						// Create a copy of C for checking that
    80  						// Zsyrk does not modify its triangle
    81  						// opposite to uplo.
    82  						cCopy := make([]complex128, len(c))
    83  						copy(cCopy, c)
    84  						// Create a copy of C expanded into a
    85  						// full symmetric matrix for computing
    86  						// the expected result using zmm.
    87  						cSym := make([]complex128, len(c))
    88  						copy(cSym, c)
    89  						if uplo == blas.Upper {
    90  							for i := 0; i < n-1; i++ {
    91  								for j := i + 1; j < n; j++ {
    92  									cSym[j*ldc+i] = cSym[i*ldc+j]
    93  								}
    94  							}
    95  						} else {
    96  							for i := 1; i < n; i++ {
    97  								for j := 0; j < i; j++ {
    98  									cSym[j*ldc+i] = cSym[i*ldc+j]
    99  								}
   100  							}
   101  						}
   102  
   103  						// Compute the expected result using an internal Zgemm implementation.
   104  						var want []complex128
   105  						if trans == blas.NoTrans {
   106  							want = zmm(blas.NoTrans, blas.Trans, n, n, k, alpha, a, lda, a, lda, beta, cSym, ldc)
   107  						} else {
   108  							want = zmm(blas.Trans, blas.NoTrans, n, n, k, alpha, a, lda, a, lda, beta, cSym, ldc)
   109  						}
   110  
   111  						// Compute the result using Zsyrk.
   112  						impl.Zsyrk(uplo, trans, n, k, alpha, a, lda, beta, c, ldc)
   113  
   114  						prefix := fmt.Sprintf("n=%v,k=%v,lda=%v,ldc=%v,alpha=%v,beta=%v", n, k, lda, ldc, alpha, beta)
   115  
   116  						if !zsame(a, aCopy) {
   117  							t.Errorf("%v: unexpected modification of A", prefix)
   118  							continue
   119  						}
   120  						if uplo == blas.Upper && !zSameLowerTri(n, c, ldc, cCopy, ldc) {
   121  							t.Errorf("%v: unexpected modification in lower triangle of C", prefix)
   122  							continue
   123  						}
   124  						if uplo == blas.Lower && !zSameUpperTri(n, c, ldc, cCopy, ldc) {
   125  							t.Errorf("%v: unexpected modification in upper triangle of C", prefix)
   126  							continue
   127  						}
   128  
   129  						// Expand C into a full symmetric matrix
   130  						// for comparison with the result from zmm.
   131  						if uplo == blas.Upper {
   132  							for i := 0; i < n-1; i++ {
   133  								for j := i + 1; j < n; j++ {
   134  									c[j*ldc+i] = c[i*ldc+j]
   135  								}
   136  							}
   137  						} else {
   138  							for i := 1; i < n; i++ {
   139  								for j := 0; j < i; j++ {
   140  									c[j*ldc+i] = c[i*ldc+j]
   141  								}
   142  							}
   143  						}
   144  						if !zEqualApprox(c, want, tol) {
   145  							t.Errorf("%v: unexpected result", prefix)
   146  						}
   147  					}
   148  				}
   149  			}
   150  		}
   151  	}
   152  }