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

     1  // Copyright ©2021 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  package testlapack
     5  
     6  import (
     7  	"fmt"
     8  	"math"
     9  	"testing"
    10  
    11  	"golang.org/x/exp/rand"
    12  
    13  	"gonum.org/v1/gonum/blas"
    14  	"gonum.org/v1/gonum/blas/blas64"
    15  	"gonum.org/v1/gonum/floats"
    16  	"gonum.org/v1/gonum/lapack"
    17  )
    18  
    19  type Dgesc2er interface {
    20  	Dgesc2(n int, a []float64, lda int, rhs []float64, ipiv, jpiv []int) (scale float64)
    21  
    22  	Dgetc2er
    23  }
    24  
    25  func Dgesc2Test(t *testing.T, impl Dgesc2er) {
    26  	rnd := rand.New(rand.NewSource(1))
    27  	for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 20, 50} {
    28  		for _, lda := range []int{n, n + 3} {
    29  			testDgesc2(t, impl, rnd, n, lda, false)
    30  			testDgesc2(t, impl, rnd, n, lda, true)
    31  		}
    32  	}
    33  }
    34  
    35  func testDgesc2(t *testing.T, impl Dgesc2er, rnd *rand.Rand, n, lda int, big bool) {
    36  	const tol = 1e-14
    37  
    38  	name := fmt.Sprintf("n=%v,lda=%v,big=%v", n, lda, big)
    39  
    40  	// Generate random general matrix.
    41  	a := randomGeneral(n, n, max(1, lda), rnd)
    42  
    43  	// Generate a random right hand side vector.
    44  	b := randomGeneral(n, 1, 1, rnd)
    45  	if big {
    46  		for i := 0; i < n; i++ {
    47  			b.Data[i] *= bignum
    48  		}
    49  	}
    50  
    51  	// Compute the LU factorization of A with full pivoting.
    52  	lu := cloneGeneral(a)
    53  	ipiv := make([]int, n)
    54  	jpiv := make([]int, n)
    55  	impl.Dgetc2(n, lu.Data, lu.Stride, ipiv, jpiv)
    56  
    57  	// Make copies of const input to Dgesc2.
    58  	luCopy := cloneGeneral(lu)
    59  	ipivCopy := make([]int, len(ipiv))
    60  	copy(ipivCopy, ipiv)
    61  	jpivCopy := make([]int, len(jpiv))
    62  	copy(jpivCopy, jpiv)
    63  
    64  	// Call Dgesc2 to solve A*x = scale*b.
    65  	x := cloneGeneral(b)
    66  	scale := impl.Dgesc2(n, lu.Data, lu.Stride, x.Data, ipiv, jpiv)
    67  
    68  	if n == 0 {
    69  		return
    70  	}
    71  
    72  	// Check that const input to Dgesc2 hasn't been modified.
    73  	if !floats.Same(lu.Data, luCopy.Data) {
    74  		t.Errorf("%v: unexpected modification in lu", name)
    75  	}
    76  	if !intsEqual(ipiv, ipivCopy) {
    77  		t.Errorf("%v: unexpected modification in ipiv", name)
    78  	}
    79  	if !intsEqual(jpiv, jpivCopy) {
    80  		t.Errorf("%v: unexpected modification in jpiv", name)
    81  	}
    82  
    83  	if scale <= 0 || 1 < scale {
    84  		t.Errorf("%v: scale %v out of bounds (0,1]", name, scale)
    85  	}
    86  	if !big && scale != 1 {
    87  		t.Errorf("%v: unexpected scaling, scale=%v", name, scale)
    88  	}
    89  
    90  	// Compute the difference rhs := A*x - scale*b.
    91  	diff := b
    92  	for i := 0; i < n; i++ {
    93  		diff.Data[i] *= scale
    94  	}
    95  	blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, a, x, -1, diff)
    96  
    97  	// Compute the residual |A*x - scale*b| / |x|.
    98  	xnorm := dlange(lapack.MaxColumnSum, n, 1, x.Data, 1)
    99  	resid := dlange(lapack.MaxColumnSum, n, 1, diff.Data, 1) / xnorm
   100  	if resid > tol || math.IsNaN(resid) {
   101  		t.Errorf("%v: unexpected result; resid=%v, want<=%v", name, resid, tol)
   102  	}
   103  }