gonum.org/v1/gonum@v0.14.0/lapack/testlapack/test_matrices.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  	"math"
     9  
    10  	"golang.org/x/exp/rand"
    11  
    12  	"gonum.org/v1/gonum/blas/blas64"
    13  )
    14  
    15  // A123 is the non-symmetric singular matrix
    16  //
    17  //	    [ 1 2 3 ]
    18  //	A = [ 4 5 6 ]
    19  //	    [ 7 8 9 ]
    20  //
    21  // It has three distinct real eigenvalues.
    22  type A123 struct{}
    23  
    24  func (A123) Matrix() blas64.General {
    25  	return blas64.General{
    26  		Rows:   3,
    27  		Cols:   3,
    28  		Stride: 3,
    29  		Data: []float64{
    30  			1, 2, 3,
    31  			4, 5, 6,
    32  			7, 8, 9,
    33  		},
    34  	}
    35  }
    36  
    37  func (A123) Eigenvalues() []complex128 {
    38  	return []complex128{16.116843969807043, -1.116843969807043, 0}
    39  }
    40  
    41  func (A123) LeftEV() blas64.General {
    42  	return blas64.General{
    43  		Rows:   3,
    44  		Cols:   3,
    45  		Stride: 3,
    46  		Data: []float64{
    47  			-0.464547273387671, -0.570795531228578, -0.677043789069485,
    48  			-0.882905959653586, -0.239520420054206, 0.403865119545174,
    49  			0.408248290463862, -0.816496580927726, 0.408248290463863,
    50  		},
    51  	}
    52  }
    53  
    54  func (A123) RightEV() blas64.General {
    55  	return blas64.General{
    56  		Rows:   3,
    57  		Cols:   3,
    58  		Stride: 3,
    59  		Data: []float64{
    60  			-0.231970687246286, -0.785830238742067, 0.408248290463864,
    61  			-0.525322093301234, -0.086751339256628, -0.816496580927726,
    62  			-0.818673499356181, 0.612327560228810, 0.408248290463863,
    63  		},
    64  	}
    65  }
    66  
    67  // AntisymRandom is a anti-symmetric random matrix. All its eigenvalues are
    68  // imaginary with one zero if the order is odd.
    69  type AntisymRandom struct {
    70  	mat blas64.General
    71  }
    72  
    73  func NewAntisymRandom(n int, rnd *rand.Rand) AntisymRandom {
    74  	a := zeros(n, n, n)
    75  	for i := 0; i < n; i++ {
    76  		for j := i + 1; j < n; j++ {
    77  			r := rnd.NormFloat64()
    78  			a.Data[i*a.Stride+j] = r
    79  			a.Data[j*a.Stride+i] = -r
    80  		}
    81  	}
    82  	return AntisymRandom{a}
    83  }
    84  
    85  func (a AntisymRandom) Matrix() blas64.General {
    86  	return cloneGeneral(a.mat)
    87  }
    88  
    89  func (AntisymRandom) Eigenvalues() []complex128 {
    90  	return nil
    91  }
    92  
    93  // Circulant is a generally non-symmetric matrix given by
    94  //
    95  //	A[i,j] = 1 + (j-i+n)%n.
    96  //
    97  // For example, for n=5,
    98  //
    99  //	    [ 1 2 3 4 5 ]
   100  //	    [ 5 1 2 3 4 ]
   101  //	A = [ 4 5 1 2 3 ]
   102  //	    [ 3 4 5 1 2 ]
   103  //	    [ 2 3 4 5 1 ]
   104  //
   105  // It has real and complex eigenvalues, some possibly repeated.
   106  type Circulant int
   107  
   108  func (c Circulant) Matrix() blas64.General {
   109  	n := int(c)
   110  	a := zeros(n, n, n)
   111  	for i := 0; i < n; i++ {
   112  		for j := 0; j < n; j++ {
   113  			a.Data[i*a.Stride+j] = float64(1 + (j-i+n)%n)
   114  		}
   115  	}
   116  	return a
   117  }
   118  
   119  func (c Circulant) Eigenvalues() []complex128 {
   120  	n := int(c)
   121  	w := rootsOfUnity(n)
   122  	ev := make([]complex128, n)
   123  	for k := 0; k < n; k++ {
   124  		ev[k] = complex(float64(n), 0)
   125  	}
   126  	for i := n - 1; i > 0; i-- {
   127  		for k := 0; k < n; k++ {
   128  			ev[k] = ev[k]*w[k] + complex(float64(i), 0)
   129  		}
   130  	}
   131  	return ev
   132  }
   133  
   134  // Clement is a generally non-symmetric matrix given by
   135  //
   136  //	A[i,j] = i+1  if j == i+1,
   137  //	       = n-i  if j == i-1,
   138  //	       = 0    otherwise.
   139  //
   140  // For example, for n=5,
   141  //
   142  //	    [ . 1 . . . ]
   143  //	    [ 4 . 2 . . ]
   144  //	A = [ . 3 . 3 . ]
   145  //	    [ . . 2 . 4 ]
   146  //	    [ . . . 1 . ]
   147  //
   148  // It has n distinct real eigenvalues.
   149  type Clement int
   150  
   151  func (c Clement) Matrix() blas64.General {
   152  	n := int(c)
   153  	a := zeros(n, n, n)
   154  	for i := 0; i < n; i++ {
   155  		if i < n-1 {
   156  			a.Data[i*a.Stride+i+1] = float64(i + 1)
   157  		}
   158  		if i > 0 {
   159  			a.Data[i*a.Stride+i-1] = float64(n - i)
   160  		}
   161  	}
   162  	return a
   163  }
   164  
   165  func (c Clement) Eigenvalues() []complex128 {
   166  	n := int(c)
   167  	ev := make([]complex128, n)
   168  	for i := range ev {
   169  		ev[i] = complex(float64(-n+2*i+1), 0)
   170  	}
   171  	return ev
   172  }
   173  
   174  // Creation is a singular non-symmetric matrix given by
   175  //
   176  //	A[i,j] = i  if j == i-1,
   177  //	       = 0  otherwise.
   178  //
   179  // For example, for n=5,
   180  //
   181  //	    [ . . . . . ]
   182  //	    [ 1 . . . . ]
   183  //	A = [ . 2 . . . ]
   184  //	    [ . . 3 . . ]
   185  //	    [ . . . 4 . ]
   186  //
   187  // Zero is its only eigenvalue.
   188  type Creation int
   189  
   190  func (c Creation) Matrix() blas64.General {
   191  	n := int(c)
   192  	a := zeros(n, n, n)
   193  	for i := 1; i < n; i++ {
   194  		a.Data[i*a.Stride+i-1] = float64(i)
   195  	}
   196  	return a
   197  }
   198  
   199  func (c Creation) Eigenvalues() []complex128 {
   200  	return make([]complex128, int(c))
   201  }
   202  
   203  // Diagonal is a diagonal matrix given by
   204  //
   205  //	A[i,j] = i+1  if i == j,
   206  //	       = 0    otherwise.
   207  //
   208  // For example, for n=5,
   209  //
   210  //	    [ 1 . . . . ]
   211  //	    [ . 2 . . . ]
   212  //	A = [ . . 3 . . ]
   213  //	    [ . . . 4 . ]
   214  //	    [ . . . . 5 ]
   215  //
   216  // It has n real eigenvalues {1,...,n}.
   217  type Diagonal int
   218  
   219  func (d Diagonal) Matrix() blas64.General {
   220  	n := int(d)
   221  	a := zeros(n, n, n)
   222  	for i := 0; i < n; i++ {
   223  		a.Data[i*a.Stride+i] = float64(i)
   224  	}
   225  	return a
   226  }
   227  
   228  func (d Diagonal) Eigenvalues() []complex128 {
   229  	n := int(d)
   230  	ev := make([]complex128, n)
   231  	for i := range ev {
   232  		ev[i] = complex(float64(i), 0)
   233  	}
   234  	return ev
   235  }
   236  
   237  // Downshift is a non-singular upper Hessenberg matrix given by
   238  //
   239  //	A[i,j] = 1  if (i-j+n)%n == 1,
   240  //	       = 0  otherwise.
   241  //
   242  // For example, for n=5,
   243  //
   244  //	    [ . . . . 1 ]
   245  //	    [ 1 . . . . ]
   246  //	A = [ . 1 . . . ]
   247  //	    [ . . 1 . . ]
   248  //	    [ . . . 1 . ]
   249  //
   250  // Its eigenvalues are the complex roots of unity.
   251  type Downshift int
   252  
   253  func (d Downshift) Matrix() blas64.General {
   254  	n := int(d)
   255  	a := zeros(n, n, n)
   256  	a.Data[n-1] = 1
   257  	for i := 1; i < n; i++ {
   258  		a.Data[i*a.Stride+i-1] = 1
   259  	}
   260  	return a
   261  }
   262  
   263  func (d Downshift) Eigenvalues() []complex128 {
   264  	return rootsOfUnity(int(d))
   265  }
   266  
   267  // Fibonacci is an upper Hessenberg matrix with 3 distinct real eigenvalues. For
   268  // example, for n=5,
   269  //
   270  //	    [ . 1 . . . ]
   271  //	    [ 1 1 . . . ]
   272  //	A = [ . 1 1 . . ]
   273  //	    [ . . 1 1 . ]
   274  //	    [ . . . 1 1 ]
   275  type Fibonacci int
   276  
   277  func (f Fibonacci) Matrix() blas64.General {
   278  	n := int(f)
   279  	a := zeros(n, n, n)
   280  	if n > 1 {
   281  		a.Data[1] = 1
   282  	}
   283  	for i := 1; i < n; i++ {
   284  		a.Data[i*a.Stride+i-1] = 1
   285  		a.Data[i*a.Stride+i] = 1
   286  	}
   287  	return a
   288  }
   289  
   290  func (f Fibonacci) Eigenvalues() []complex128 {
   291  	n := int(f)
   292  	ev := make([]complex128, n)
   293  	if n == 0 || n == 1 {
   294  		return ev
   295  	}
   296  	phi := 0.5 * (1 + math.Sqrt(5))
   297  	ev[0] = complex(phi, 0)
   298  	for i := 1; i < n-1; i++ {
   299  		ev[i] = 1 + 0i
   300  	}
   301  	ev[n-1] = complex(1-phi, 0)
   302  	return ev
   303  }
   304  
   305  // Gear is a singular non-symmetric matrix with real eigenvalues. For example,
   306  // for n=5,
   307  //
   308  //	    [ . 1 . . 1 ]
   309  //	    [ 1 . 1 . . ]
   310  //	A = [ . 1 . 1 . ]
   311  //	    [ . . 1 . 1 ]
   312  //	    [-1 . . 1 . ]
   313  type Gear int
   314  
   315  func (g Gear) Matrix() blas64.General {
   316  	n := int(g)
   317  	a := zeros(n, n, n)
   318  	if n == 1 {
   319  		return a
   320  	}
   321  	for i := 0; i < n-1; i++ {
   322  		a.Data[i*a.Stride+i+1] = 1
   323  	}
   324  	for i := 1; i < n; i++ {
   325  		a.Data[i*a.Stride+i-1] = 1
   326  	}
   327  	a.Data[n-1] = 1
   328  	a.Data[(n-1)*a.Stride] = -1
   329  	return a
   330  }
   331  
   332  func (g Gear) Eigenvalues() []complex128 {
   333  	n := int(g)
   334  	ev := make([]complex128, n)
   335  	if n == 0 || n == 1 {
   336  		return ev
   337  	}
   338  	if n == 2 {
   339  		ev[0] = complex(0, 1)
   340  		ev[1] = complex(0, -1)
   341  		return ev
   342  	}
   343  	w := 0
   344  	ev[w] = math.Pi / 2
   345  	w++
   346  	phi := (n - 1) / 2
   347  	for p := 1; p <= phi; p++ {
   348  		ev[w] = complex(float64(2*p)*math.Pi/float64(n), 0)
   349  		w++
   350  	}
   351  	phi = n / 2
   352  	for p := 1; p <= phi; p++ {
   353  		ev[w] = complex(float64(2*p-1)*math.Pi/float64(n), 0)
   354  		w++
   355  	}
   356  	for i, v := range ev {
   357  		ev[i] = complex(2*math.Cos(real(v)), 0)
   358  	}
   359  	return ev
   360  }
   361  
   362  // Grcar is an upper Hessenberg matrix given by
   363  //
   364  //	A[i,j] = -1  if i == j+1,
   365  //	       = 1   if i <= j and j <= i+k,
   366  //	       = 0   otherwise.
   367  //
   368  // For example, for n=5 and k=2,
   369  //
   370  //	    [  1  1  1  .  . ]
   371  //	    [ -1  1  1  1  . ]
   372  //	A = [  . -1  1  1  1 ]
   373  //	    [  .  . -1  1  1 ]
   374  //	    [  .  .  . -1  1 ]
   375  //
   376  // The matrix has sensitive eigenvalues but they are not given explicitly.
   377  type Grcar struct {
   378  	N int
   379  	K int
   380  }
   381  
   382  func (g Grcar) Matrix() blas64.General {
   383  	n := g.N
   384  	a := zeros(n, n, n)
   385  	for k := 0; k <= g.K; k++ {
   386  		for i := 0; i < n-k; i++ {
   387  			a.Data[i*a.Stride+i+k] = 1
   388  		}
   389  	}
   390  	for i := 1; i < n; i++ {
   391  		a.Data[i*a.Stride+i-1] = -1
   392  	}
   393  	return a
   394  }
   395  
   396  func (Grcar) Eigenvalues() []complex128 {
   397  	return nil
   398  }
   399  
   400  // Hanowa is a non-symmetric non-singular matrix of even order given by
   401  //
   402  //	A[i,j] = alpha    if i == j,
   403  //	       = -i-1     if i < n/2 and j == i + n/2,
   404  //	       = i+1-n/2  if i >= n/2 and j == i - n/2,
   405  //	       = 0        otherwise.
   406  //
   407  // The matrix has complex eigenvalues.
   408  type Hanowa struct {
   409  	N     int // Order of the matrix, must be even.
   410  	Alpha float64
   411  }
   412  
   413  func (h Hanowa) Matrix() blas64.General {
   414  	if h.N&0x1 != 0 {
   415  		panic("lapack: matrix order must be even")
   416  	}
   417  	n := h.N
   418  	a := zeros(n, n, n)
   419  	for i := 0; i < n; i++ {
   420  		a.Data[i*a.Stride+i] = h.Alpha
   421  	}
   422  	for i := 0; i < n/2; i++ {
   423  		a.Data[i*a.Stride+i+n/2] = float64(-i - 1)
   424  	}
   425  	for i := n / 2; i < n; i++ {
   426  		a.Data[i*a.Stride+i-n/2] = float64(i + 1 - n/2)
   427  	}
   428  	return a
   429  }
   430  
   431  func (h Hanowa) Eigenvalues() []complex128 {
   432  	if h.N&0x1 != 0 {
   433  		panic("lapack: matrix order must be even")
   434  	}
   435  	n := h.N
   436  	ev := make([]complex128, n)
   437  	for i := 0; i < n/2; i++ {
   438  		ev[2*i] = complex(h.Alpha, float64(-i-1))
   439  		ev[2*i+1] = complex(h.Alpha, float64(i+1))
   440  	}
   441  	return ev
   442  }
   443  
   444  // Lesp is a tridiagonal, generally non-symmetric matrix given by
   445  //
   446  //	A[i,j] = -2*i-5   if i == j,
   447  //	       = 1/(i+1)  if i == j-1,
   448  //	       = j+1      if i == j+1.
   449  //
   450  // For example, for n=5,
   451  //
   452  //	    [  -5    2    .    .    . ]
   453  //	    [ 1/2   -7    3    .    . ]
   454  //	A = [   .  1/3   -9    4    . ]
   455  //	    [   .    .  1/4  -11    5 ]
   456  //	    [   .    .    .  1/5  -13 ].
   457  //
   458  // The matrix has sensitive eigenvalues but they are not given explicitly.
   459  type Lesp int
   460  
   461  func (l Lesp) Matrix() blas64.General {
   462  	n := int(l)
   463  	a := zeros(n, n, n)
   464  	for i := 0; i < n; i++ {
   465  		a.Data[i*a.Stride+i] = float64(-2*i - 5)
   466  	}
   467  	for i := 0; i < n-1; i++ {
   468  		a.Data[i*a.Stride+i+1] = float64(i + 2)
   469  	}
   470  	for i := 1; i < n; i++ {
   471  		a.Data[i*a.Stride+i-1] = 1 / float64(i+1)
   472  	}
   473  	return a
   474  }
   475  
   476  func (Lesp) Eigenvalues() []complex128 {
   477  	return nil
   478  }
   479  
   480  // Rutis is the 4×4 non-symmetric matrix
   481  //
   482  //	    [ 4 -5  0  3 ]
   483  //	A = [ 0  4 -3 -5 ]
   484  //	    [ 5 -3  4  0 ]
   485  //	    [ 3  0  5  4 ]
   486  //
   487  // It has two distinct real eigenvalues and a pair of complex eigenvalues.
   488  type Rutis struct{}
   489  
   490  func (Rutis) Matrix() blas64.General {
   491  	return blas64.General{
   492  		Rows:   4,
   493  		Cols:   4,
   494  		Stride: 4,
   495  		Data: []float64{
   496  			4, -5, 0, 3,
   497  			0, 4, -3, -5,
   498  			5, -3, 4, 0,
   499  			3, 0, 5, 4,
   500  		},
   501  	}
   502  }
   503  
   504  func (Rutis) Eigenvalues() []complex128 {
   505  	return []complex128{12, 1 + 5i, 1 - 5i, 2}
   506  }
   507  
   508  // Tris is a tridiagonal matrix given by
   509  //
   510  //	A[i,j] = x  if i == j-1,
   511  //	       = y  if i == j,
   512  //	       = z  if i == j+1.
   513  //
   514  // If x*z is negative, the matrix has complex eigenvalues.
   515  type Tris struct {
   516  	N       int
   517  	X, Y, Z float64
   518  }
   519  
   520  func (t Tris) Matrix() blas64.General {
   521  	n := t.N
   522  	a := zeros(n, n, n)
   523  	for i := 1; i < n; i++ {
   524  		a.Data[i*a.Stride+i-1] = t.X
   525  	}
   526  	for i := 0; i < n; i++ {
   527  		a.Data[i*a.Stride+i] = t.Y
   528  	}
   529  	for i := 0; i < n-1; i++ {
   530  		a.Data[i*a.Stride+i+1] = t.Z
   531  	}
   532  	return a
   533  }
   534  
   535  func (t Tris) Eigenvalues() []complex128 {
   536  	n := t.N
   537  	ev := make([]complex128, n)
   538  	for i := range ev {
   539  		angle := float64(i+1) * math.Pi / float64(n+1)
   540  		arg := t.X * t.Z
   541  		if arg >= 0 {
   542  			ev[i] = complex(t.Y+2*math.Sqrt(arg)*math.Cos(angle), 0)
   543  		} else {
   544  			ev[i] = complex(t.Y, 2*math.Sqrt(-arg)*math.Cos(angle))
   545  		}
   546  	}
   547  	return ev
   548  }
   549  
   550  // Wilk4 is a 4×4 lower triangular matrix with 4 distinct real eigenvalues.
   551  type Wilk4 struct{}
   552  
   553  func (Wilk4) Matrix() blas64.General {
   554  	return blas64.General{
   555  		Rows:   4,
   556  		Cols:   4,
   557  		Stride: 4,
   558  		Data: []float64{
   559  			0.9143e-4, 0.0, 0.0, 0.0,
   560  			0.8762, 0.7156e-4, 0.0, 0.0,
   561  			0.7943, 0.8143, 0.9504e-4, 0.0,
   562  			0.8017, 0.6123, 0.7165, 0.7123e-4,
   563  		},
   564  	}
   565  }
   566  
   567  func (Wilk4) Eigenvalues() []complex128 {
   568  	return []complex128{
   569  		0.9504e-4, 0.9143e-4, 0.7156e-4, 0.7123e-4,
   570  	}
   571  }
   572  
   573  // Wilk12 is a 12×12 lower Hessenberg matrix with 12 distinct real eigenvalues.
   574  type Wilk12 struct{}
   575  
   576  func (Wilk12) Matrix() blas64.General {
   577  	return blas64.General{
   578  		Rows:   12,
   579  		Cols:   12,
   580  		Stride: 12,
   581  		Data: []float64{
   582  			12, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   583  			11, 11, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   584  			10, 10, 10, 9, 0, 0, 0, 0, 0, 0, 0, 0,
   585  			9, 9, 9, 9, 8, 0, 0, 0, 0, 0, 0, 0,
   586  			8, 8, 8, 8, 8, 7, 0, 0, 0, 0, 0, 0,
   587  			7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0,
   588  			6, 6, 6, 6, 6, 6, 6, 5, 0, 0, 0, 0,
   589  			5, 5, 5, 5, 5, 5, 5, 5, 4, 0, 0, 0,
   590  			4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 0, 0,
   591  			3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 0,
   592  			2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
   593  			1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
   594  		},
   595  	}
   596  }
   597  
   598  func (Wilk12) Eigenvalues() []complex128 {
   599  	return []complex128{
   600  		32.2288915015722210,
   601  		20.1989886458770691,
   602  		12.3110774008685340,
   603  		6.9615330855671154,
   604  		3.5118559485807528,
   605  		1.5539887091319704,
   606  		0.6435053190136506,
   607  		0.2847497205488856,
   608  		0.1436465181918488,
   609  		0.0812276683076552,
   610  		0.0495074140194613,
   611  		0.0310280683208907,
   612  	}
   613  }
   614  
   615  // Wilk20 is a 20×20 lower Hessenberg matrix. If the parameter is 0, the matrix
   616  // has 20 distinct real eigenvalues. If the parameter is 1e-10, the matrix has 6
   617  // real eigenvalues and 7 pairs of complex eigenvalues.
   618  type Wilk20 float64
   619  
   620  func (w Wilk20) Matrix() blas64.General {
   621  	a := zeros(20, 20, 20)
   622  	for i := 0; i < 20; i++ {
   623  		a.Data[i*a.Stride+i] = float64(i + 1)
   624  	}
   625  	for i := 0; i < 19; i++ {
   626  		a.Data[i*a.Stride+i+1] = 20
   627  	}
   628  	a.Data[19*a.Stride] = float64(w)
   629  	return a
   630  }
   631  
   632  func (w Wilk20) Eigenvalues() []complex128 {
   633  	if float64(w) == 0 {
   634  		ev := make([]complex128, 20)
   635  		for i := range ev {
   636  			ev[i] = complex(float64(i+1), 0)
   637  		}
   638  		return ev
   639  	}
   640  	return nil
   641  }
   642  
   643  // Zero is a matrix with all elements equal to zero.
   644  type Zero int
   645  
   646  func (z Zero) Matrix() blas64.General {
   647  	n := int(z)
   648  	return zeros(n, n, n)
   649  }
   650  
   651  func (z Zero) Eigenvalues() []complex128 {
   652  	n := int(z)
   653  	return make([]complex128, n)
   654  }