github.com/gopherd/gonum@v0.0.4/lapack/testlapack/locallapack.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  	"math"
     9  
    10  	"github.com/gopherd/gonum/blas"
    11  	"github.com/gopherd/gonum/internal/asm/f64"
    12  	"github.com/gopherd/gonum/lapack"
    13  )
    14  
    15  // dlagtm is a local implementation of Dlagtm to keep code paths independent.
    16  func dlagtm(trans blas.Transpose, m, n int, alpha float64, dl, d, du []float64, b []float64, ldb int, beta float64, c []float64, ldc int) {
    17  	if m == 0 || n == 0 {
    18  		return
    19  	}
    20  
    21  	if beta != 1 {
    22  		if beta == 0 {
    23  			for i := 0; i < m; i++ {
    24  				ci := c[i*ldc : i*ldc+n]
    25  				for j := range ci {
    26  					ci[j] = 0
    27  				}
    28  			}
    29  		} else {
    30  			for i := 0; i < m; i++ {
    31  				ci := c[i*ldc : i*ldc+n]
    32  				for j := range ci {
    33  					ci[j] *= beta
    34  				}
    35  			}
    36  		}
    37  	}
    38  
    39  	if alpha == 0 {
    40  		return
    41  	}
    42  
    43  	if m == 1 {
    44  		if alpha == 1 {
    45  			for j := 0; j < n; j++ {
    46  				c[j] += d[0] * b[j]
    47  			}
    48  		} else {
    49  			for j := 0; j < n; j++ {
    50  				c[j] += alpha * d[0] * b[j]
    51  			}
    52  		}
    53  		return
    54  	}
    55  
    56  	if trans != blas.NoTrans {
    57  		dl, du = du, dl
    58  	}
    59  
    60  	if alpha == 1 {
    61  		for j := 0; j < n; j++ {
    62  			c[j] += d[0]*b[j] + du[0]*b[ldb+j]
    63  		}
    64  		for i := 1; i < m-1; i++ {
    65  			for j := 0; j < n; j++ {
    66  				c[i*ldc+j] += dl[i-1]*b[(i-1)*ldb+j] + d[i]*b[i*ldb+j] + du[i]*b[(i+1)*ldb+j]
    67  			}
    68  		}
    69  		for j := 0; j < n; j++ {
    70  			c[(m-1)*ldc+j] += dl[m-2]*b[(m-2)*ldb+j] + d[m-1]*b[(m-1)*ldb+j]
    71  		}
    72  	} else {
    73  		for j := 0; j < n; j++ {
    74  			c[j] += alpha * (d[0]*b[j] + du[0]*b[ldb+j])
    75  		}
    76  		for i := 1; i < m-1; i++ {
    77  			for j := 0; j < n; j++ {
    78  				c[i*ldc+j] += alpha * (dl[i-1]*b[(i-1)*ldb+j] + d[i]*b[i*ldb+j] + du[i]*b[(i+1)*ldb+j])
    79  			}
    80  		}
    81  		for j := 0; j < n; j++ {
    82  			c[(m-1)*ldc+j] += alpha * (dl[m-2]*b[(m-2)*ldb+j] + d[m-1]*b[(m-1)*ldb+j])
    83  		}
    84  	}
    85  }
    86  
    87  // dlangt is a local implementation of Dlangt to keep code paths independent.
    88  func dlangt(norm lapack.MatrixNorm, n int, dl, d, du []float64) float64 {
    89  	if n == 0 {
    90  		return 0
    91  	}
    92  
    93  	dl = dl[:n-1]
    94  	d = d[:n]
    95  	du = du[:n-1]
    96  
    97  	var anorm float64
    98  	switch norm {
    99  	case lapack.MaxAbs:
   100  		for _, diag := range [][]float64{dl, d, du} {
   101  			for _, di := range diag {
   102  				if math.IsNaN(di) {
   103  					return di
   104  				}
   105  				di = math.Abs(di)
   106  				if di > anorm {
   107  					anorm = di
   108  				}
   109  			}
   110  		}
   111  	case lapack.MaxColumnSum:
   112  		if n == 1 {
   113  			return math.Abs(d[0])
   114  		}
   115  		anorm = math.Abs(d[0]) + math.Abs(dl[0])
   116  		if math.IsNaN(anorm) {
   117  			return anorm
   118  		}
   119  		tmp := math.Abs(du[n-2]) + math.Abs(d[n-1])
   120  		if math.IsNaN(tmp) {
   121  			return tmp
   122  		}
   123  		if tmp > anorm {
   124  			anorm = tmp
   125  		}
   126  		for i := 1; i < n-1; i++ {
   127  			tmp = math.Abs(du[i-1]) + math.Abs(d[i]) + math.Abs(dl[i])
   128  			if math.IsNaN(tmp) {
   129  				return tmp
   130  			}
   131  			if tmp > anorm {
   132  				anorm = tmp
   133  			}
   134  		}
   135  	case lapack.MaxRowSum:
   136  		if n == 1 {
   137  			return math.Abs(d[0])
   138  		}
   139  		anorm = math.Abs(d[0]) + math.Abs(du[0])
   140  		if math.IsNaN(anorm) {
   141  			return anorm
   142  		}
   143  		tmp := math.Abs(dl[n-2]) + math.Abs(d[n-1])
   144  		if math.IsNaN(tmp) {
   145  			return tmp
   146  		}
   147  		if tmp > anorm {
   148  			anorm = tmp
   149  		}
   150  		for i := 1; i < n-1; i++ {
   151  			tmp = math.Abs(dl[i-1]) + math.Abs(d[i]) + math.Abs(du[i])
   152  			if math.IsNaN(tmp) {
   153  				return tmp
   154  			}
   155  			if tmp > anorm {
   156  				anorm = tmp
   157  			}
   158  		}
   159  	case lapack.Frobenius:
   160  		panic("not implemented")
   161  	default:
   162  		panic("invalid norm")
   163  	}
   164  	return anorm
   165  }
   166  
   167  // dlansy is a local implementation of Dlansy to keep code paths independent.
   168  func dlansy(norm lapack.MatrixNorm, uplo blas.Uplo, n int, a []float64, lda int) float64 {
   169  	if n == 0 {
   170  		return 0
   171  	}
   172  	work := make([]float64, n)
   173  	switch norm {
   174  	case lapack.MaxAbs:
   175  		if uplo == blas.Upper {
   176  			var max float64
   177  			for i := 0; i < n; i++ {
   178  				for j := i; j < n; j++ {
   179  					v := math.Abs(a[i*lda+j])
   180  					if math.IsNaN(v) {
   181  						return math.NaN()
   182  					}
   183  					if v > max {
   184  						max = v
   185  					}
   186  				}
   187  			}
   188  			return max
   189  		}
   190  		var max float64
   191  		for i := 0; i < n; i++ {
   192  			for j := 0; j <= i; j++ {
   193  				v := math.Abs(a[i*lda+j])
   194  				if math.IsNaN(v) {
   195  					return math.NaN()
   196  				}
   197  				if v > max {
   198  					max = v
   199  				}
   200  			}
   201  		}
   202  		return max
   203  	case lapack.MaxRowSum, lapack.MaxColumnSum:
   204  		// A symmetric matrix has the same 1-norm and ∞-norm.
   205  		for i := 0; i < n; i++ {
   206  			work[i] = 0
   207  		}
   208  		if uplo == blas.Upper {
   209  			for i := 0; i < n; i++ {
   210  				work[i] += math.Abs(a[i*lda+i])
   211  				for j := i + 1; j < n; j++ {
   212  					v := math.Abs(a[i*lda+j])
   213  					work[i] += v
   214  					work[j] += v
   215  				}
   216  			}
   217  		} else {
   218  			for i := 0; i < n; i++ {
   219  				for j := 0; j < i; j++ {
   220  					v := math.Abs(a[i*lda+j])
   221  					work[i] += v
   222  					work[j] += v
   223  				}
   224  				work[i] += math.Abs(a[i*lda+i])
   225  			}
   226  		}
   227  		var max float64
   228  		for i := 0; i < n; i++ {
   229  			v := work[i]
   230  			if math.IsNaN(v) {
   231  				return math.NaN()
   232  			}
   233  			if v > max {
   234  				max = v
   235  			}
   236  		}
   237  		return max
   238  	case lapack.Frobenius:
   239  		panic("not implemented")
   240  	default:
   241  		panic("invalid norm")
   242  	}
   243  }
   244  
   245  // dlange is a local implementation of Dlange to keep code paths independent.
   246  func dlange(norm lapack.MatrixNorm, m, n int, a []float64, lda int) float64 {
   247  	if m == 0 || n == 0 {
   248  		return 0
   249  	}
   250  	var value float64
   251  	switch norm {
   252  	case lapack.MaxAbs:
   253  		for i := 0; i < m; i++ {
   254  			for j := 0; j < n; j++ {
   255  				value = math.Max(value, math.Abs(a[i*lda+j]))
   256  			}
   257  		}
   258  	case lapack.MaxColumnSum:
   259  		work := make([]float64, n)
   260  		for i := 0; i < m; i++ {
   261  			for j := 0; j < n; j++ {
   262  				work[j] += math.Abs(a[i*lda+j])
   263  			}
   264  		}
   265  		for i := 0; i < n; i++ {
   266  			value = math.Max(value, work[i])
   267  		}
   268  	case lapack.MaxRowSum:
   269  		for i := 0; i < m; i++ {
   270  			var sum float64
   271  			for j := 0; j < n; j++ {
   272  				sum += math.Abs(a[i*lda+j])
   273  			}
   274  			value = math.Max(value, sum)
   275  		}
   276  	case lapack.Frobenius:
   277  		for i := 0; i < m; i++ {
   278  			row := f64.L2NormUnitary(a[i*lda : i*lda+n])
   279  			value = math.Hypot(value, row)
   280  		}
   281  	default:
   282  		panic("invalid norm")
   283  	}
   284  	return value
   285  }
   286  
   287  // dlansb is a local implementation of Dlansb to keep code paths independent.
   288  func dlansb(norm lapack.MatrixNorm, uplo blas.Uplo, n, kd int, ab []float64, ldab int, work []float64) float64 {
   289  	if n == 0 {
   290  		return 0
   291  	}
   292  	var value float64
   293  	switch norm {
   294  	case lapack.MaxAbs:
   295  		if uplo == blas.Upper {
   296  			for i := 0; i < n; i++ {
   297  				for j := 0; j < min(n-i, kd+1); j++ {
   298  					aij := math.Abs(ab[i*ldab+j])
   299  					if aij > value || math.IsNaN(aij) {
   300  						value = aij
   301  					}
   302  				}
   303  			}
   304  		} else {
   305  			for i := 0; i < n; i++ {
   306  				for j := max(0, kd-i); j < kd+1; j++ {
   307  					aij := math.Abs(ab[i*ldab+j])
   308  					if aij > value || math.IsNaN(aij) {
   309  						value = aij
   310  					}
   311  				}
   312  			}
   313  		}
   314  	case lapack.MaxColumnSum, lapack.MaxRowSum:
   315  		work = work[:n]
   316  		var sum float64
   317  		if uplo == blas.Upper {
   318  			for i := range work {
   319  				work[i] = 0
   320  			}
   321  			for i := 0; i < n; i++ {
   322  				sum := work[i] + math.Abs(ab[i*ldab])
   323  				for j := i + 1; j < min(i+kd+1, n); j++ {
   324  					aij := math.Abs(ab[i*ldab+j-i])
   325  					sum += aij
   326  					work[j] += aij
   327  				}
   328  				if sum > value || math.IsNaN(sum) {
   329  					value = sum
   330  				}
   331  			}
   332  		} else {
   333  			for i := 0; i < n; i++ {
   334  				sum = 0
   335  				for j := max(0, i-kd); j < i; j++ {
   336  					aij := math.Abs(ab[i*ldab+kd+j-i])
   337  					sum += aij
   338  					work[j] += aij
   339  				}
   340  				work[i] = sum + math.Abs(ab[i*ldab+kd])
   341  			}
   342  			for _, sum := range work {
   343  				if sum > value || math.IsNaN(sum) {
   344  					value = sum
   345  				}
   346  			}
   347  		}
   348  	case lapack.Frobenius:
   349  		panic("not implemented")
   350  	default:
   351  		panic("invalid norm")
   352  	}
   353  	return value
   354  }
   355  
   356  // dlantr is a local implementation of Dlantr to keep code paths independent.
   357  func dlantr(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, m, n int, a []float64, lda int, work []float64) float64 {
   358  	// Quick return if possible.
   359  	minmn := min(m, n)
   360  	if minmn == 0 {
   361  		return 0
   362  	}
   363  	switch norm {
   364  	case lapack.MaxAbs:
   365  		if diag == blas.Unit {
   366  			value := 1.0
   367  			if uplo == blas.Upper {
   368  				for i := 0; i < m; i++ {
   369  					for j := i + 1; j < n; j++ {
   370  						tmp := math.Abs(a[i*lda+j])
   371  						if math.IsNaN(tmp) {
   372  							return tmp
   373  						}
   374  						if tmp > value {
   375  							value = tmp
   376  						}
   377  					}
   378  				}
   379  				return value
   380  			}
   381  			for i := 1; i < m; i++ {
   382  				for j := 0; j < min(i, n); j++ {
   383  					tmp := math.Abs(a[i*lda+j])
   384  					if math.IsNaN(tmp) {
   385  						return tmp
   386  					}
   387  					if tmp > value {
   388  						value = tmp
   389  					}
   390  				}
   391  			}
   392  			return value
   393  		}
   394  		var value float64
   395  		if uplo == blas.Upper {
   396  			for i := 0; i < m; i++ {
   397  				for j := i; j < n; j++ {
   398  					tmp := math.Abs(a[i*lda+j])
   399  					if math.IsNaN(tmp) {
   400  						return tmp
   401  					}
   402  					if tmp > value {
   403  						value = tmp
   404  					}
   405  				}
   406  			}
   407  			return value
   408  		}
   409  		for i := 0; i < m; i++ {
   410  			for j := 0; j <= min(i, n-1); j++ {
   411  				tmp := math.Abs(a[i*lda+j])
   412  				if math.IsNaN(tmp) {
   413  					return tmp
   414  				}
   415  				if tmp > value {
   416  					value = tmp
   417  				}
   418  			}
   419  		}
   420  		return value
   421  	case lapack.MaxColumnSum:
   422  		if diag == blas.Unit {
   423  			for i := 0; i < minmn; i++ {
   424  				work[i] = 1
   425  			}
   426  			for i := minmn; i < n; i++ {
   427  				work[i] = 0
   428  			}
   429  			if uplo == blas.Upper {
   430  				for i := 0; i < m; i++ {
   431  					for j := i + 1; j < n; j++ {
   432  						work[j] += math.Abs(a[i*lda+j])
   433  					}
   434  				}
   435  			} else {
   436  				for i := 1; i < m; i++ {
   437  					for j := 0; j < min(i, n); j++ {
   438  						work[j] += math.Abs(a[i*lda+j])
   439  					}
   440  				}
   441  			}
   442  		} else {
   443  			for i := 0; i < n; i++ {
   444  				work[i] = 0
   445  			}
   446  			if uplo == blas.Upper {
   447  				for i := 0; i < m; i++ {
   448  					for j := i; j < n; j++ {
   449  						work[j] += math.Abs(a[i*lda+j])
   450  					}
   451  				}
   452  			} else {
   453  				for i := 0; i < m; i++ {
   454  					for j := 0; j <= min(i, n-1); j++ {
   455  						work[j] += math.Abs(a[i*lda+j])
   456  					}
   457  				}
   458  			}
   459  		}
   460  		var max float64
   461  		for _, v := range work[:n] {
   462  			if math.IsNaN(v) {
   463  				return math.NaN()
   464  			}
   465  			if v > max {
   466  				max = v
   467  			}
   468  		}
   469  		return max
   470  	case lapack.MaxRowSum:
   471  		var maxsum float64
   472  		if diag == blas.Unit {
   473  			if uplo == blas.Upper {
   474  				for i := 0; i < m; i++ {
   475  					var sum float64
   476  					if i < minmn {
   477  						sum = 1
   478  					}
   479  					for j := i + 1; j < n; j++ {
   480  						sum += math.Abs(a[i*lda+j])
   481  					}
   482  					if math.IsNaN(sum) {
   483  						return math.NaN()
   484  					}
   485  					if sum > maxsum {
   486  						maxsum = sum
   487  					}
   488  				}
   489  				return maxsum
   490  			} else {
   491  				for i := 0; i < m; i++ {
   492  					var sum float64
   493  					if i < minmn {
   494  						sum = 1
   495  					}
   496  					for j := 0; j < min(i, n); j++ {
   497  						sum += math.Abs(a[i*lda+j])
   498  					}
   499  					if math.IsNaN(sum) {
   500  						return math.NaN()
   501  					}
   502  					if sum > maxsum {
   503  						maxsum = sum
   504  					}
   505  				}
   506  				return maxsum
   507  			}
   508  		} else {
   509  			if uplo == blas.Upper {
   510  				for i := 0; i < m; i++ {
   511  					var sum float64
   512  					for j := i; j < n; j++ {
   513  						sum += math.Abs(a[i*lda+j])
   514  					}
   515  					if math.IsNaN(sum) {
   516  						return sum
   517  					}
   518  					if sum > maxsum {
   519  						maxsum = sum
   520  					}
   521  				}
   522  				return maxsum
   523  			} else {
   524  				for i := 0; i < m; i++ {
   525  					var sum float64
   526  					for j := 0; j <= min(i, n-1); j++ {
   527  						sum += math.Abs(a[i*lda+j])
   528  					}
   529  					if math.IsNaN(sum) {
   530  						return sum
   531  					}
   532  					if sum > maxsum {
   533  						maxsum = sum
   534  					}
   535  				}
   536  				return maxsum
   537  			}
   538  		}
   539  	case lapack.Frobenius:
   540  		panic("not implemented")
   541  	default:
   542  		panic("invalid norm")
   543  	}
   544  }
   545  
   546  // dlantb is a local implementation of Dlantb to keep code paths independent.
   547  func dlantb(norm lapack.MatrixNorm, uplo blas.Uplo, diag blas.Diag, n, k int, a []float64, lda int, work []float64) float64 {
   548  	if n == 0 {
   549  		return 0
   550  	}
   551  	var value float64
   552  	switch norm {
   553  	case lapack.MaxAbs:
   554  		if uplo == blas.Upper {
   555  			var jfirst int
   556  			if diag == blas.Unit {
   557  				value = 1
   558  				jfirst = 1
   559  			}
   560  			for i := 0; i < n; i++ {
   561  				for _, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] {
   562  					if math.IsNaN(aij) {
   563  						return aij
   564  					}
   565  					aij = math.Abs(aij)
   566  					if aij > value {
   567  						value = aij
   568  					}
   569  				}
   570  			}
   571  		} else {
   572  			jlast := k + 1
   573  			if diag == blas.Unit {
   574  				value = 1
   575  				jlast = k
   576  			}
   577  			for i := 0; i < n; i++ {
   578  				for _, aij := range a[i*lda+max(0, k-i) : i*lda+jlast] {
   579  					if math.IsNaN(aij) {
   580  						return math.NaN()
   581  					}
   582  					aij = math.Abs(aij)
   583  					if aij > value {
   584  						value = aij
   585  					}
   586  				}
   587  			}
   588  		}
   589  	case lapack.MaxRowSum:
   590  		var sum float64
   591  		if uplo == blas.Upper {
   592  			var jfirst int
   593  			if diag == blas.Unit {
   594  				jfirst = 1
   595  			}
   596  			for i := 0; i < n; i++ {
   597  				sum = 0
   598  				if diag == blas.Unit {
   599  					sum = 1
   600  				}
   601  				for _, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] {
   602  					sum += math.Abs(aij)
   603  				}
   604  				if math.IsNaN(sum) {
   605  					return math.NaN()
   606  				}
   607  				if sum > value {
   608  					value = sum
   609  				}
   610  			}
   611  		} else {
   612  			jlast := k + 1
   613  			if diag == blas.Unit {
   614  				jlast = k
   615  			}
   616  			for i := 0; i < n; i++ {
   617  				sum = 0
   618  				if diag == blas.Unit {
   619  					sum = 1
   620  				}
   621  				for _, aij := range a[i*lda+max(0, k-i) : i*lda+jlast] {
   622  					sum += math.Abs(aij)
   623  				}
   624  				if math.IsNaN(sum) {
   625  					return math.NaN()
   626  				}
   627  				if sum > value {
   628  					value = sum
   629  				}
   630  			}
   631  		}
   632  	case lapack.MaxColumnSum:
   633  		work = work[:n]
   634  		if diag == blas.Unit {
   635  			for i := range work {
   636  				work[i] = 1
   637  			}
   638  		} else {
   639  			for i := range work {
   640  				work[i] = 0
   641  			}
   642  		}
   643  		if uplo == blas.Upper {
   644  			var jfirst int
   645  			if diag == blas.Unit {
   646  				jfirst = 1
   647  			}
   648  			for i := 0; i < n; i++ {
   649  				for j, aij := range a[i*lda+jfirst : i*lda+min(n-i, k+1)] {
   650  					work[i+jfirst+j] += math.Abs(aij)
   651  				}
   652  			}
   653  		} else {
   654  			jlast := k + 1
   655  			if diag == blas.Unit {
   656  				jlast = k
   657  			}
   658  			for i := 0; i < n; i++ {
   659  				off := max(0, k-i)
   660  				for j, aij := range a[i*lda+off : i*lda+jlast] {
   661  					work[i+j+off-k] += math.Abs(aij)
   662  				}
   663  			}
   664  		}
   665  		for _, wi := range work {
   666  			if math.IsNaN(wi) {
   667  				return math.NaN()
   668  			}
   669  			if wi > value {
   670  				value = wi
   671  			}
   672  		}
   673  	case lapack.Frobenius:
   674  		panic("not implemented")
   675  	default:
   676  		panic("invalid norm")
   677  	}
   678  	return value
   679  }