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