github.com/gopherd/gonum@v0.0.4/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/gopherd/gonum/blas"
    11  	"github.com/gopherd/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 a plane rotation
   241  //  ⎡  c s ⎤ ⎡ a ⎤ = ⎡ r ⎤
   242  //  ⎣ -s c ⎦ ⎣ b ⎦   ⎣ 0 ⎦
   243  // satisfying c^2 + s^2 = 1.
   244  //
   245  // The computation uses the formulas
   246  //  sigma = sgn(a)    if |a| >  |b|
   247  //        = sgn(b)    if |b| >= |a|
   248  //  r = sigma*sqrt(a^2 + b^2)
   249  //  c = 1; s = 0      if r = 0
   250  //  c = a/r; s = b/r  if r != 0
   251  //  c >= 0            if |a| > |b|
   252  //
   253  // The subroutine also computes
   254  //  z = s    if |a| > |b|,
   255  //    = 1/c  if |b| >= |a| and c != 0
   256  //    = 1    if c = 0
   257  // This allows c and s to be reconstructed from z as follows:
   258  //  If z = 1, set c = 0, s = 1.
   259  //  If |z| < 1, set c = sqrt(1 - z^2) and s = z.
   260  //  If |z| > 1, set c = 1/z and s = sqrt(1 - c^2).
   261  //
   262  // NOTE: There is a discrepancy between the reference implementation and the
   263  // BLAS technical manual regarding the sign for r when a or b are zero. Drotg
   264  // agrees with the definition in the manual and other common BLAS
   265  // implementations.
   266  func (Implementation) Drotg(a, b float64) (c, s, r, z float64) {
   267  	// Implementation based on Supplemental Material to:
   268  	// Edward Anderson. 2017. Algorithm 978: Safe Scaling in the Level 1 BLAS.
   269  	// ACM Trans. Math. Softw. 44, 1, Article 12 (July 2017), 28 pages.
   270  	// DOI: https://doi.org/10.1145/3061665
   271  	const (
   272  		safmin = 0x1p-1022
   273  		safmax = 1 / safmin
   274  	)
   275  	anorm := math.Abs(a)
   276  	bnorm := math.Abs(b)
   277  	switch {
   278  	case bnorm == 0:
   279  		c = 1
   280  		s = 0
   281  		r = a
   282  		z = 0
   283  	case anorm == 0:
   284  		c = 0
   285  		s = 1
   286  		r = b
   287  		z = 1
   288  	default:
   289  		maxab := math.Max(anorm, bnorm)
   290  		scl := math.Min(math.Max(safmin, maxab), safmax)
   291  		var sigma float64
   292  		if anorm > bnorm {
   293  			sigma = math.Copysign(1, a)
   294  		} else {
   295  			sigma = math.Copysign(1, b)
   296  		}
   297  		ascl := a / scl
   298  		bscl := b / scl
   299  		r = sigma * (scl * math.Sqrt(ascl*ascl+bscl*bscl))
   300  		c = a / r
   301  		s = b / r
   302  		switch {
   303  		case anorm > bnorm:
   304  			z = s
   305  		case c != 0:
   306  			z = 1 / c
   307  		default:
   308  			z = 1
   309  		}
   310  	}
   311  	return c, s, r, z
   312  }
   313  
   314  // Drotmg computes the modified Givens rotation. See
   315  // http://www.netlib.org/lapack/explore-html/df/deb/drotmg_8f.html
   316  // for more details.
   317  func (Implementation) Drotmg(d1, d2, x1, y1 float64) (p blas.DrotmParams, rd1, rd2, rx1 float64) {
   318  	// The implementation of Drotmg used here is taken from Hopkins 1997
   319  	// Appendix A: https://doi.org/10.1145/289251.289253
   320  	// with the exception of the gam constants below.
   321  
   322  	const (
   323  		gam    = 4096.0
   324  		gamsq  = gam * gam
   325  		rgamsq = 1.0 / gamsq
   326  	)
   327  
   328  	if d1 < 0 {
   329  		p.Flag = blas.Rescaling // Error state.
   330  		return p, 0, 0, 0
   331  	}
   332  
   333  	if d2 == 0 || y1 == 0 {
   334  		p.Flag = blas.Identity
   335  		return p, d1, d2, x1
   336  	}
   337  
   338  	var h11, h12, h21, h22 float64
   339  	if (d1 == 0 || x1 == 0) && d2 > 0 {
   340  		p.Flag = blas.Diagonal
   341  		h12 = 1
   342  		h21 = -1
   343  		x1 = y1
   344  		d1, d2 = d2, d1
   345  	} else {
   346  		p2 := d2 * y1
   347  		p1 := d1 * x1
   348  		q2 := p2 * y1
   349  		q1 := p1 * x1
   350  		if math.Abs(q1) > math.Abs(q2) {
   351  			p.Flag = blas.OffDiagonal
   352  			h11 = 1
   353  			h22 = 1
   354  			h21 = -y1 / x1
   355  			h12 = p2 / p1
   356  			u := 1 - float64(h12*h21)
   357  			if u <= 0 {
   358  				p.Flag = blas.Rescaling // Error state.
   359  				return p, 0, 0, 0
   360  			}
   361  
   362  			d1 /= u
   363  			d2 /= u
   364  			x1 *= u
   365  		} else {
   366  			if q2 < 0 {
   367  				p.Flag = blas.Rescaling // Error state.
   368  				return p, 0, 0, 0
   369  			}
   370  
   371  			p.Flag = blas.Diagonal
   372  			h21 = -1
   373  			h12 = 1
   374  			h11 = p1 / p2
   375  			h22 = x1 / y1
   376  			u := 1 + float64(h11*h22)
   377  			d1, d2 = d2/u, d1/u
   378  			x1 = y1 * u
   379  		}
   380  	}
   381  
   382  	for d1 <= rgamsq && d1 != 0 {
   383  		p.Flag = blas.Rescaling
   384  		d1 = (d1 * gam) * gam
   385  		x1 /= gam
   386  		h11 /= gam
   387  		h12 /= gam
   388  	}
   389  	for d1 > gamsq {
   390  		p.Flag = blas.Rescaling
   391  		d1 = (d1 / gam) / gam
   392  		x1 *= gam
   393  		h11 *= gam
   394  		h12 *= gam
   395  	}
   396  
   397  	for math.Abs(d2) <= rgamsq && d2 != 0 {
   398  		p.Flag = blas.Rescaling
   399  		d2 = (d2 * gam) * gam
   400  		h21 /= gam
   401  		h22 /= gam
   402  	}
   403  	for math.Abs(d2) > gamsq {
   404  		p.Flag = blas.Rescaling
   405  		d2 = (d2 / gam) / gam
   406  		h21 *= gam
   407  		h22 *= gam
   408  	}
   409  
   410  	switch p.Flag {
   411  	case blas.Diagonal:
   412  		p.H = [4]float64{0: h11, 3: h22}
   413  	case blas.OffDiagonal:
   414  		p.H = [4]float64{1: h21, 2: h12}
   415  	case blas.Rescaling:
   416  		p.H = [4]float64{h11, h21, h12, h22}
   417  	default:
   418  		panic(badFlag)
   419  	}
   420  
   421  	return p, d1, d2, x1
   422  }
   423  
   424  // Drot applies a plane transformation.
   425  //  x[i] = c * x[i] + s * y[i]
   426  //  y[i] = c * y[i] - s * x[i]
   427  func (Implementation) Drot(n int, x []float64, incX int, y []float64, incY int, c float64, s float64) {
   428  	if incX == 0 {
   429  		panic(zeroIncX)
   430  	}
   431  	if incY == 0 {
   432  		panic(zeroIncY)
   433  	}
   434  	if n < 1 {
   435  		if n == 0 {
   436  			return
   437  		}
   438  		panic(nLT0)
   439  	}
   440  	if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
   441  		panic(shortX)
   442  	}
   443  	if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
   444  		panic(shortY)
   445  	}
   446  	if incX == 1 && incY == 1 {
   447  		x = x[:n]
   448  		for i, vx := range x {
   449  			vy := y[i]
   450  			x[i], y[i] = c*vx+s*vy, c*vy-s*vx
   451  		}
   452  		return
   453  	}
   454  	var ix, iy int
   455  	if incX < 0 {
   456  		ix = (-n + 1) * incX
   457  	}
   458  	if incY < 0 {
   459  		iy = (-n + 1) * incY
   460  	}
   461  	for i := 0; i < n; i++ {
   462  		vx := x[ix]
   463  		vy := y[iy]
   464  		x[ix], y[iy] = c*vx+s*vy, c*vy-s*vx
   465  		ix += incX
   466  		iy += incY
   467  	}
   468  }
   469  
   470  // Drotm applies the modified Givens rotation to the 2×n matrix.
   471  func (Implementation) Drotm(n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams) {
   472  	if incX == 0 {
   473  		panic(zeroIncX)
   474  	}
   475  	if incY == 0 {
   476  		panic(zeroIncY)
   477  	}
   478  	if n <= 0 {
   479  		if n == 0 {
   480  			return
   481  		}
   482  		panic(nLT0)
   483  	}
   484  	if (incX > 0 && len(x) <= (n-1)*incX) || (incX < 0 && len(x) <= (1-n)*incX) {
   485  		panic(shortX)
   486  	}
   487  	if (incY > 0 && len(y) <= (n-1)*incY) || (incY < 0 && len(y) <= (1-n)*incY) {
   488  		panic(shortY)
   489  	}
   490  
   491  	if p.Flag == blas.Identity {
   492  		return
   493  	}
   494  
   495  	switch p.Flag {
   496  	case blas.Rescaling:
   497  		h11 := p.H[0]
   498  		h12 := p.H[2]
   499  		h21 := p.H[1]
   500  		h22 := p.H[3]
   501  		if incX == 1 && incY == 1 {
   502  			x = x[:n]
   503  			for i, vx := range x {
   504  				vy := y[i]
   505  				x[i], y[i] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(vy*h22)
   506  			}
   507  			return
   508  		}
   509  		var ix, iy int
   510  		if incX < 0 {
   511  			ix = (-n + 1) * incX
   512  		}
   513  		if incY < 0 {
   514  			iy = (-n + 1) * incY
   515  		}
   516  		for i := 0; i < n; i++ {
   517  			vx := x[ix]
   518  			vy := y[iy]
   519  			x[ix], y[iy] = float64(vx*h11)+float64(vy*h12), float64(vx*h21)+float64(vy*h22)
   520  			ix += incX
   521  			iy += incY
   522  		}
   523  	case blas.OffDiagonal:
   524  		h12 := p.H[2]
   525  		h21 := p.H[1]
   526  		if incX == 1 && incY == 1 {
   527  			x = x[:n]
   528  			for i, vx := range x {
   529  				vy := y[i]
   530  				x[i], y[i] = vx+float64(vy*h12), float64(vx*h21)+vy
   531  			}
   532  			return
   533  		}
   534  		var ix, iy int
   535  		if incX < 0 {
   536  			ix = (-n + 1) * incX
   537  		}
   538  		if incY < 0 {
   539  			iy = (-n + 1) * incY
   540  		}
   541  		for i := 0; i < n; i++ {
   542  			vx := x[ix]
   543  			vy := y[iy]
   544  			x[ix], y[iy] = vx+float64(vy*h12), float64(vx*h21)+vy
   545  			ix += incX
   546  			iy += incY
   547  		}
   548  	case blas.Diagonal:
   549  		h11 := p.H[0]
   550  		h22 := p.H[3]
   551  		if incX == 1 && incY == 1 {
   552  			x = x[:n]
   553  			for i, vx := range x {
   554  				vy := y[i]
   555  				x[i], y[i] = float64(vx*h11)+vy, -vx+float64(vy*h22)
   556  			}
   557  			return
   558  		}
   559  		var ix, iy int
   560  		if incX < 0 {
   561  			ix = (-n + 1) * incX
   562  		}
   563  		if incY < 0 {
   564  			iy = (-n + 1) * incY
   565  		}
   566  		for i := 0; i < n; i++ {
   567  			vx := x[ix]
   568  			vy := y[iy]
   569  			x[ix], y[iy] = float64(vx*h11)+vy, -vx+float64(vy*h22)
   570  			ix += incX
   571  			iy += incY
   572  		}
   573  	}
   574  }
   575  
   576  // Dscal scales x by alpha.
   577  //  x[i] *= alpha
   578  // Dscal has no effect if incX < 0.
   579  func (Implementation) Dscal(n int, alpha float64, x []float64, incX int) {
   580  	if incX < 1 {
   581  		if incX == 0 {
   582  			panic(zeroIncX)
   583  		}
   584  		return
   585  	}
   586  	if n < 1 {
   587  		if n == 0 {
   588  			return
   589  		}
   590  		panic(nLT0)
   591  	}
   592  	if (n-1)*incX >= len(x) {
   593  		panic(shortX)
   594  	}
   595  	if alpha == 0 {
   596  		if incX == 1 {
   597  			x = x[:n]
   598  			for i := range x {
   599  				x[i] = 0
   600  			}
   601  			return
   602  		}
   603  		for ix := 0; ix < n*incX; ix += incX {
   604  			x[ix] = 0
   605  		}
   606  		return
   607  	}
   608  	if incX == 1 {
   609  		f64.ScalUnitary(alpha, x[:n])
   610  		return
   611  	}
   612  	f64.ScalInc(alpha, x, uintptr(n), uintptr(incX))
   613  }