gonum.org/v1/gonum@v0.14.0/lapack/testlapack/dlangt.go (about)

     1  // Copyright ©2020 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  	"testing"
    11  
    12  	"golang.org/x/exp/rand"
    13  
    14  	"gonum.org/v1/gonum/floats"
    15  	"gonum.org/v1/gonum/lapack"
    16  )
    17  
    18  type Dlangter interface {
    19  	Dlangt(norm lapack.MatrixNorm, n int, dl, d, du []float64) float64
    20  }
    21  
    22  func DlangtTest(t *testing.T, impl Dlangter) {
    23  	rnd := rand.New(rand.NewSource(1))
    24  	for _, norm := range []lapack.MatrixNorm{lapack.MaxAbs, lapack.MaxRowSum, lapack.MaxColumnSum, lapack.Frobenius} {
    25  		t.Run(normToString(norm), func(t *testing.T) {
    26  			for _, n := range []int{0, 1, 2, 3, 4, 5, 10} {
    27  				for iter := 0; iter < 10; iter++ {
    28  					dlangtTest(t, impl, rnd, norm, n)
    29  				}
    30  			}
    31  		})
    32  	}
    33  }
    34  
    35  func dlangtTest(t *testing.T, impl Dlangter, rnd *rand.Rand, norm lapack.MatrixNorm, n int) {
    36  	const (
    37  		tol   = 1e-14
    38  		extra = 10
    39  	)
    40  
    41  	name := fmt.Sprintf("n=%v", n)
    42  
    43  	// Generate three random diagonals.
    44  	dl := randomSlice(n+extra, rnd)
    45  	dlCopy := make([]float64, len(dl))
    46  	copy(dlCopy, dl)
    47  
    48  	d := randomSlice(n+1+extra, rnd)
    49  	// Sometimes put a NaN into the matrix.
    50  	if n > 0 && rnd.Float64() < 0.5 {
    51  		d[rnd.Intn(n)] = math.NaN()
    52  	}
    53  	dCopy := make([]float64, len(d))
    54  	copy(dCopy, d)
    55  
    56  	du := randomSlice(n+extra, rnd)
    57  	duCopy := make([]float64, len(du))
    58  	copy(duCopy, du)
    59  
    60  	// Deal with zero-sized matrices early.
    61  	if n == 0 {
    62  		got := impl.Dlangt(norm, n, nil, nil, nil)
    63  		if got != 0 {
    64  			t.Errorf("%v: unexpected result for zero-sized matrix with nil input", name)
    65  		}
    66  		got = impl.Dlangt(norm, n, dl, d, du)
    67  		if !floats.Same(dl, dlCopy) {
    68  			t.Errorf("%v: unexpected modification in dl", name)
    69  		}
    70  		if !floats.Same(d, dCopy) {
    71  			t.Errorf("%v: unexpected modification in d", name)
    72  		}
    73  		if !floats.Same(du, duCopy) {
    74  			t.Errorf("%v: unexpected modification in du", name)
    75  		}
    76  		if got != 0 {
    77  			t.Errorf("%v: unexpected result for zero-sized matrix with non-nil input", name)
    78  		}
    79  		return
    80  	}
    81  
    82  	// Generate a dense representation of the matrix and compute the wanted result.
    83  	a := zeros(n, n, n)
    84  	for i := 0; i < n-1; i++ {
    85  		a.Data[i*a.Stride+i] = d[i]
    86  		a.Data[i*a.Stride+i+1] = du[i]
    87  		a.Data[(i+1)*a.Stride+i] = dl[i]
    88  	}
    89  	a.Data[(n-1)*a.Stride+n-1] = d[n-1]
    90  
    91  	got := impl.Dlangt(norm, n, dl, d, du)
    92  
    93  	if !floats.Same(dl, dlCopy) {
    94  		t.Errorf("%v: unexpected modification in dl", name)
    95  	}
    96  	if !floats.Same(d, dCopy) {
    97  		t.Errorf("%v: unexpected modification in d", name)
    98  	}
    99  	if !floats.Same(du, duCopy) {
   100  		t.Errorf("%v: unexpected modification in du", name)
   101  	}
   102  
   103  	want := dlange(norm, n, n, a.Data, a.Stride)
   104  
   105  	if math.IsNaN(want) {
   106  		if !math.IsNaN(got) {
   107  			t.Errorf("%v: unexpected result with NaN element; got %v, want %v", name, got, want)
   108  		}
   109  		return
   110  	}
   111  
   112  	if norm == lapack.MaxAbs {
   113  		if got != want {
   114  			t.Errorf("%v: unexpected result; got %v, want %v", name, got, want)
   115  		}
   116  		return
   117  	}
   118  	diff := math.Abs(got - want)
   119  	if diff > tol {
   120  		t.Errorf("%v: unexpected result; got %v, want %v, diff=%v", name, got, want, diff)
   121  	}
   122  }