github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/testlapack/dtrevc3.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/rand"
    11  	"testing"
    12  
    13  	"github.com/gonum/blas/blas64"
    14  	"github.com/gonum/floats"
    15  	"github.com/gonum/lapack"
    16  )
    17  
    18  type Dtrevc3er interface {
    19  	Dtrevc3(side lapack.EVSide, howmny lapack.HowMany, selected []bool, n int, t []float64, ldt int, vl []float64, ldvl int, vr []float64, ldvr int, mm int, work []float64, lwork int) int
    20  }
    21  
    22  func Dtrevc3Test(t *testing.T, impl Dtrevc3er) {
    23  	rnd := rand.New(rand.NewSource(1))
    24  	for _, side := range []lapack.EVSide{lapack.RightEV, lapack.LeftEV, lapack.RightLeftEV} {
    25  		for _, howmny := range []lapack.HowMany{lapack.AllEV, lapack.AllEVMulQ, lapack.SelectedEV} {
    26  			for _, n := range []int{0, 1, 2, 3, 4, 5, 10, 34, 100} {
    27  				for _, extra := range []int{0, 11} {
    28  					for _, optwork := range []bool{true, false} {
    29  						for cas := 0; cas < 10; cas++ {
    30  							tmat := randomSchurCanonical(n, n+extra, rnd)
    31  							testDtrevc3(t, impl, side, howmny, tmat, optwork, rnd)
    32  						}
    33  					}
    34  				}
    35  			}
    36  		}
    37  	}
    38  }
    39  
    40  func testDtrevc3(t *testing.T, impl Dtrevc3er, side lapack.EVSide, howmny lapack.HowMany, tmat blas64.General, optwork bool, rnd *rand.Rand) {
    41  	const tol = 1e-14
    42  
    43  	n := tmat.Rows
    44  	extra := tmat.Stride - tmat.Cols
    45  	right := side != lapack.LeftEV
    46  	left := side != lapack.RightEV
    47  
    48  	var selected, selectedWant []bool
    49  	var mWant int // How many columns will the eigenvectors occupy.
    50  	if howmny == lapack.SelectedEV {
    51  		selected = make([]bool, n)
    52  		selectedWant = make([]bool, n)
    53  		// Dtrevc3 will compute only selected eigenvectors. Pick them
    54  		// randomly disregarding whether they are real or complex.
    55  		for i := range selected {
    56  			if rnd.Float64() < 0.5 {
    57  				selected[i] = true
    58  			}
    59  		}
    60  		// Dtrevc3 will modify (standardize) the slice selected based on
    61  		// whether the corresponding eigenvalues are real or complex. Do
    62  		// the same process here to fill selectedWant.
    63  		for i := 0; i < n; {
    64  			if i == n-1 || tmat.Data[(i+1)*tmat.Stride+i] == 0 {
    65  				// Real eigenvalue.
    66  				if selected[i] {
    67  					selectedWant[i] = true
    68  					mWant++ // Real eigenvectors occupy one column.
    69  				}
    70  				i++
    71  			} else {
    72  				// Complex eigenvalue.
    73  				if selected[i] || selected[i+1] {
    74  					// Dtrevc3 will modify selected so that
    75  					// only the first element of the pair is
    76  					// true.
    77  					selectedWant[i] = true
    78  					mWant += 2 // Complex eigenvectors occupy two columns.
    79  				}
    80  				i += 2
    81  			}
    82  		}
    83  	} else {
    84  		// All eigenvectors occupy n columns.
    85  		mWant = n
    86  	}
    87  
    88  	var vr blas64.General
    89  	if right {
    90  		if howmny == lapack.AllEVMulQ {
    91  			vr = eye(n, n+extra)
    92  		} else {
    93  			// VR will be overwritten.
    94  			vr = nanGeneral(n, mWant, n+extra)
    95  		}
    96  	}
    97  
    98  	var vl blas64.General
    99  	if left {
   100  		if howmny == lapack.AllEVMulQ {
   101  			vl = eye(n, n+extra)
   102  		} else {
   103  			// VL will be overwritten.
   104  			vl = nanGeneral(n, mWant, n+extra)
   105  		}
   106  	}
   107  
   108  	work := make([]float64, max(1, 3*n))
   109  	if optwork {
   110  		impl.Dtrevc3(side, howmny, nil, n, nil, 1, nil, 1, nil, 1, mWant, work, -1)
   111  		work = make([]float64, int(work[0]))
   112  	}
   113  
   114  	m := impl.Dtrevc3(side, howmny, selected, n, tmat.Data, tmat.Stride,
   115  		vl.Data, vl.Stride, vr.Data, vr.Stride, mWant, work, len(work))
   116  
   117  	prefix := fmt.Sprintf("Case side=%v, howmny=%v, n=%v, extra=%v, optwk=%v",
   118  		side, howmny, n, extra, optwork)
   119  
   120  	if !generalOutsideAllNaN(tmat) {
   121  		t.Errorf("%v: out-of-range write to T", prefix)
   122  	}
   123  	if !generalOutsideAllNaN(vl) {
   124  		t.Errorf("%v: out-of-range write to VL", prefix)
   125  	}
   126  	if !generalOutsideAllNaN(vr) {
   127  		t.Errorf("%v: out-of-range write to VR", prefix)
   128  	}
   129  
   130  	if m != mWant {
   131  		t.Errorf("%v: unexpected value of m. Want %v, got %v", prefix, mWant, m)
   132  	}
   133  
   134  	if howmny == lapack.SelectedEV {
   135  		for i := range selected {
   136  			if selected[i] != selectedWant[i] {
   137  				t.Errorf("%v: unexpected selected[%v]", prefix, i)
   138  			}
   139  		}
   140  	}
   141  
   142  	// Check that the columns of VR and VL are actually eigenvectors and
   143  	// that the magnitude of their largest element is 1.
   144  	var k int
   145  	for j := 0; j < n; {
   146  		re := tmat.Data[j*tmat.Stride+j]
   147  		if j == n-1 || tmat.Data[(j+1)*tmat.Stride+j] == 0 {
   148  			if howmny == lapack.SelectedEV && !selected[j] {
   149  				j++
   150  				continue
   151  			}
   152  			if right {
   153  				ev := columnOf(vr, k)
   154  				norm := floats.Norm(ev, math.Inf(1))
   155  				if math.Abs(norm-1) > tol {
   156  					t.Errorf("%v: magnitude of largest element of VR[:,%v] not 1", prefix, k)
   157  				}
   158  				if !isRightEigenvectorOf(tmat, ev, nil, complex(re, 0), tol) {
   159  					t.Errorf("%v: VR[:,%v] is not real right eigenvector", prefix, k)
   160  				}
   161  			}
   162  			if left {
   163  				ev := columnOf(vl, k)
   164  				norm := floats.Norm(ev, math.Inf(1))
   165  				if math.Abs(norm-1) > tol {
   166  					t.Errorf("%v: magnitude of largest element of VL[:,%v] not 1", prefix, k)
   167  				}
   168  				if !isLeftEigenvectorOf(tmat, ev, nil, complex(re, 0), tol) {
   169  					t.Errorf("%v: VL[:,%v] is not real left eigenvector", prefix, k)
   170  				}
   171  			}
   172  			k++
   173  			j++
   174  			continue
   175  		}
   176  		if howmny == lapack.SelectedEV && !selected[j] {
   177  			j += 2
   178  			continue
   179  		}
   180  		im := math.Sqrt(math.Abs(tmat.Data[(j+1)*tmat.Stride+j])) *
   181  			math.Sqrt(math.Abs(tmat.Data[j*tmat.Stride+j+1]))
   182  		if right {
   183  			evre := columnOf(vr, k)
   184  			evim := columnOf(vr, k+1)
   185  			var evmax float64
   186  			for i, v := range evre {
   187  				evmax = math.Max(evmax, math.Abs(v)+math.Abs(evim[i]))
   188  			}
   189  			if math.Abs(evmax-1) > tol {
   190  				t.Errorf("%v: magnitude of largest element of VR[:,%v] not 1", prefix, k)
   191  			}
   192  			if !isRightEigenvectorOf(tmat, evre, evim, complex(re, im), tol) {
   193  				t.Errorf("%v: VR[:,%v:%v] is not complex right eigenvector", prefix, k, k+1)
   194  			}
   195  			floats.Scale(-1, evim)
   196  			if !isRightEigenvectorOf(tmat, evre, evim, complex(re, -im), tol) {
   197  				t.Errorf("%v: VR[:,%v:%v] is not complex right eigenvector", prefix, k, k+1)
   198  			}
   199  		}
   200  		if left {
   201  			evre := columnOf(vl, k)
   202  			evim := columnOf(vl, k+1)
   203  			var evmax float64
   204  			for i, v := range evre {
   205  				evmax = math.Max(evmax, math.Abs(v)+math.Abs(evim[i]))
   206  			}
   207  			if math.Abs(evmax-1) > tol {
   208  				t.Errorf("%v: magnitude of largest element of VL[:,%v] not 1", prefix, k)
   209  			}
   210  			if !isLeftEigenvectorOf(tmat, evre, evim, complex(re, im), tol) {
   211  				t.Errorf("%v: VL[:,%v:%v] is not complex left eigenvector", prefix, k, k+1)
   212  			}
   213  			floats.Scale(-1, evim)
   214  			if !isLeftEigenvectorOf(tmat, evre, evim, complex(re, -im), tol) {
   215  				t.Errorf("%v: VL[:,%v:%v] is not complex left eigenvector", prefix, k, k+1)
   216  			}
   217  		}
   218  		k += 2
   219  		j += 2
   220  	}
   221  }