// 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 }
// Calculate C = alpha*A*B.T + beta*C, C is M*N, A is M*P and B is N*P func MMMultTransB(C, A, B *matrix.FloatMatrix, alpha, beta float64) error { psize := int64(C.NumElements() * A.Cols()) Ar := A.FloatArray() ldA := A.LeadingIndex() Br := B.FloatArray() ldB := B.LeadingIndex() Cr := C.FloatArray() ldC := C.LeadingIndex() if nWorker <= 1 || psize <= limitOne { calgo.DMult(Cr, Ar, Br, alpha, beta, calgo.TRANSB, ldC, ldA, ldB, B.Rows(), 0, C.Cols(), 0, C.Rows(), vpLen, nB, mB) return nil } // here we have more than one worker available worker := func(cstart, cend, rstart, rend int, ready chan int) { calgo.DMult(Cr, Ar, Br, alpha, beta, calgo.TRANSB, ldC, ldA, ldB, B.Rows(), cstart, cend, rstart, rend, vpLen, nB, mB) ready <- 1 } colworks, rowworks := divideWork(C.Rows(), C.Cols(), nWorker) scheduleWork(colworks, rowworks, C.Cols(), C.Rows(), worker) //scheduleWork(colworks, rowworks, worker) return nil }
// 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 Mult0(C, A, B *matrix.FloatMatrix, alpha, beta float64, flags Flags) error { if A.Cols() != B.Rows() { return errors.New("A.cols != B.rows: size mismatch") } psize := int64(C.NumElements()) * int64(A.Cols()) Ar := A.FloatArray() ldA := A.LeadingIndex() Br := B.FloatArray() ldB := B.LeadingIndex() Cr := C.FloatArray() ldC := C.LeadingIndex() if nWorker <= 1 || psize <= limitOne { calgo.DMult0(Cr, Ar, Br, alpha, beta, calgo.Flags(flags), ldC, ldA, ldB, B.Rows(), 0, C.Cols(), 0, C.Rows(), vpLen, nB, mB) return nil } // here we have more than one worker available worker := func(cstart, cend, rstart, rend int, ready chan int) { calgo.DMult0(Cr, Ar, Br, alpha, beta, calgo.Flags(flags), ldC, ldA, ldB, B.Rows(), cstart, cend, rstart, rend, vpLen, nB, mB) ready <- 1 } colworks, rowworks := divideWork(C.Rows(), C.Cols(), nWorker) scheduleWork(colworks, rowworks, C.Cols(), C.Rows(), worker) return nil }
// Calculate C = alpha*A*B + beta*C, C is M*N, A is M*M and B is M*N func MMSymmUpper(C, A, B *matrix.FloatMatrix, alpha, beta float64) error { if A.Rows() != A.Cols() { return errors.New("A matrix not square matrix.") } psize := int64(C.NumElements() * A.Cols()) Ar := A.FloatArray() ldA := A.LeadingIndex() Br := B.FloatArray() ldB := B.LeadingIndex() Cr := C.FloatArray() ldC := C.LeadingIndex() if nWorker <= 1 || psize <= limitOne { calgo.DMultSymm(Cr, Ar, Br, alpha, beta, calgo.LEFT|calgo.UPPER, ldC, ldA, ldB, A.Cols(), 0, C.Cols(), 0, C.Rows(), vpLen, nB, mB) return nil } // here we have more than one worker available worker := func(cstart, cend, rstart, rend int, ready chan int) { calgo.DMultSymm(Cr, Ar, Br, alpha, beta, calgo.LEFT|calgo.UPPER, ldC, ldA, ldB, A.Cols(), cstart, cend, rstart, rend, vpLen, nB, mB) ready <- 1 } colworks, rowworks := divideWork(C.Rows(), C.Cols(), nWorker) scheduleWork(colworks, rowworks, C.Cols(), C.Rows(), worker) return nil }
// Generic matrix-matrix multpily. (blas.GEMM). Calculates // C = beta*C + alpha*A*B (default) // C = beta*C + alpha*A.T*B flags&TRANSA // C = beta*C + alpha*A*B.T flags&TRANSB // C = beta*C + alpha*A.T*B.T flags&(TRANSA|TRANSB) // // C is M*N, A is M*P or P*M if flags&TRANSA. B is P*N or N*P if flags&TRANSB. // func Mult(C, A, B *matrix.FloatMatrix, alpha, beta float64, flags Flags) error { var ok, empty bool // error checking must take in account flag values! ar, ac := A.Size() br, bc := B.Size() cr, cc := C.Size() switch flags & (TRANSA | TRANSB) { case TRANSA | TRANSB: empty = ac == 0 || br == 0 ok = cr == ac && cc == br && ar == bc case TRANSA: empty = ac == 0 || bc == 0 ok = cr == ac && cc == bc && ar == br case TRANSB: empty = ar == 0 || br == 0 ok = cr == ar && cc == br && ac == bc default: empty = ar == 0 || bc == 0 ok = cr == ar && cc == bc && ac == br } if empty { return nil } if !ok { return errors.New("Mult: size mismatch") } psize := int64(C.NumElements()) * int64(A.Cols()) Ar := A.FloatArray() ldA := A.LeadingIndex() Br := B.FloatArray() ldB := B.LeadingIndex() Cr := C.FloatArray() ldC := C.LeadingIndex() // matrix A, B common dimension P := A.Cols() if flags&TRANSA != 0 { P = A.Rows() } if nWorker <= 1 || psize <= limitOne { calgo.DMult(Cr, Ar, Br, alpha, beta, calgo.Flags(flags), ldC, ldA, ldB, P, 0, C.Cols(), 0, C.Rows(), vpLen, nB, mB) return nil } // here we have more than one worker available worker := func(cstart, cend, rstart, rend int, ready chan int) { calgo.DMult(Cr, Ar, Br, alpha, beta, calgo.Flags(flags), ldC, ldA, ldB, P, cstart, cend, rstart, rend, vpLen, nB, mB) ready <- 1 } colworks, rowworks := divideWork(C.Rows(), C.Cols(), nWorker) scheduleWork(colworks, rowworks, C.Cols(), C.Rows(), worker) return nil }
/* Returns x' * J * y, where J = [1, 0; 0, -I]. */ func jdot(x, y *matrix.FloatMatrix, n, offsetx, offsety int) float64 { if n <= 0 { n = x.NumElements() } a := blas.DotFloat(x, y, &la_.IOpt{"n", n - 1}, &la_.IOpt{"offsetx", offsetx + 1}, &la_.IOpt{"offsety", offsety + 1}) return x.GetIndex(offsetx)*y.GetIndex(offsety) - a }
// Symmetric matrix multiply. (blas.SYMM) // C = beta*C + alpha*A*B (default) // C = beta*C + alpha*A.T*B flags&TRANSA // C = beta*C + alpha*A*B.T flags&TRANSB // C = beta*C + alpha*A.T*B.T flags&(TRANSA|TRANSB) // // C is N*P, A is N*N symmetric matrix. B is N*P or P*N if flags&TRANSB. // func MultSym(C, A, B *matrix.FloatMatrix, alpha, beta float64, flags Flags) error { var ok, empty bool ar, ac := A.Size() br, bc := B.Size() cr, cc := C.Size() switch flags & (TRANSA | TRANSB) { case TRANSA | TRANSB: empty = ac == 0 || br == 0 ok = ar == ac && cr == ac && cc == br && ar == bc case TRANSA: empty = ac == 0 || bc == 0 ok = ar == ac && cr == ac && cc == bc && ar == br case TRANSB: empty = ar == 0 || br == 0 ok = ar == ac && cr == ar && cc == br && ac == bc default: empty = ar == 0 || bc == 0 ok = ar == ac && cr == ar && cc == bc && ac == br } if empty { return nil } if !ok { return errors.New("MultSym: size mismatch") } /* if A.Rows() != A.Cols() { return errors.New("A matrix not square matrix."); } if A.Cols() != B.Rows() { return errors.New("A.cols != B.rows: size mismatch") } */ psize := int64(C.NumElements()) * int64(A.Cols()) Ar := A.FloatArray() ldA := A.LeadingIndex() Br := B.FloatArray() ldB := B.LeadingIndex() Cr := C.FloatArray() ldC := C.LeadingIndex() if nWorker <= 1 || psize <= limitOne { calgo.DMultSymm(Cr, Ar, Br, alpha, beta, calgo.Flags(flags), ldC, ldA, ldB, A.Cols(), 0, C.Cols(), 0, C.Rows(), vpLen, nB, mB) return nil } // here we have more than one worker available worker := func(cstart, cend, rstart, rend int, ready chan int) { calgo.DMultSymm(Cr, Ar, Br, alpha, beta, calgo.Flags(flags), ldC, ldA, ldB, A.Cols(), cstart, cend, rstart, rend, vpLen, nB, mB) ready <- 1 } colworks, rowworks := divideWork(C.Rows(), C.Cols(), nWorker) scheduleWork(colworks, rowworks, C.Cols(), C.Rows(), worker) return nil }
/* Returns sqrt(x' * J * x) where J = [1, 0; 0, -I], for a vector x in a second order cone. */ func jnrm2(x *matrix.FloatMatrix, n, offset int) float64 { /*DEBUGGED*/ if n <= 0 { n = x.NumElements() } if offset < 0 { offset = 0 } a := blas.Nrm2Float(x, &la_.IOpt{"n", n - 1}, &la_.IOpt{"offset", offset + 1}) fst := x.GetIndex(offset) return math.Sqrt(fst-a) * math.Sqrt(fst+a) }
// 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()) }
// 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()) }
// 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()) }
// 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()) }
// 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()) }
func _TestPartition2D(t *testing.T) { var ATL, ATR, ABL, ABR, As matrix.FloatMatrix var A00, a01, A02, a10, a11, a12, A20, a21, A22 matrix.FloatMatrix A := matrix.FloatZeros(6, 6) As.SubMatrixOf(A, 1, 1, 4, 4) As.SetIndexes(1.0) partition2x2(&ATL, &ATR, &ABL, &ABR, &As, 0) t.Logf("ATL:\n%v\n", &ATL) for ATL.Rows() < As.Rows() { repartition2x2to3x3(&ATL, &A00, &a01, &A02, &a10, &a11, &a12, &A20, &a21, &A22, &As, 1) t.Logf("m(a12)=%d [%d], m(a11)=%d\n", a12.Cols(), a12.NumElements(), a11.NumElements()) a11.Add(1.0) a21.Add(-2.0) continue3x3to2x2(&ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, &As) } t.Logf("A:\n%v\n", A) }
// Inner product: alpha * X * Y func Dot(X, Y *matrix.FloatMatrix, alpha float64) float64 { if X == nil || Y == nil { return math.NaN() } if !isVector(X) { return math.NaN() } if !isVector(Y) { return math.NaN() } 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() } return calgo.DDot(Xr, Yr, alpha, incX, incY, X.NumElements()) }
/* * Generic rank update of diagonal matrix. * diag(D) = diag(D) + alpha * x * y.T * * Arguments: * D N element column or row vector or N-by-N matrix * * x, y N element vectors * * alpha scalar */ func MVUpdateDiag(D, x, y *matrix.FloatMatrix, alpha float64) error { var d *matrix.FloatMatrix var dvec matrix.FloatMatrix if !isVector(x) || !isVector(y) { return errors.New("x, y not vectors") } if D.Rows() > 0 && D.Cols() == D.Rows() { D.Diag(&dvec) d = &dvec } else if isVector(D) { d = D } else { return errors.New("D not a diagonal") } N := d.NumElements() for k := 0; k < N; k++ { val := d.GetIndex(k) val += x.GetIndex(k) * y.GetIndex(k) * alpha d.SetIndex(k, val) } return nil }