github.com/gonum/lapack@v0.0.0-20181123203213-e4cdc5a0bff9/testlapack/dlaqr23.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/rand"
    10  	"testing"
    11  
    12  	"github.com/gonum/blas"
    13  	"github.com/gonum/blas/blas64"
    14  )
    15  
    16  type Dlaqr23er interface {
    17  	Dlaqr23(wantt, wantz bool, n, ktop, kbot, nw int, h []float64, ldh int, iloz, ihiz int, z []float64, ldz int, sr, si []float64, v []float64, ldv int, nh int, t []float64, ldt int, nv int, wv []float64, ldwv int, work []float64, lwork int, recur int) (ns, nd int)
    18  }
    19  
    20  type dlaqr23Test struct {
    21  	wantt, wantz bool
    22  	ktop, kbot   int
    23  	nw           int
    24  	h            blas64.General
    25  	iloz, ihiz   int
    26  
    27  	evWant []complex128 // Optional slice with known eigenvalues.
    28  }
    29  
    30  func Dlaqr23Test(t *testing.T, impl Dlaqr23er) {
    31  	rnd := rand.New(rand.NewSource(1))
    32  
    33  	for _, wantt := range []bool{true, false} {
    34  		for _, wantz := range []bool{true, false} {
    35  			for _, n := range []int{1, 2, 3, 4, 5, 6, 10, 18, 31, 100} {
    36  				for _, extra := range []int{0, 11} {
    37  					for cas := 0; cas < 30; cas++ {
    38  						var nw int
    39  						if nw <= 75 {
    40  							nw = rnd.Intn(n) + 1
    41  						} else {
    42  							nw = 76 + rnd.Intn(n-75)
    43  						}
    44  						ktop := rnd.Intn(n - nw + 1)
    45  						kbot := ktop + nw - 1
    46  						kbot += rnd.Intn(n - kbot)
    47  						h := randomHessenberg(n, n+extra, rnd)
    48  						if ktop-1 >= 0 {
    49  							h.Data[ktop*h.Stride+ktop-1] = 0
    50  						}
    51  						if kbot+1 < n {
    52  							h.Data[(kbot+1)*h.Stride+kbot] = 0
    53  						}
    54  						iloz := rnd.Intn(ktop + 1)
    55  						ihiz := kbot + rnd.Intn(n-kbot)
    56  						test := dlaqr23Test{
    57  							wantt: wantt,
    58  							wantz: wantz,
    59  							ktop:  ktop,
    60  							kbot:  kbot,
    61  							nw:    nw,
    62  							h:     h,
    63  							iloz:  iloz,
    64  							ihiz:  ihiz,
    65  						}
    66  						testDlaqr23(t, impl, test, false, 1, rnd)
    67  						testDlaqr23(t, impl, test, true, 1, rnd)
    68  						testDlaqr23(t, impl, test, false, 0, rnd)
    69  						testDlaqr23(t, impl, test, true, 0, rnd)
    70  					}
    71  				}
    72  			}
    73  		}
    74  	}
    75  
    76  	// Tests with n=0.
    77  	for _, wantt := range []bool{true, false} {
    78  		for _, wantz := range []bool{true, false} {
    79  			for _, extra := range []int{0, 1, 11} {
    80  				test := dlaqr23Test{
    81  					wantt: wantt,
    82  					wantz: wantz,
    83  					h:     randomHessenberg(0, extra, rnd),
    84  					ktop:  0,
    85  					kbot:  -1,
    86  					iloz:  0,
    87  					ihiz:  -1,
    88  					nw:    0,
    89  				}
    90  				testDlaqr23(t, impl, test, true, 1, rnd)
    91  				testDlaqr23(t, impl, test, false, 1, rnd)
    92  				testDlaqr23(t, impl, test, true, 0, rnd)
    93  				testDlaqr23(t, impl, test, false, 0, rnd)
    94  			}
    95  		}
    96  	}
    97  
    98  	// Tests with explicit eigenvalues computed by Octave.
    99  	for _, test := range []dlaqr23Test{
   100  		{
   101  			h: blas64.General{
   102  				Rows:   1,
   103  				Cols:   1,
   104  				Stride: 1,
   105  				Data:   []float64{7.09965484086874e-1},
   106  			},
   107  			ktop:   0,
   108  			kbot:   0,
   109  			iloz:   0,
   110  			ihiz:   0,
   111  			evWant: []complex128{7.09965484086874e-1},
   112  		},
   113  		{
   114  			h: blas64.General{
   115  				Rows:   2,
   116  				Cols:   2,
   117  				Stride: 2,
   118  				Data: []float64{
   119  					0, -1,
   120  					1, 0,
   121  				},
   122  			},
   123  			ktop:   0,
   124  			kbot:   1,
   125  			iloz:   0,
   126  			ihiz:   1,
   127  			evWant: []complex128{1i, -1i},
   128  		},
   129  		{
   130  			h: blas64.General{
   131  				Rows:   2,
   132  				Cols:   2,
   133  				Stride: 2,
   134  				Data: []float64{
   135  					6.25219991450918e-1, 8.17510791994361e-1,
   136  					3.31218891622294e-1, 1.24103744878131e-1,
   137  				},
   138  			},
   139  			ktop:   0,
   140  			kbot:   1,
   141  			iloz:   0,
   142  			ihiz:   1,
   143  			evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1},
   144  		},
   145  		{
   146  			h: blas64.General{
   147  				Rows:   4,
   148  				Cols:   4,
   149  				Stride: 4,
   150  				Data: []float64{
   151  					1, 0, 0, 0,
   152  					0, 6.25219991450918e-1, 8.17510791994361e-1, 0,
   153  					0, 3.31218891622294e-1, 1.24103744878131e-1, 0,
   154  					0, 0, 0, 1,
   155  				},
   156  			},
   157  			ktop:   1,
   158  			kbot:   2,
   159  			iloz:   0,
   160  			ihiz:   3,
   161  			evWant: []complex128{9.52203547663447e-1, -2.02879811334398e-1},
   162  		},
   163  		{
   164  			h: blas64.General{
   165  				Rows:   2,
   166  				Cols:   2,
   167  				Stride: 2,
   168  				Data: []float64{
   169  					-1.1219562276608, 6.85473513349362e-1,
   170  					-8.19951061145131e-1, 1.93728523178888e-1,
   171  				},
   172  			},
   173  			ktop: 0,
   174  			kbot: 1,
   175  			iloz: 0,
   176  			ihiz: 1,
   177  			evWant: []complex128{
   178  				-4.64113852240958e-1 + 3.59580510817350e-1i,
   179  				-4.64113852240958e-1 - 3.59580510817350e-1i,
   180  			},
   181  		},
   182  		{
   183  			h: blas64.General{
   184  				Rows:   5,
   185  				Cols:   5,
   186  				Stride: 5,
   187  				Data: []float64{
   188  					9.57590178533658e-1, -5.10651295522708e-1, 9.24974510015869e-1, -1.30016306879522e-1, 2.92601986926954e-2,
   189  					-1.08084756637964, 1.77529701001213, -1.36480197632509, 2.23196371219601e-1, 1.12912853063308e-1,
   190  					0, -8.44075612174676e-1, 1.067867614486, -2.55782915176399e-1, -2.00598563137468e-1,
   191  					0, 0, -5.67097237165410e-1, 2.07205057427341e-1, 6.54998340743380e-1,
   192  					0, 0, 0, -1.89441413886041e-1, -4.18125416021786e-1,
   193  				},
   194  			},
   195  			ktop: 0,
   196  			kbot: 4,
   197  			iloz: 0,
   198  			ihiz: 4,
   199  			evWant: []complex128{
   200  				2.94393309555622,
   201  				4.97029793606701e-1 + 3.63041654992384e-1i,
   202  				4.97029793606701e-1 - 3.63041654992384e-1i,
   203  				-1.74079119166145e-1 + 2.01570009462092e-1i,
   204  				-1.74079119166145e-1 - 2.01570009462092e-1i,
   205  			},
   206  		},
   207  	} {
   208  		test.wantt = true
   209  		test.wantz = true
   210  		test.nw = test.kbot - test.ktop + 1
   211  		testDlaqr23(t, impl, test, true, 1, rnd)
   212  		testDlaqr23(t, impl, test, false, 1, rnd)
   213  		testDlaqr23(t, impl, test, true, 0, rnd)
   214  		testDlaqr23(t, impl, test, false, 0, rnd)
   215  	}
   216  }
   217  
   218  func testDlaqr23(t *testing.T, impl Dlaqr23er, test dlaqr23Test, opt bool, recur int, rnd *rand.Rand) {
   219  	const tol = 1e-14
   220  
   221  	h := cloneGeneral(test.h)
   222  	n := h.Cols
   223  	extra := h.Stride - h.Cols
   224  	wantt := test.wantt
   225  	wantz := test.wantz
   226  	ktop := test.ktop
   227  	kbot := test.kbot
   228  	nw := test.nw
   229  	iloz := test.iloz
   230  	ihiz := test.ihiz
   231  
   232  	var z, zCopy blas64.General
   233  	if wantz {
   234  		z = eye(n, n+extra)
   235  		zCopy = cloneGeneral(z)
   236  	}
   237  
   238  	sr := nanSlice(kbot + 1)
   239  	si := nanSlice(kbot + 1)
   240  
   241  	v := randomGeneral(nw, nw, nw+extra, rnd)
   242  	var nh int
   243  	if nw > 0 {
   244  		nh = nw + rnd.Intn(nw) // nh must be at least nw.
   245  	}
   246  	tmat := randomGeneral(nw, nh, nh+extra, rnd)
   247  	var nv int
   248  	if nw > 0 {
   249  		nv = rnd.Intn(nw) + 1
   250  	}
   251  	wv := randomGeneral(nv, nw, nw+extra, rnd)
   252  
   253  	var work []float64
   254  	if opt {
   255  		work = nanSlice(1)
   256  		impl.Dlaqr23(wantt, wantz, n, ktop, kbot, nw, nil, h.Stride, iloz, ihiz, nil, z.Stride,
   257  			nil, nil, nil, v.Stride, tmat.Cols, nil, tmat.Stride, wv.Rows, nil, wv.Stride, work, -1, recur)
   258  		work = nanSlice(int(work[0]))
   259  	} else {
   260  		work = nanSlice(max(1, 2*nw))
   261  	}
   262  
   263  	ns, nd := impl.Dlaqr23(wantt, wantz, n, ktop, kbot, nw, h.Data, h.Stride, iloz, ihiz, z.Data, z.Stride,
   264  		sr, si, v.Data, v.Stride, tmat.Cols, tmat.Data, tmat.Stride, wv.Rows, wv.Data, wv.Stride, work, len(work), recur)
   265  
   266  	prefix := fmt.Sprintf("Case wantt=%v, wantz=%v, n=%v, ktop=%v, kbot=%v, nw=%v, iloz=%v, ihiz=%v, extra=%v",
   267  		wantt, wantz, n, ktop, kbot, nw, iloz, ihiz, extra)
   268  
   269  	if !generalOutsideAllNaN(h) {
   270  		t.Errorf("%v: out-of-range write to H\n%v", prefix, h.Data)
   271  	}
   272  	if !generalOutsideAllNaN(z) {
   273  		t.Errorf("%v: out-of-range write to Z\n%v", prefix, z.Data)
   274  	}
   275  	if !generalOutsideAllNaN(v) {
   276  		t.Errorf("%v: out-of-range write to V\n%v", prefix, v.Data)
   277  	}
   278  	if !generalOutsideAllNaN(tmat) {
   279  		t.Errorf("%v: out-of-range write to T\n%v", prefix, tmat.Data)
   280  	}
   281  	if !generalOutsideAllNaN(wv) {
   282  		t.Errorf("%v: out-of-range write to WV\n%v", prefix, wv.Data)
   283  	}
   284  	if !isAllNaN(sr[:kbot-nd-ns+1]) || !isAllNaN(sr[kbot+1:]) {
   285  		t.Errorf("%v: out-of-range write to sr")
   286  	}
   287  	if !isAllNaN(si[:kbot-nd-ns+1]) || !isAllNaN(si[kbot+1:]) {
   288  		t.Errorf("%v: out-of-range write to si")
   289  	}
   290  
   291  	if !isUpperHessenberg(h) {
   292  		t.Errorf("%v: H is not upper Hessenberg", prefix)
   293  	}
   294  
   295  	if test.evWant != nil {
   296  		for i := kbot - nd + 1; i <= kbot; i++ {
   297  			ev := complex(sr[i], si[i])
   298  			found, _ := containsComplex(test.evWant, ev, tol)
   299  			if !found {
   300  				t.Errorf("%v: unexpected eigenvalue %v", prefix, ev)
   301  			}
   302  		}
   303  	}
   304  
   305  	if !wantz {
   306  		return
   307  	}
   308  
   309  	var zmod bool
   310  	for i := 0; i < n; i++ {
   311  		for j := 0; j < n; j++ {
   312  			if z.Data[i*z.Stride+j] == zCopy.Data[i*zCopy.Stride+j] {
   313  				continue
   314  			}
   315  			if i < iloz || i > ihiz || j < kbot-nw+1 || j > kbot {
   316  				zmod = true
   317  			}
   318  		}
   319  	}
   320  	if zmod {
   321  		t.Errorf("%v: unexpected modification of Z", prefix)
   322  	}
   323  	if !isOrthonormal(z) {
   324  		t.Errorf("%v: Z is not orthogonal", prefix)
   325  	}
   326  	if wantt {
   327  		hu := eye(n, n)
   328  		blas64.Gemm(blas.NoTrans, blas.NoTrans, 1, test.h, z, 0, hu)
   329  		uhu := eye(n, n)
   330  		blas64.Gemm(blas.Trans, blas.NoTrans, 1, z, hu, 0, uhu)
   331  		if !equalApproxGeneral(uhu, h, 10*tol) {
   332  			t.Errorf("%v: Z^T*(initial H)*Z and (final H) are not equal", prefix)
   333  		}
   334  	}
   335  }