github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/blas/gonum/level1float64.go (about)

     1  // Copyright ©2015 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 gonum
     6  
     7  import (
     8  	"math"
     9  
    10  	"github.com/jingcheng-WU/gonum/blas"
    11  	"github.com/jingcheng-WU/gonum/internal/asm/f64"
    12  )
    13  
    14  var _ blas.Float64Level1 = Implementation{}
    15  
    16  // Dnrm2 computes the Euclidean norm of a vector,
    17  //  sqrt(\sum_i x[i] * x[i]).
    18  // This function returns 0 if incX is negative.
    19  func (Implementation) Dnrm2(n int, x []float64, incX int) float64 {
    20  	if incX < 1 {
    21  		if incX == 0 {
    22  			panic(zeroIncX)
    23  		}
    24  		return 0
    25  	}
    26  	if len(x) <= (n-1)*incX {
    27  		panic(shortX)
    28  	}
    29  	if n < 2 {
    30  		if n == 1 {
    31  			return math.Abs(x[0])
    32  		}
    33  		if n == 0 {
    34  			return 0
    35  		}
    36  		panic(nLT0)
    37  	}
    38  	if incX == 1 {
    39  		return f64.L2NormUnitary(x[:n])
    40  	}
    41  	return f64.L2NormInc(x, uintptr(n), uintptr(incX))
    42  }
    43  
    44  // Dasum computes the sum of the absolute values of the elements of x.
    45  //  \sum_i |x[i]|
    46  // Dasum returns 0 if incX is negative.
    47  func (Implementation) Dasum(n int, x []float64, incX int) float64 {
    48  	var sum float64
    49  	if n < 0 {
    50  		panic(nLT0)
    51  	}
    52  	if incX < 1 {
    53  		if incX == 0 {
    54  			panic(zeroIncX)
    55  		}
    56  		return 0
    57  	}
    58  	if len(x) <= (n-1)*incX {
    59  		panic(shortX)
    60  	}
    61  	if incX == 1 {
    62  		x = x[:n]
    63  		for _, v := range x {
    64  			sum += math.Abs(v)
    65  		}
    66  		return sum
    67  	}
    68  	for i := 0; i < n; i++ {
    69  		sum += math.Abs(x[i*incX])
    70  	}
    71  	return sum
    72  }
    73  
    74  // Idamax returns the index of an element of x with the largest absolute value.
    75  // If there are multiple such indices the earliest is returned.
    76  // Idamax returns -1 if n == 0.
    77  func (Implementation) Idamax(n int, x []float64, incX int) int {
    78  	if incX < 1 {
    79  		if incX == 0 {
    80  			panic(zeroIncX)
    81  		}
    82  		return -1
    83  	}
    84  	if len(x) <= (n-1)*incX {
    85  		panic(shortX)
    86  	}
    87  	if n < 2 {
    88  		if n == 1 {
    89  			return 0
    90  		}
    91  		if n == 0 {
    92  			return -1 // Netlib returns invalid index when n == 0.
    93  		}
    94  		panic(nLT0)
    95  	}
    96  	idx := 0
    97  	max := math.Abs(x[0])
    98  	if incX == 1 {
    99  		for i, v := range x[:n] {
   100  			absV := math.Abs(v)
   101  			if absV > max {
   102  				max = absV
   103  				idx = i
   104  			}
   105  		}
   106  		return idx
   107  	}
   108  	ix := incX
   109  	for i := 1; i < n; i++ {
   110  		v := x[ix]
   111  		absV := math.Abs(v)
   112  		if absV > max {
   113  			max = absV
   114  			idx = i
   115  		}
   116  		ix += incX
   117  	}
   118  	return idx
   119  }
   120  
   121  // Dswap exchanges the elements of two vectors.
   122  //  x[i], y[i] = y[i], x[i] for all i
   123  func (Implementation) Dswap(n int, x []float64, incX int, y []float64, incY int) {
   124  	if incX == 0 {
   125  		panic(zeroIncX)
   126  	}
   127  	if incY == 0 {
   128  		panic(zeroIncY)
   129  	}
   130  	if n < 1 {
   131  		if n == 0 {
   132  			return
   133  		}
   134  		panic(nLT0)
   135  	}
   136  	if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
   137  		panic(shortX)
   138  	}
   139  	if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
   140  		panic(shortY)
   141  	}
   142  	if incX == 1 && incY == 1 {
   143  		x = x[:n]
   144  		for i, v := range x {
   145  			x[i], y[i] = y[i], v
   146  		}
   147  		return
   148  	}
   149  	var ix, iy int
   150  	if incX < 0 {
   151  		ix = (-n + 1) * incX
   152  	}
   153  	if incY < 0 {
   154  		iy = (-n + 1) * incY
   155  	}
   156  	for i := 0; i < n; i++ {
   157  		x[ix], y[iy] = y[iy], x[ix]
   158  		ix += incX
   159  		iy += incY
   160  	}
   161  }
   162  
   163  // Dcopy copies the elements of x into the elements of y.
   164  //  y[i] = x[i] for all i
   165  func (Implementation) Dcopy(n int, x []float64, incX int, y []float64, incY int) {
   166  	if incX == 0 {
   167  		panic(zeroIncX)
   168  	}
   169  	if incY == 0 {
   170  		panic(zeroIncY)
   171  	}
   172  	if n < 1 {
   173  		if n == 0 {
   174  			return
   175  		}
   176  		panic(nLT0)
   177  	}
   178  	if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
   179  		panic(shortX)
   180  	}
   181  	if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
   182  		panic(shortY)
   183  	}
   184  	if incX == 1 && incY == 1 {
   185  		copy(y[:n], x[:n])
   186  		return
   187  	}
   188  	var ix, iy int
   189  	if incX < 0 {
   190  		ix = (-n + 1) * incX
   191  	}
   192  	if incY < 0 {
   193  		iy = (-n + 1) * incY
   194  	}
   195  	for i := 0; i < n; i++ {
   196  		y[iy] = x[ix]
   197  		ix += incX
   198  		iy += incY
   199  	}
   200  }
   201  
   202  // Daxpy adds alpha times x to y
   203  //  y[i] += alpha * x[i] for all i
   204  func (Implementation) Daxpy(n int, alpha float64, x []float64, incX int, y []float64, incY int) {
   205  	if incX == 0 {
   206  		panic(zeroIncX)
   207  	}
   208  	if incY == 0 {
   209  		panic(zeroIncY)
   210  	}
   211  	if n < 1 {
   212  		if n == 0 {
   213  			return
   214  		}
   215  		panic(nLT0)
   216  	}
   217  	if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
   218  		panic(shortX)
   219  	}
   220  	if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
   221  		panic(shortY)
   222  	}
   223  	if alpha == 0 {
   224  		return
   225  	}
   226  	if incX == 1 && incY == 1 {
   227  		f64.AxpyUnitary(alpha, x[:n], y[:n])
   228  		return
   229  	}
   230  	var ix, iy int
   231  	if incX < 0 {
   232  		ix = (-n + 1) * incX
   233  	}
   234  	if incY < 0 {
   235  		iy = (-n + 1) * incY
   236  	}
   237  	f64.AxpyInc(alpha, x, y, uintptr(n), uintptr(incX), uintptr(incY), uintptr(ix), uintptr(iy))
   238  }
   239  
   240  // Drotg computes the plane rotation
   241  //   _    _      _ _       _ _
   242  //  |  c s |    | a |     | r |
   243  //  | -s c |  * | b |   = | 0 |
   244  //   ‾    ‾      ‾ ‾       ‾ ‾
   245  // where
   246  //  r = ±√(a^2 + b^2)
   247  //  c = a/r, the cosine of the plane rotation
   248  //  s = b/r, the sine of the plane rotation
   249  //
   250  // NOTE: There is a discrepancy between the reference implementation and the BLAS
   251  // technical manual regarding the sign for r when a or b are zero.
   252  // Drotg agrees with the definition in the manual and other
   253  // common BLAS implementations.
   254  func (Implementation) Drotg(a, b float64) (c, s, r, z float64) {
   255  	if b == 0 && a == 0 {
   256  		return 1, 0, a, 0
   257  	}
   258  	absA := math.Abs(a)
   259  	absB := math.Abs(b)
   260  	aGTb := absA > absB
   261  	r = math.Hypot(a, b)
   262  	if aGTb {
   263  		r = math.Copysign(r, a)
   264  	} else {
   265  		r = math.Copysign(r, b)
   266  	}
   267  	c = a / r
   268  	s = b / r
   269  	if aGTb {
   270  		z = s
   271  	} else if c != 0 { // r == 0 case handled above
   272  		z = 1 / c
   273  	} else {
   274  		z = 1
   275  	}
   276  	return
   277  }
   278  
   279  // Drotmg computes the modified Givens rotation. See
   280  // http://www.netlib.org/lapack/explore-html/df/deb/drotmg_8f.html
   281  // for more details.
   282  func (Implementation) Drotmg(d1, d2, x1, y1 float64) (p blas.DrotmParams, rd1, rd2, rx1 float64) {
   283  	// The implementation of Drotmg used here is taken from Hopkins 1997
   284  	// Appendix A: https://doi.org/10.1145/289251.289253
   285  	// with the exception of the gam constants below.
   286  
   287  	const (
   288  		gam    = 4096.0
   289  		gamsq  = gam * gam
   290  		rgamsq = 1.0 / gamsq
   291  	)
   292  
   293  	if d1 < 0 {
   294  		p.Flag = blas.Rescaling // Error state.
   295  		return p, 0, 0, 0
   296  	}
   297  
   298  	if d2 == 0 || y1 == 0 {
   299  		p.Flag = blas.Identity
   300  		return p, d1, d2, x1
   301  	}
   302  
   303  	var h11, h12, h21, h22 float64
   304  	if (d1 == 0 || x1 == 0) && d2 > 0 {
   305  		p.Flag = blas.Diagonal
   306  		h12 = 1
   307  		h21 = -1
   308  		x1 = y1
   309  		d1, d2 = d2, d1
   310  	} else {
   311  		p2 := d2 * y1
   312  		p1 := d1 * x1
   313  		q2 := p2 * y1
   314  		q1 := p1 * x1
   315  		if math.Abs(q1) > math.Abs(q2) {
   316  			p.Flag = blas.OffDiagonal
   317  			h11 = 1
   318  			h22 = 1
   319  			h21 = -y1 / x1
   320  			h12 = p2 / p1
   321  			u := 1 - float64(h12*h21)
   322  			if u <= 0 {
   323  				p.Flag = blas.Rescaling // Error state.
   324  				return p, 0, 0, 0
   325  			}
   326  
   327  			d1 /= u
   328  			d2 /= u
   329  			x1 *= u
   330  		} else {
   331  			if q2 < 0 {
   332  				p.Flag = blas.Rescaling // Error state.
   333  				return p, 0, 0, 0
   334  			}
   335  
   336  			p.Flag = blas.Diagonal
   337  			h21 = -1
   338  			h12 = 1
   339  			h11 = p1 / p2
   340  			h22 = x1 / y1
   341  			u := 1 + float64(h11*h22)
   342  			d1, d2 = d2/u, d1/u
   343  			x1 = y1 * u
   344  		}
   345  	}
   346  
   347  	for d1 <= rgamsq && d1 != 0 {
   348  		p.Flag = blas.Rescaling
   349  		d1 = (d1 * gam) * gam
   350  		x1 /= gam
   351  		h11 /= gam
   352  		h12 /= gam
   353  	}
   354  	for d1 > gamsq {
   355  		p.Flag = blas.Rescaling
   356  		d1 = (d1 / gam) / gam
   357  		x1 *= gam
   358  		h11 *= gam
   359  		h12 *= gam
   360  	}
   361  
   362  	for math.Abs(d2) <= rgamsq && d2 != 0 {
   363  		p.Flag = blas.Rescaling
   364  		d2 = (d2 * gam) * gam
   365  		h21 /= gam
   366  		h22 /= gam
   367  	}
   368  	for math.Abs(d2) > gamsq {
   369  		p.Flag = blas.Rescaling
   370  		d2 = (d2 / gam) / gam
   371  		h21 *= gam
   372  		h22 *= gam
   373  	}
   374  
   375  	switch p.Flag {
   376  	case blas.Diagonal:
   377  		p.H = [4]float64{0: h11, 3: h22}
   378  	case blas.OffDiagonal:
   379  		p.H = [4]float64{1: h21, 2: h12}
   380  	case blas.Rescaling:
   381  		p.H = [4]float64{h11, h21, h12, h22}
   382  	default:
   383  		panic(badFlag)
   384  	}
   385  
   386  	return p, d1, d2, x1
   387  }
   388  
   389  // Drot applies a plane transformation.
   390  //  x[i] = c * x[i] + s * y[i]
   391  //  y[i] = c * y[i] - s * x[i]
   392  func (Implementation) Drot(n int, x []float64, incX int, y []float64, incY int, c float64, s float64) {
   393  	if incX == 0 {
   394  		panic(zeroIncX)
   395  	}
   396  	if incY == 0 {
   397  		panic(zeroIncY)
   398  	}
   399  	if n < 1 {
   400  		if n == 0 {
   401  			return
   402  		}
   403  		panic(nLT0)
   404  	}
   405  	if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
   406  		panic(shortX)
   407  	}
   408  	if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
   409  		panic(shortY)
   410  	}
   411  	if incX == 1 && incY == 1 {
   412  		x = x[:n]
   413  		for i, vx := range x {
   414  			vy := y[i]
   415  			x[i], y[i] = c*vx+s*vy, c*vy-s*vx
   416  		}
   417  		return
   418  	}
   419  	var ix, iy int
   420  	if incX < 0 {
   421  		ix = (-n + 1) * incX
   422  	}
   423  	if incY < 0 {
   424  		iy = (-n + 1) * incY
   425  	}
   426  	for i := 0; i < n; i++ {
   427  		vx := x[ix]
   428  		vy := y[iy]
   429  		x[ix], y[iy] = c*vx+s*vy, c*vy-s*vx
   430  		ix += incX
   431  		iy += incY
   432  	}
   433  }
   434  
   435  // Drotm applies the modified Givens rotation to the 2×n matrix.
   436  func (Implementation) Drotm(n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) {
   437  	if incX == 0 {
   438  		panic(zeroIncX)
   439  	}
   440  	if incY == 0 {
   441  		panic(zeroIncY)
   442  	}
   443  	if n <= 0 {
   444  		if n == 0 {
   445  			return
   446  		}
   447  		panic(nLT0)
   448  	}
   449  	if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
   450  		panic(shortX)
   451  	}
   452  	if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
   453  		panic(shortY)
   454  	}
   455  
   456  	if p.Flag == blas.Identity {
   457  		return
   458  	}
   459  
   460  	switch p.Flag {
   461  	case blas.Rescaling:
   462  		h11 := p.H[0]
   463  		h12 := p.H[2]
   464  		h21 := p.H[1]
   465  		h22 := p.H[3]
   466  		if incX == 1 && incY == 1 {
   467  			x = x[:n]
   468  			for i, vx := range x {
   469  				vy := y[i]
   470  				x[i], y[i] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(vy*h22)
   471  			}
   472  			return
   473  		}
   474  		var ix, iy int
   475  		if incX < 0 {
   476  			ix = (-n + 1) * incX
   477  		}
   478  		if incY < 0 {
   479  			iy = (-n + 1) * incY
   480  		}
   481  		for i := 0; i < n; i++ {
   482  			vx := x[ix]
   483  			vy := y[iy]
   484  			x[ix], y[iy] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(vy*h22)
   485  			ix += incX
   486  			iy += incY
   487  		}
   488  	case blas.OffDiagonal:
   489  		h12 := p.H[2]
   490  		h21 := p.H[1]
   491  		if incX == 1 && incY == 1 {
   492  			x = x[:n]
   493  			for i, vx := range x {
   494  				vy := y[i]
   495  				x[i], y[i] = vx+float64(vy*h12), float64(vx*h21)+vy
   496  			}
   497  			return
   498  		}
   499  		var ix, iy int
   500  		if incX < 0 {
   501  			ix = (-n + 1) * incX
   502  		}
   503  		if incY < 0 {
   504  			iy = (-n + 1) * incY
   505  		}
   506  		for i := 0; i < n; i++ {
   507  			vx := x[ix]
   508  			vy := y[iy]
   509  			x[ix], y[iy] = vx+float64(vy*h12), float64(vx*h21)+vy
   510  			ix += incX
   511  			iy += incY
   512  		}
   513  	case blas.Diagonal:
   514  		h11 := p.H[0]
   515  		h22 := p.H[3]
   516  		if incX == 1 && incY == 1 {
   517  			x = x[:n]
   518  			for i, vx := range x {
   519  				vy := y[i]
   520  				x[i], y[i] = float64(vx*h11)+vy, -vx+float64(vy*h22)
   521  			}
   522  			return
   523  		}
   524  		var ix, iy int
   525  		if incX < 0 {
   526  			ix = (-n + 1) * incX
   527  		}
   528  		if incY < 0 {
   529  			iy = (-n + 1) * incY
   530  		}
   531  		for i := 0; i < n; i++ {
   532  			vx := x[ix]
   533  			vy := y[iy]
   534  			x[ix], y[iy] = float64(vx*h11)+vy, -vx+float64(vy*h22)
   535  			ix += incX
   536  			iy += incY
   537  		}
   538  	}
   539  }
   540  
   541  // Dscal scales x by alpha.
   542  //  x[i] *= alpha
   543  // Dscal has no effect if incX < 0.
   544  func (Implementation) Dscal(n int, alpha float64, x []float64, incX int) {
   545  	if incX < 1 {
   546  		if incX == 0 {
   547  			panic(zeroIncX)
   548  		}
   549  		return
   550  	}
   551  	if n < 1 {
   552  		if n == 0 {
   553  			return
   554  		}
   555  		panic(nLT0)
   556  	}
   557  	if (n-1)*incX >= len(x) {
   558  		panic(shortX)
   559  	}
   560  	if alpha == 0 {
   561  		if incX == 1 {
   562  			x = x[:n]
   563  			for i := range x {
   564  				x[i] = 0
   565  			}
   566  			return
   567  		}
   568  		for ix := 0; ix < n*incX; ix += incX {
   569  			x[ix] = 0
   570  		}
   571  		return
   572  	}
   573  	if incX == 1 {
   574  		f64.ScalUnitary(alpha, x[:n])
   575  		return
   576  	}
   577  	f64.ScalInc(alpha, x, uintptr(n), uintptr(incX))
   578  }