// Solve multiple right sides. If flags&UNIT then A diagonal is assumed to // to unit and is not referenced. (blas.TRSM) // alpha*B = A.-1*B if flags&LEFT // alpha*B = A.-T*B if flags&(LEFT|TRANS) // alpha*B = B*A.-1 if flags&RIGHT // alpha*B = B*A.-T if flags&(RIGHT|TRANS) // // Matrix A is N*N triangular matrix defined with flags bits as follow // LOWER non-unit lower triangular // LOWER|UNIT unit lower triangular // UPPER non-unit upper triangular // UPPER|UNIT unit upper triangular // // Matrix B is N*P if flags&LEFT or P*N if flags&RIGHT. // func SolveTrm(B, A *matrix.FloatMatrix, alpha float64, flags Flags) error { ok := true empty := false br, bc := B.Size() ar, ac := A.Size() switch flags & (LEFT | RIGHT) { case LEFT: empty = br == 0 ok = br == ac && ac == ar case RIGHT: empty = bc == 0 ok = bc == ar && ac == ar } if empty { return nil } if !ok { return onError("A, B size mismatch") } Ar := A.FloatArray() ldA := A.LeadingIndex() Br := B.FloatArray() ldB := B.LeadingIndex() E := bc if flags&RIGHT != 0 { E = br } // if more workers available can divide to tasks by B columns if flags&LEFT or by // B rows if flags&RIGHT. calgo.DSolveBlk(Br, Ar, alpha, calgo.Flags(flags), ldB, ldA, ac, 0, E, nB) return nil }
func solveMVTest(t *testing.T, A, X0 *matrix.FloatMatrix, flags Flags, bN, bNB int) { X1 := X0.Copy() uplo := linalg.OptUpper diag := linalg.OptNonUnit if flags&LOWER != 0 { uplo = linalg.OptLower } if flags&UNIT != 0 { diag = linalg.OptUnit } blas.TrsvFloat(A, X0, uplo, diag) Ar := A.FloatArray() Xr := X1.FloatArray() if bN == bNB { DSolveUnblkMV(Xr, Ar, flags, 1, A.LeadingIndex(), bN) } else { DSolveBlkMV(Xr, Ar, flags, 1, A.LeadingIndex(), bN, bNB) } ok := X1.AllClose(X0) t.Logf("X1 == X0: %v\n", ok) if !ok && bN < 8 { t.Logf("A=\n%v\n", A) t.Logf("X0=\n%v\n", X0) t.Logf("blas: X0\n%v\n", X0) t.Logf("X1:\n%v\n", X1) } }
func trmvTest(t *testing.T, A *matrix.FloatMatrix, flags Flags, nb int) bool { N := A.Cols() //S := 0 //E := A.Cols() X0 := matrix.FloatWithValue(A.Rows(), 1, 2.0) X1 := X0.Copy() trans := linalg.OptNoTrans if flags&TRANS != 0 { trans = linalg.OptTrans } diag := linalg.OptNonUnit if flags&UNIT != 0 { diag = linalg.OptUnit } uplo := linalg.OptUpper if flags&LOWER != 0 { uplo = linalg.OptLower } blas.TrmvFloat(A, X0, uplo, diag, trans) Ar := A.FloatArray() Xr := X1.FloatArray() if nb == 0 { DTrimvUnblkMV(Xr, Ar, flags, 1, A.LeadingIndex(), N) } result := X0.AllClose(X1) t.Logf(" X0 == X1: %v\n", result) if !result && A.Rows() < 8 { t.Logf(" BLAS TRMV X0:\n%v\n", X0) t.Logf(" DTrmv X1:\n%v\n", X1) } return result }
// See function Trsm. func TrsmFloat(A, B *matrix.FloatMatrix, alpha float64, opts ...linalg.Option) (err error) { params, e := linalg.GetParameters(opts...) if e != nil { err = e return } ind := linalg.GetIndexOpts(opts...) err = check_level3_func(ind, ftrsm, A, B, nil, params) if err != nil { return } if ind.N == 0 || ind.M == 0 { return } Aa := A.FloatArray() Ba := B.FloatArray() uplo := linalg.ParamString(params.Uplo) transA := linalg.ParamString(params.TransA) side := linalg.ParamString(params.Side) diag := linalg.ParamString(params.Diag) dtrsm(side, uplo, transA, diag, ind.M, ind.N, alpha, Aa[ind.OffsetA:], ind.LDa, Ba[ind.OffsetB:], ind.LDb) return }
func syrkTest(t *testing.T, C, A *matrix.FloatMatrix, flags Flags, vlen, nb int) bool { //var B0 *matrix.FloatMatrix P := A.Cols() S := 0 E := C.Rows() C0 := C.Copy() trans := linalg.OptNoTrans if flags&TRANSA != 0 { trans = linalg.OptTrans P = A.Rows() } uplo := linalg.OptUpper if flags&LOWER != 0 { uplo = linalg.OptLower } blas.SyrkFloat(A, C0, 1.0, 1.0, uplo, trans) if A.Rows() < 8 { //t.Logf("..A\n%v\n", A) t.Logf(" BLAS C0:\n%v\n", C0) } Ar := A.FloatArray() Cr := C.FloatArray() DSymmRankBlk(Cr, Ar, 1.0, 1.0, flags, C.LeadingIndex(), A.LeadingIndex(), P, S, E, vlen, nb) result := C0.AllClose(C) t.Logf(" C0 == C: %v\n", result) if A.Rows() < 8 { t.Logf(" DMRank C:\n%v\n", C) } return result }
// See function Syrk. func SyrkFloat(A, C *matrix.FloatMatrix, alpha, beta float64, opts ...linalg.Option) (err error) { params, e := linalg.GetParameters(opts...) if e != nil { err = e return } ind := linalg.GetIndexOpts(opts...) err = check_level3_func(ind, fsyrk, A, nil, C, params) if e != nil || err != nil { return } if ind.N == 0 { return } Aa := A.FloatArray() Ca := C.FloatArray() uplo := linalg.ParamString(params.Uplo) trans := linalg.ParamString(params.Trans) //diag := linalg.ParamString(params.Diag) dsyrk(uplo, trans, ind.N, ind.K, alpha, Aa[ind.OffsetA:], ind.LDa, beta, Ca[ind.OffsetC:], ind.LDc) return }
// Swap X and Y. func Swap(X, Y *matrix.FloatMatrix) { if X == nil || Y == nil { return } if X.NumElements() == 0 || Y.NumElements() == 0 { return } if !isVector(X) { return } if !isVector(Y) { return } Xr := X.FloatArray() incX := 1 if X.Cols() != 1 { // Row vector incX = X.LeadingIndex() } Yr := Y.FloatArray() incY := 1 if Y.Cols() != 1 { // Row vector incY = Y.LeadingIndex() } calgo.DSwap(Xr, Yr, incX, incY, X.NumElements()) }
// Y := alpha * X + Y func Axpy(Y, X *matrix.FloatMatrix, alpha float64) { if X == nil || Y == nil { return } if !isVector(X) { return } if !isVector(Y) { return } Xr := X.FloatArray() incX := 1 if X.Cols() != 1 { // Row vector incX = X.LeadingIndex() } Yr := Y.FloatArray() incY := 1 if Y.Cols() != 1 { // Row vector incY = Y.LeadingIndex() } calgo.DAxpy(Xr, Yr, alpha, incX, incY, X.NumElements()) return }
func sinv(x, y *matrix.FloatMatrix, dims *sets.DimensionSet, mnl int) (err error) { /*DEBUGGED*/ err = nil // For the nonlinear and 'l' blocks: // // yk o\ xk = yk .\ xk. ind := mnl + dims.At("l")[0] blas.Tbsv(y, x, &la_.IOpt{"n", ind}, &la_.IOpt{"k", 0}, &la_.IOpt{"ldA", 1}) // For the 'q' blocks: // // [ l0 -l1' ] // yk o\ xk = 1/a^2 * [ ] * xk // [ -l1 (a*I + l1*l1')/l0 ] // // where yk = (l0, l1) and a = l0^2 - l1'*l1. for _, m := range dims.At("q") { aa := blas.Nrm2Float(y, &la_.IOpt{"n", m - 1}, &la_.IOpt{"offset", ind + 1}) ee := y.GetIndex(ind) aa = (ee + aa) * (ee - aa) cc := x.GetIndex(ind) dd := blas.DotFloat(x, y, &la_.IOpt{"n", m - 1}, &la_.IOpt{"offsetx", ind + 1}, &la_.IOpt{"offsety", ind + 1}) x.SetIndex(ind, cc*ee-dd) blas.ScalFloat(x, aa/ee, &la_.IOpt{"n", m - 1}, &la_.IOpt{"offset", ind + 1}) blas.AxpyFloat(y, x, dd/ee-cc, &la_.IOpt{"n", m - 1}, &la_.IOpt{"offsetx", ind + 1}, &la_.IOpt{"offsety", ind + 1}) blas.ScalFloat(x, 1.0/aa, &la_.IOpt{"n", m}, &la_.IOpt{"offset", ind}) ind += m } // For the 's' blocks: // // yk o\ xk = xk ./ gamma // // where gammaij = .5 * (yk_i + yk_j). ind2 := ind for _, m := range dims.At("s") { for j := 0; j < m; j++ { u := matrix.FloatVector(y.FloatArray()[ind2+j : ind2+m]) u.Add(y.GetIndex(ind2 + j)) u.Scale(0.5) blas.Tbsv(u, x, &la_.IOpt{"n", m - j}, &la_.IOpt{"k", 0}, &la_.IOpt{"lda", 1}, &la_.IOpt{"offsetx", ind + j*(m+1)}) } ind += m * m ind2 += m } return }
// Returns min {t | x + t*e >= 0}, where e is defined as follows // // - For the nonlinear and 'l' blocks: e is the vector of ones. // - For the 'q' blocks: e is the first unit vector. // - For the 's' blocks: e is the identity matrix. // // When called with the argument sigma, also returns the eigenvalues // (in sigma) and the eigenvectors (in x) of the 's' components of x. func maxStep(x *matrix.FloatMatrix, dims *sets.DimensionSet, mnl int, sigma *matrix.FloatMatrix) (rval float64, err error) { /*DEBUGGED*/ rval = 0.0 err = nil t := make([]float64, 0, 10) ind := mnl + dims.Sum("l") if ind > 0 { t = append(t, -minvec(x.FloatArray()[:ind])) } for _, m := range dims.At("q") { if m > 0 { v := blas.Nrm2Float(x, &la_.IOpt{"offset", ind + 1}, &la_.IOpt{"n", m - 1}) v -= x.GetIndex(ind) t = append(t, v) } ind += m } //var Q *matrix.FloatMatrix //var w *matrix.FloatMatrix ind2 := 0 //if sigma == nil && len(dims.At("s")) > 0 { // mx := dims.Max("s") // Q = matrix.FloatZeros(mx, mx) // w = matrix.FloatZeros(mx, 1) //} for _, m := range dims.At("s") { if sigma == nil { Q := matrix.FloatZeros(m, m) w := matrix.FloatZeros(m, 1) blas.Copy(x, Q, &la_.IOpt{"offsetx", ind}, &la_.IOpt{"n", m * m}) err = lapack.SyevrFloat(Q, w, nil, 0.0, nil, []int{1, 1}, la_.OptRangeInt, &la_.IOpt{"n", m}, &la_.IOpt{"lda", m}) if m > 0 && err == nil { t = append(t, -w.GetIndex(0)) } } else { err = lapack.SyevdFloat(x, sigma, la_.OptJobZValue, &la_.IOpt{"n", m}, &la_.IOpt{"lda", m}, &la_.IOpt{"offseta", ind}, &la_.IOpt{"offsetw", ind2}) if m > 0 { t = append(t, -sigma.GetIndex(ind2)) } } ind += m * m ind2 += m } if len(t) > 0 { rval = maxvec(t) } return }
// See function Scal. func ScalFloat(X *matrix.FloatMatrix, alpha float64, opts ...linalg.Option) (err error) { ind := linalg.GetIndexOpts(opts...) err = check_level1_func(ind, fscal, X, nil) if err != nil { return } if ind.Nx == 0 { return } Xa := X.FloatArray() dscal(ind.Nx, alpha, Xa[ind.OffsetX:], ind.IncX) return }
// A = alpha*A + beta*B // A = alpha*A + beta*B.T if flags&TRANSB func ScalePlus(A, B *matrix.FloatMatrix, alpha, beta float64, flags Flags) error { Ar := A.FloatArray() ldA := A.LeadingIndex() Br := B.FloatArray() ldB := B.LeadingIndex() S := 0 L := A.Cols() R := 0 E := A.Rows() calgo.DScalePlus(Ar, Br, alpha, beta, calgo.Flags(flags), ldA, ldB, S, L, R, E) return nil }
func trmmTest(t *testing.T, A *matrix.FloatMatrix, flags Flags, nb int) bool { var B0 *matrix.FloatMatrix N := A.Cols() S := 0 E := A.Cols() side := linalg.OptLeft if flags&RIGHT != 0 { B0 = matrix.FloatWithValue(2, A.Rows(), 2.0) side = linalg.OptRight E = B0.Rows() } else { B0 = matrix.FloatWithValue(A.Rows(), 2, 2.0) E = B0.Cols() } B1 := B0.Copy() trans := linalg.OptNoTrans if flags&TRANSA != 0 { trans = linalg.OptTransA } diag := linalg.OptNonUnit if flags&UNIT != 0 { diag = linalg.OptUnit } uplo := linalg.OptUpper if flags&LOWER != 0 { uplo = linalg.OptLower } blas.TrmmFloat(A, B0, 1.0, uplo, diag, trans, side) if A.Rows() < 8 { //t.Logf("..A\n%v\n", A) t.Logf(" BLAS B0:\n%v\n", B0) } Ar := A.FloatArray() Br := B1.FloatArray() if nb != 0 { DTrmmBlk(Br, Ar, 1.0, flags, B1.LeadingIndex(), A.LeadingIndex(), N, S, E, nb) } else { DTrmmUnblk(Br, Ar, 1.0, flags, B1.LeadingIndex(), A.LeadingIndex(), N, S, E, 0) } result := B0.AllClose(B1) t.Logf(" B0 == B1: %v\n", result) if A.Rows() < 8 { t.Logf(" DTrmm B1:\n%v\n", B1) } return result }
// See function Copy. func CopyFloat(X, Y *matrix.FloatMatrix, opts ...linalg.Option) (err error) { ind := linalg.GetIndexOpts(opts...) err = check_level1_func(ind, fcopy, X, Y) if err != nil { return } if ind.Nx == 0 { return } Xa := X.FloatArray() Ya := Y.FloatArray() dcopy(ind.Nx, Xa[ind.OffsetX:], ind.IncX, Ya[ind.OffsetY:], ind.IncY) return }
// index of max |x| func IAMax(X *matrix.FloatMatrix) int { if X == nil { return -1 } if !isVector(X) { return -1 } Xr := X.FloatArray() incX := 1 if X.Cols() != 1 { // Row vector incX = X.LeadingIndex() } return calgo.DIAMax(Xr, incX, X.NumElements()) }
// See function Asum. func AsumFloat(X *matrix.FloatMatrix, opts ...linalg.Option) (v float64) { v = math.NaN() ind := linalg.GetIndexOpts(opts...) err := check_level1_func(ind, fasum, X, nil) if err != nil { return } if ind.Nx == 0 { v = 0.0 return } Xa := X.FloatArray() v = dasum(ind.Nx, Xa[ind.OffsetX:], ind.IncX) return }
// sum(|x|) func ASum(X *matrix.FloatMatrix) float64 { if X == nil { return math.NaN() } if !isVector(X) { return math.NaN() } Xr := X.FloatArray() incX := 1 if X.Cols() != 1 { // Row vector incX = X.LeadingIndex() } return calgo.DAsum(Xr, incX, X.NumElements()) }
// Scaling with scalar: X = alpha * X func Scale(X *matrix.FloatMatrix, alpha float64) { if X == nil || X.NumElements() == 0 { return } if !isVector(X) { return } Xr := X.FloatArray() incX := 1 if X.Cols() != 1 { // Row vector incX = X.LeadingIndex() } calgo.DScal(Xr, alpha, incX, X.NumElements()) }
// See functin Dot. func DotFloat(X, Y *matrix.FloatMatrix, opts ...linalg.Option) (v float64) { v = math.NaN() ind := linalg.GetIndexOpts(opts...) err := check_level1_func(ind, fdot, X, Y) if err != nil { return } if ind.Nx == 0 { v = 0.0 return } Xa := X.FloatArray() Ya := Y.FloatArray() v = ddot(ind.Nx, Xa[ind.OffsetX:], ind.IncX, Ya[ind.OffsetY:], ind.IncY) return }
// A = A + alpha*X*Y.T; A is N*N symmetric, X is row or column vector of length N. func MVSymmUpdateUpper(A, X *matrix.FloatMatrix, alpha float64) error { if X.Rows() != 1 && X.Cols() != 1 { return errors.New("X not a vector.") } Ar := A.FloatArray() ldA := A.LeadingIndex() Xr := X.FloatArray() incX := 1 if X.Rows() == 1 { // row vector incX = X.LeadingIndex() } // NOTE: This could diveded to parallel tasks per column. calgo.DSymmRankMV(Ar, Xr, alpha, calgo.UPPER, ldA, incX, 0, A.Cols(), 0) return nil }
// Convert triangular band matrix S to new matrix R with elements stored in // triangular-band-packed mode. Returned matrix has dimensions R.Rows() == K+1 // and R.Cols() == S.Cols(). Parameter flags must have either UPPER or LOWER bit set. func BandedTrmMatrix(S *matrix.FloatMatrix, K int, flags Flags) (R *matrix.FloatMatrix) { if S.Rows() != S.Cols() { return nil } M := S.Rows() N := S.Cols() R = nil Sr := S.FloatArray() if flags&UPPER != 0 { // Upper triangular matrix R = matrix.FloatZeros(K+1, M) Rr := R.FloatArray() for j := 0; j < N; j++ { m := K + 1 - j // is = max(0, j-K) is := j - K if is < 0 { is = 0 } for i := is; i <= j; i++ { Rr[j*(K+1)+m+i-1] = Sr[j*M+i] } } } else if flags&LOWER != 0 { // Lower triangular matrix R = matrix.FloatZeros(K+1, M) Rr := R.FloatArray() for j := 0; j < N; j++ { m := 1 - j // ie = min(N, j+K+1) ie := j + K + 1 if ie >= N { ie = N } for i := j; i < ie; i++ { Rr[j*(K+1)+m+i-1] = Sr[j*M+i] } } } return }
// Tridiagonal multiplication; X = A*X func MVMultTrm(X, A *matrix.FloatMatrix, flags Flags) error { if A.Rows() == 0 || A.Cols() == 0 { return nil } if X.Rows() != 1 && X.Cols() != 1 { return errors.New("X not a vector.") } Ar := A.FloatArray() ldA := A.LeadingIndex() Xr := X.FloatArray() incX := 1 if X.Rows() == 1 { // row vector incX = X.LeadingIndex() } calgo.DTrimvUnblkMV(Xr, Ar, calgo.Flags(flags), incX, ldA, A.Cols()) return nil }
// Rank update for symmetric lower or upper matrix (blas.SYRK) // C = beta*C + alpha*A*A.T + alpha*A.T*A func RankUpdateSym(C, A *matrix.FloatMatrix, alpha, beta float64, flags Flags) error { if C.Rows() != C.Cols() { return onError("C not a square matrix") } Ar := A.FloatArray() ldA := A.LeadingIndex() Cr := C.FloatArray() ldC := C.LeadingIndex() S := 0 E := C.Rows() P := A.Cols() if flags&TRANSA != 0 { P = A.Rows() } // if more workers available C can be divided to blocks [S:E, S:E] along diagonal // and updated in separate tasks. calgo.DSymmRankBlk(Cr, Ar, alpha, beta, calgo.Flags(flags), ldC, ldA, P, S, E, vpLen, nB) return nil }
// See function Syr. func SyrFloat(X, A *matrix.FloatMatrix, alpha float64, opts ...linalg.Option) (err error) { var params *linalg.Parameters params, err = linalg.GetParameters(opts...) if err != nil { return } ind := linalg.GetIndexOpts(opts...) err = check_level2_func(ind, fsyr, X, nil, A, params) if err != nil { return } if ind.N == 0 { return } Xa := X.FloatArray() Aa := A.FloatArray() uplo := linalg.ParamString(params.Uplo) dsyr(uplo, ind.N, alpha, Xa[ind.OffsetX:], ind.IncX, Aa[ind.OffsetA:], ind.LDa) return }
// See function Gbmv. func GbmvFloat(A, X, Y *matrix.FloatMatrix, alpha, beta float64, opts ...linalg.Option) (err error) { var params *linalg.Parameters params, err = linalg.GetParameters(opts...) if err != nil { return } ind := linalg.GetIndexOpts(opts...) err = check_level2_func(ind, fgbmv, X, Y, A, params) if err != nil { return } if ind.M == 0 && ind.N == 0 { return } Xa := X.FloatArray() Ya := Y.FloatArray() Aa := A.FloatArray() if params.Trans == linalg.PNoTrans && ind.N == 0 { dscal(ind.M, beta, Ya[ind.OffsetY:], ind.IncY) } else if params.Trans == linalg.PTrans && ind.M == 0 { dscal(ind.N, beta, Ya[ind.OffsetY:], ind.IncY) } else { trans := linalg.ParamString(params.Trans) dgbmv(trans, ind.M, ind.N, ind.Kl, ind.Ku, alpha, Aa[ind.OffsetA:], ind.LDa, Xa[ind.OffsetX:], ind.IncX, beta, Ya[ind.OffsetY:], ind.IncY) } return }
// See function Gemm. func GemmFloat(A, B, C *matrix.FloatMatrix, alpha, beta float64, opts ...linalg.Option) (err error) { params, e := linalg.GetParameters(opts...) if e != nil { err = e return } ind := linalg.GetIndexOpts(opts...) err = check_level3_func(ind, fgemm, A, B, C, params) if err != nil { return } if ind.M == 0 || ind.N == 0 { return } Aa := A.FloatArray() Ba := B.FloatArray() Ca := C.FloatArray() transB := linalg.ParamString(params.TransB) transA := linalg.ParamString(params.TransA) //diag := linalg.ParamString(params.Diag) dgemm(transA, transB, ind.M, ind.N, ind.K, alpha, Aa[ind.OffsetA:], ind.LDa, Ba[ind.OffsetB:], ind.LDb, beta, Ca[ind.OffsetC:], ind.LDc) return }
// See function Symm. func SymmFloat(A, B, C *matrix.FloatMatrix, alpha, beta float64, opts ...linalg.Option) (err error) { params, e := linalg.GetParameters(opts...) if e != nil { err = e return } ind := linalg.GetIndexOpts(opts...) err = check_level3_func(ind, fsymm, A, B, C, params) if err != nil { return } if ind.M == 0 || ind.N == 0 { return } Aa := A.FloatArray() Ba := B.FloatArray() Ca := C.FloatArray() uplo := linalg.ParamString(params.Uplo) side := linalg.ParamString(params.Side) dsymm(side, uplo, ind.M, ind.N, alpha, Aa[ind.OffsetA:], ind.LDa, Ba[ind.OffsetB:], ind.LDb, beta, Ca[ind.OffsetC:], ind.LDc) return }
// Matrix-vector rank update A = A + alpha*X*Y.T // A is M*N generic matrix, // X is row or column vector of length M // Y is row or column vector of legth N. func MVRankUpdate(A, X, Y *matrix.FloatMatrix, alpha float64) error { if A.Rows() == 0 || A.Cols() == 0 { return nil } if Y.Rows() != 1 && Y.Cols() != 1 { return errors.New("Y not a vector.") } if X.Rows() != 1 && X.Cols() != 1 { return errors.New("X not a vector.") } Ar := A.FloatArray() ldA := A.LeadingIndex() Yr := Y.FloatArray() incY := 1 if Y.Rows() == 1 { // row vector incY = Y.LeadingIndex() } Xr := X.FloatArray() incX := 1 if X.Rows() == 1 { // row vector incX = X.LeadingIndex() } // NOTE: This could diveded to parallel tasks like matrix-matrix multiplication calgo.DRankMV(Ar, Xr, Yr, alpha, ldA, incX, incY, 0, A.Cols(), 0, A.Rows(), 0, 0) return nil }
// Compute // Y = alpha*A*X + beta*Y // Y = alpha*A.T*X + beta*Y ; flags = TRANSA // // A is M*N or N*M generic matrix, // X is row or column vector of length N // Y is row or column vector of legth M. // // MVMult is vector orientation agnostic. It does not matter if Y, X are row or // column vectors, they are always handled as if they were column vectors. func MVMult(Y, A, X *matrix.FloatMatrix, alpha, beta float64, flags Flags) error { if A.Rows() == 0 || A.Cols() == 0 { return nil } if Y.Rows() != 1 && Y.Cols() != 1 { return errors.New("Y not a vector.") } if X.Rows() != 1 && X.Cols() != 1 { return errors.New("X not a vector.") } Ar := A.FloatArray() ldA := A.LeadingIndex() Yr := Y.FloatArray() incY := 1 lenY := Y.NumElements() if Y.Rows() == 1 { // row vector incY = Y.LeadingIndex() } Xr := X.FloatArray() incX := 1 lenX := X.NumElements() if X.Rows() == 1 { // row vector incX = X.LeadingIndex() } // NOTE: This could diveded to parallel tasks by rows. calgo.DMultMV(Yr, Ar, Xr, alpha, beta, calgo.Flags(flags), incY, ldA, incX, 0, lenX, 0, lenY, vpLen, mB) return nil }
// Add inner product: Z[index] = beta*Z[index] + alpha * X * Y func AddDot(Z, X, Y *matrix.FloatMatrix, alpha, beta float64, index int) { if X == nil || Y == nil { return } if X.NumElements() == 0 || Y.NumElements() == 0 { return } if !isVector(X) { return } if !isVector(Y) { return } Xr := X.FloatArray() incX := 1 if X.Cols() != 1 { // Row vector incX = X.LeadingIndex() } Yr := Y.FloatArray() incY := 1 if Y.Cols() != 1 { // Row vector incY = Y.LeadingIndex() } Zr := Z.FloatArray() incZ := 1 if Z.Cols() != 1 { // Row vector incZ = Z.LeadingIndex() } calgo.DDotSum(Zr[incZ*index:], Xr, Yr, alpha, beta, incZ, incX, incY, X.NumElements()) }