Beispiel #1
0
/*
 * Compute
 *   B = B*diag(D)      flags & RIGHT == true
 *   B = diag(D)*B      flags & LEFT  == true
 *
 * If flags is LEFT (RIGHT) then element-wise multiplies columns (rows) of B with vector D.
 *
 * Arguments
 *   B     M-by-N matrix if flags&RIGHT == true or N-by-M matrix if flags&LEFT == true
 *
 *   D     N element column or row vector or N-by-N matrix
 *
 *   flags Indicator bits, LEFT or RIGHT
 */
func MultDiag(B, D *cmat.FloatMatrix, flags int, confs ...*gomas.Config) *gomas.Error {
	var c, d0 cmat.FloatMatrix
	var d *cmat.FloatMatrix

	conf := gomas.CurrentConf(confs...)
	d = D
	if !D.IsVector() {
		d0.Diag(D)
		d = &d0
	}
	dn := d.Len()
	br, bc := B.Size()
	switch flags & (gomas.LEFT | gomas.RIGHT) {
	case gomas.LEFT:
		if br != dn {
			return gomas.NewError(gomas.ESIZE, "MultDiag")
		}
		// scale rows; for each column element-wise multiply with D-vector
		for k := 0; k < dn; k++ {
			c.Row(B, k)
			blasd.Scale(&c, d.GetAt(k), conf)
		}
	case gomas.RIGHT:
		if bc != dn {
			return gomas.NewError(gomas.ESIZE, "MultDiag")
		}
		// scale columns
		for k := 0; k < dn; k++ {
			c.Column(B, k)
			blasd.Scale(&c, d.GetAt(k), conf)
		}
	}
	return nil
}
Beispiel #2
0
/*
 * Generates the real orthogonal matrix Q which is defined as the product of K elementary
 * reflectors of order N embedded in matrix A as returned by TRDReduce().
 *
 *   A     On entry tridiagonal reduction as returned by TRDReduce().
 *         On exit the orthogonal matrix Q.
 *
 *  tau    Scalar coefficients of elementary reflectors.
 *
 *  W      Workspace
 *
 *  K      Number of reflectors , 0 < K < N
 *
 *  flags  LOWER or UPPER
 *
 *  confs  Optional blocking configuration
 *
 * If flags has UPPER set then
 *    Q = H(K)...H(1)H(0) where 0 < K < N-1
 *
 * If flags has LOWR set then
 *    Q = H(0)H(1)...H(K) where 0 < K < N-1
 */
func TRDBuild(A, tau, W *cmat.FloatMatrix, K, flags int, confs ...*gomas.Config) *gomas.Error {
	var err *gomas.Error = nil
	var Qh, tauh cmat.FloatMatrix
	var s, d cmat.FloatMatrix

	if K > m(A)-1 {
		K = m(A) - 1
	}

	switch flags & (gomas.LOWER | gomas.UPPER) {
	case gomas.LOWER:
		// Shift Q matrix embedded in A right and fill first column
		// unit column vector
		for j := m(A) - 1; j > 0; j-- {
			s.SubMatrix(A, j, j-1, m(A)-j, 1)
			d.SubMatrix(A, j, j, m(A)-j, 1)
			blasd.Copy(&d, &s)
			A.Set(0, j, 0.0)
		}
		// zero first column and set first entry to one
		d.Column(A, 0)
		blasd.Scale(&d, 0.0)
		d.Set(0, 0, 1.0)

		Qh.SubMatrix(A, 1, 1, m(A)-1, m(A)-1)
		tauh.SubMatrix(tau, 0, 0, m(A)-1, 1)
		err = QRBuild(&Qh, &tauh, W, K, confs...)

	case gomas.UPPER:
		// Shift Q matrix embedded in A left and fill last column
		// unit column vector
		for j := 1; j < m(A); j++ {
			s.SubMatrix(A, 0, j, j, 1)
			d.SubMatrix(A, 0, j-1, j, 1)
			blasd.Copy(&d, &s)
			A.Set(-1, j-1, 0.0)
		}
		// zero last column and set last entry to one
		d.Column(A, m(A)-1)
		blasd.Scale(&d, 0.0)
		d.Set(-1, 0, 1.0)

		Qh.SubMatrix(A, 0, 0, m(A)-1, m(A)-1)
		tauh.SubMatrix(tau, 0, 0, m(A)-1, 1)
		err = QLBuild(&Qh, &tauh, W, K, confs...)
	}
	if err != nil {
		err.Update("TRDBuild")
	}
	return err
}
Beispiel #3
0
/*
 * Unblocked code for generating M by N matrix Q with orthogonal columns which
 * are defined as the last N columns of the product of K first elementary
 * reflectors.
 *
 * Parameter nk is last nk elementary reflectors that are not used in computing
 * the matrix Q. Parameter mk length of the first unused elementary reflectors
 * First nk columns are zeroed and subdiagonal mk-nk is set to unit.
 *
 * Compatible with lapack.DORG2L subroutine.
 */
func unblkBuildQL(A, Tvec, W *cmat.FloatMatrix, mk, nk int, mayClear bool) {
	var ATL, ATR, ABL, ABR cmat.FloatMatrix
	var A00, a01, a10, a11, a21, A22 cmat.FloatMatrix
	var tT, tB cmat.FloatMatrix
	var t0, tau1, t2, w12, D cmat.FloatMatrix

	// (mk, nk) = (rows, columns) of upper left partition
	util.Partition2x2(
		&ATL, &ATR,
		&ABL, &ABR, A, mk, nk, util.PTOPLEFT)
	util.Partition2x1(
		&tT,
		&tB, Tvec, nk, util.PTOP)

	// zero the left side
	if nk > 0 && mayClear {
		blasd.Scale(&ABL, 0.0)
		blasd.Scale(&ATL, 0.0)
		D.Diag(&ATL, nk-mk)
		blasd.Add(&D, 1.0)
	}

	for m(&ABR) > 0 && n(&ABR) > 0 {
		util.Repartition2x2to3x3(&ATL,
			&A00, &a01, nil,
			&a10, &a11, nil,
			nil, &a21, &A22, A, 1, util.PBOTTOMRIGHT)
		util.Repartition2x1to3x1(&tT,
			&t0,
			&tau1,
			&t2, Tvec, 1, util.PBOTTOM)
		// ------------------------------------------------------
		w12.SubMatrix(W, 0, 0, a10.Len(), 1)
		applyHouseholder2x1(&tau1, &a01, &a10, &A00, &w12, gomas.LEFT)

		blasd.Scale(&a01, -tau1.Get(0, 0))
		a11.Set(0, 0, 1.0-tau1.Get(0, 0))

		// zero bottom elements
		blasd.Scale(&a21, 0.0)
		// ------------------------------------------------------
		util.Continue3x3to2x2(
			&ATL, &ATR,
			&ABL, &ABR, &A00, &a11, &A22, A, util.PBOTTOMRIGHT)
		util.Continue3x1to2x1(
			&tT,
			&tB, &t0, &tau1, Tvec, util.PBOTTOM)
	}
}
Beispiel #4
0
/*
 * Unblocked code for generating M by N matrix Q with orthogonal columns which
 * are defined as the first N columns of the product of K first elementary
 * reflectors.
 *
 * Parameters nk = n(A)-K, mk = m(A)-K define the initial partitioning of
 * matrix A.
 *
 *  Q = H(k)H(k-1)...H(1)  , 0 < k <= M, where H(i) = I - tau*v*v.T
 *
 * Computation is ordered as H(k)*H(k-1)...*H(1)*I ie. from bottom to top.
 *
 * If k < M rows k+1:M are cleared and diagonal entries [k+1:M,k+1:M] are
 * set to unit. Then the matrix Q is generated by right multiplying elements below
 * of i'th elementary reflector H(i).
 *
 * Compatible to lapack.xORG2L subroutine.
 */
func unblkBuildLQ(A, Tvec, W *cmat.FloatMatrix, mk, nk int, mayClear bool) {
	var ATL, ATR, ABL, ABR cmat.FloatMatrix
	var A00, a10, a11, a12, a21, A22 cmat.FloatMatrix
	var tT, tB cmat.FloatMatrix
	var t0, tau1, t2, w12, D cmat.FloatMatrix

	util.Partition2x2(
		&ATL, &ATR,
		&ABL, &ABR, A, mk, nk, util.PBOTTOMRIGHT)
	util.Partition2x1(
		&tT,
		&tB, Tvec, mk, util.PBOTTOM)

	// zero the bottom part
	if mk > 0 && mayClear {
		blasd.Scale(&ABL, 0.0)
		blasd.Scale(&ABR, 0.0)
		D.Diag(&ABR)
		blasd.Add(&D, 1.0)
	}

	for m(&ATL) > 0 && n(&ATL) > 0 {
		util.Repartition2x2to3x3(&ATL,
			&A00, nil, nil,
			&a10, &a11, &a12,
			nil, &a21, &A22, A, 1, util.PTOPLEFT)
		util.Repartition2x1to3x1(&tT,
			&t0,
			&tau1,
			&t2, Tvec, 1, util.PTOP)
		// ------------------------------------------------------

		w12.SubMatrix(W, 0, 0, a21.Len(), 1)
		applyHouseholder2x1(&tau1, &a12, &a21, &A22, &w12, gomas.RIGHT)

		blasd.Scale(&a12, -tau1.Get(0, 0))
		a11.Set(0, 0, 1.0-tau1.Get(0, 0))

		// zero
		blasd.Scale(&a10, 0.0)
		// ------------------------------------------------------
		util.Continue3x3to2x2(
			&ATL, &ATR,
			&ABL, &ABR, &A00, &a11, &A22, A, util.PTOPLEFT)
		util.Continue3x1to2x1(
			&tT,
			&tB, &t0, &tau1, Tvec, util.PTOP)
	}
}
Beispiel #5
0
/*
 * Applies a real elementary reflector H to a real m by n matrix A,
 * from either the left or the right. H is represented in the form
 *
 *       H = I - tau * ( 1 ) * ( 1 v.T )
 *                     ( v )
 *
 * where tau is a real scalar and v is a real vector.
 *
 * If tau = 0, then H is taken to be the unit cmat.
 *
 * A is /a1\   a1 := a1 - w1
 *      \A2/   A2 := A2 - v*w1
 *             w1 := tau*(a1 + A2.T*v) if side == LEFT
 *                := tau*(a1 + A2*v)   if side == RIGHT
 *
 * Intermediate work space w1 required as parameter, no allocation.
 */
func applyHouseholder2x1(tau, v, a1, A2, w1 *cmat.FloatMatrix, flags int) *gomas.Error {
	var err *gomas.Error = nil
	tval := tau.Get(0, 0)
	if tval == 0.0 {
		return err
	}

	// shape oblivious vector copy.
	blasd.Axpby(w1, a1, 1.0, 0.0)
	if flags&gomas.LEFT != 0 {
		// w1 = a1 + A2.T*v
		err = blasd.MVMult(w1, A2, v, 1.0, 1.0, gomas.TRANSA)
	} else {
		// w1 = a1 + A2*v
		err = blasd.MVMult(w1, A2, v, 1.0, 1.0, gomas.NONE)
	}
	// w1 = tau*w1
	blasd.Scale(w1, tval)

	// a1 = a1 - w1
	blasd.Axpy(a1, w1, -1.0)

	// A2 = A2 - v*w1
	if flags&gomas.LEFT != 0 {
		err = blasd.MVUpdate(A2, v, w1, -1.0)
	} else {
		err = blasd.MVUpdate(A2, w1, v, -1.0)
	}
	return err
}
Beispiel #6
0
func TestDVecScal(t *testing.T) {

	const N = 911

	X := cmat.NewMatrix(N, 1)
	Y := cmat.NewMatrix(N, 1)

	zeromean := cmat.NewFloatUniformSource(2.0, 0.5)

	X.SetFrom(zeromean)
	Y.Copy(X)

	// B = A*B
	blasd.Scale(X, 2.0)
	blasd.InvScale(X, 2.0)
	ok := X.AllClose(Y)
	t.Logf("X = InvScale(Scale(X, 2.0), 2.0) : %v\n", ok)

}
Beispiel #7
0
/* From LAPACK/dlarf.f
 *
 * Applies a real elementary reflector H to a real m by n matrix A,
 * from either the left or the right. H is represented in the form
 *
 *       H = I - tau * ( 1 ) * ( 1 v.T )
 *                     ( v )
 *
 * where tau is a real scalar and v is a real vector.
 *
 * If tau = 0, then H is taken to be the unit cmat.
 *
 * A is /a1\   a1 := a1 - w1
 *      \A2/   A2 := A2 - v*w1
 *             w1 := tau*(a1 + A2.T*v) if side == LEFT
 *                := tau*(a1 + A2*v)   if side == RIGHT
 *
 * Allocates/frees intermediate work space matrix w1.
 */
func applyHouseholder(tau, v, a1, A2 *cmat.FloatMatrix, flags int) {

	tval := tau.Get(0, 0)
	if tval == 0.0 {
		return
	}
	w1 := cmat.NewCopy(a1)
	if flags&gomas.LEFT != 0 {
		// w1 = a1 + A2.T*v
		blasd.MVMult(w1, A2, v, 1.0, 1.0, gomas.TRANSA)
	} else {
		// w1 = a1 + A2*v
		blasd.MVMult(w1, A2, v, 1.0, 1.0, gomas.NONE)
	}

	// w1 = tau*w1
	blasd.Scale(w1, tval)

	// a1 = a1 - w1
	blasd.Axpy(a1, w1, -1.0)

	// A2 = A2 - v*w1
	blasd.MVUpdate(A2, v, w1, -1.0)
}
Beispiel #8
0
/*
 * Blocked version for computing C = C*Q and C = C*Q.T from elementary reflectors
 * and scalar coefficients.
 *
 * Elementary reflectors and scalar coefficients are used to build block reflector T.
 * Matrix C is updated by applying block reflector T using compact WY algorithm.
 */
func blockedMultQRight(C, A, tau, W *cmat.FloatMatrix, flags, nb int, conf *gomas.Config) {
	var ATL, ATR, ABL, ABR, AL cmat.FloatMatrix
	var A00, A10, A11, A20, A21, A22 cmat.FloatMatrix
	var CL, CR, C0, C1, C2 cmat.FloatMatrix
	var tT, tB cmat.FloatMatrix
	var t0, tau1, t2 cmat.FloatMatrix
	var W0, Wrk, Tw, Twork cmat.FloatMatrix

	var Aref *cmat.FloatMatrix
	var pAdir, pAstart, pDir, pStart, pCstart, pCdir util.Direction
	var bsz, cb, mb int

	// partitioning start and direction
	if flags&gomas.TRANS != 0 {
		// from bottom-right to top-left to produce transpose sequence (C*Q.T)
		pAstart = util.PBOTTOMRIGHT
		pAdir = util.PTOPLEFT
		pStart = util.PBOTTOM
		pDir = util.PTOP
		pCstart = util.PRIGHT
		pCdir = util.PLEFT
		mb = imax(0, m(A)-n(A))
		cb = n(C) - n(A)
		Aref = &ATL
	} else {
		// from top-left to bottom-right to produce normal sequence (C*Q)
		pAstart = util.PTOPLEFT
		pAdir = util.PBOTTOMRIGHT
		pStart = util.PTOP
		pDir = util.PBOTTOM
		pCstart = util.PLEFT
		pCdir = util.PRIGHT
		mb = 0
		cb = 0
		Aref = &ABR
	}

	// intermediate reflector at start of workspace
	Twork.SetBuf(nb, nb, nb, W.Data())
	W0.SetBuf(m(C), nb, m(C), W.Data()[Twork.Len():])

	util.Partition2x2(
		&ATL, &ATR,
		&ABL, &ABR, A, mb, 0, pAstart)
	util.Partition1x2(
		&CL, &CR, C, cb, pCstart)
	util.Partition2x1(
		&tT,
		&tB, tau, 0, pStart)

	transpose := flags&gomas.TRANS != 0

	for m(Aref) > 0 && n(Aref) > 0 {
		util.Repartition2x2to3x3(&ATL,
			&A00, nil, nil,
			&A10, &A11, nil,
			&A20, &A21, &A22, A, nb, pAdir)
		util.Repartition2x1to3x1(&tT,
			&t0,
			&tau1,
			&t2, tau, nb, pDir)

		bsz = n(&A11) // C1 block size must match A11
		util.Repartition1x2to1x3(&CL,
			&C0, &C1, &C2, C, bsz, pCdir)
		// --------------------------------------------------------
		// clear & build block reflector from current block
		util.Merge2x1(&AL, &A11, &A21)
		Tw.SubMatrix(&Twork, 0, 0, bsz, bsz)
		blasd.Scale(&Tw, 0.0)
		unblkQRBlockReflector(&Tw, &AL, &tau1)

		// compute: C*Q.T == C - C*(Y*T*Y.T).T = C - C*Y*T.T*Y.T
		//          C*Q   == C - C*Y*T*Y.T
		Wrk.SubMatrix(&W0, 0, 0, m(&C1), bsz)
		updateWithQTRight(&C1, &C2, &A11, &A21, &Tw, &Wrk, transpose, conf)
		// --------------------------------------------------------
		util.Continue3x3to2x2(
			&ATL, &ATR,
			&ABL, &ABR, &A00, &A11, &A22, A, pAdir)
		util.Continue1x3to1x2(
			&CL, &CR, &C0, &C1, C, pCdir)
		util.Continue3x1to2x1(
			&tT,
			&tB, &t0, &tau1, tau, pDir)
	}

}
Beispiel #9
0
/*
 * Blocked version for computing C = Q*C and C = Q.T*C from elementary reflectors
 * and scalar coefficients.
 *
 * Elementary reflectors and scalar coefficients are used to build block reflector T.
 * Matrix C is updated by applying block reflector T using compact WY algorithm.
 */
func blockedMultQLeft(C, A, tau, W *cmat.FloatMatrix, flags, nb int, conf *gomas.Config) {
	var ATL, ATR, ABL, ABR, AL cmat.FloatMatrix
	var A00, A10, A11, A20, A21, A22 cmat.FloatMatrix
	var CT, CB, C0, C1, C2 cmat.FloatMatrix
	var tT, tB cmat.FloatMatrix
	var t0, tau1, t2 cmat.FloatMatrix
	var Wrk, W0, Tw, Twork cmat.FloatMatrix

	var Aref *cmat.FloatMatrix
	var pAdir, pAstart, pDir, pStart util.Direction
	var bsz, mb int

	// partitioning start and direction
	if flags&gomas.TRANS != 0 || nb == n(A) {
		// from top-left to bottom-right to produce transposed sequence (Q.T*C)
		pAstart = util.PTOPLEFT
		pAdir = util.PBOTTOMRIGHT
		pStart = util.PTOP
		pDir = util.PBOTTOM
		mb = 0
		Aref = &ABR
	} else {
		// from bottom-right to top-left to produce normal sequence (Q*C)
		pAstart = util.PBOTTOMRIGHT
		pAdir = util.PTOPLEFT
		pStart = util.PBOTTOM
		pDir = util.PTOP
		mb = imax(0, m(A)-n(A))
		Aref = &ATL
	}

	util.Partition2x2(
		&ATL, &ATR,
		&ABL, &ABR, A, mb, 0, pAstart)
	util.Partition2x1(
		&CT,
		&CB, C, mb, pStart)
	util.Partition2x1(
		&tT,
		&tB, tau, 0, pStart)

	transpose := flags&gomas.TRANS != 0

	// intermediate reflector at start of workspace
	Twork.SetBuf(nb, nb, nb, W.Data())
	W0.SetBuf(n(C), nb, n(C), W.Data()[Twork.Len():])

	for m(Aref) > 0 && n(Aref) > 0 {
		util.Repartition2x2to3x3(&ATL,
			&A00, nil, nil,
			&A10, &A11, nil,
			&A20, &A21, &A22, A, nb, pAdir)
		util.Repartition2x1to3x1(&tT,
			&t0,
			&tau1,
			&t2, tau, nb, pDir)
		bsz = n(&A11)
		util.Repartition2x1to3x1(&CT,
			&C0,
			&C1,
			&C2, C, bsz, pDir)
		// --------------------------------------------------------
		// clear & build block reflector from current block
		util.Merge2x1(&AL, &A11, &A21)
		Tw.SubMatrix(&Twork, 0, 0, bsz, bsz)
		blasd.Scale(&Tw, 0.0)
		unblkQRBlockReflector(&Tw, &AL, &tau1)

		// compute: Q*T.C == C - Y*(C.T*Y*T).T  transpose == true
		//          Q*C   == C - C*Y*T*Y.T      transpose == false
		Wrk.SubMatrix(&W0, 0, 0, n(&C1), bsz)
		updateWithQTLeft(&C1, &C2, &A11, &A21, &Tw, &Wrk, transpose, conf)
		// --------------------------------------------------------
		util.Continue3x3to2x2(
			&ATL, &ATR,
			&ABL, &ABR, &A00, &A11, &A22, A, pAdir)
		util.Continue3x1to2x1(
			&CT,
			&CB, &C0, &C1, C, pDir)
		util.Continue3x1to2x1(
			&tT,
			&tB, &t0, &tau1, tau, pDir)
	}

}
Beispiel #10
0
func blkMultLeftQL(C, A, tau, W *cmat.FloatMatrix, flags, lb int, conf *gomas.Config) {
	var ATL /*ATR, ABL,*/, ABR, AL cmat.FloatMatrix
	var A00, A01, A11, A22 cmat.FloatMatrix
	var CT, CB, C0, C1, C2 cmat.FloatMatrix
	var tT, tB cmat.FloatMatrix
	var t0, tau1, t2 cmat.FloatMatrix
	var T0, T, W0, Wrk cmat.FloatMatrix

	var Aref *cmat.FloatMatrix
	var pAdir, pAstart, pDir, pStart util.Direction
	var mb, tb, nb int

	// partitioning start and direction
	if flags&gomas.TRANS != 0 {
		// A from bottom-right to top-left to produce transposed sequence (Q.T*C)
		pAstart = util.PBOTTOMRIGHT
		pAdir = util.PTOPLEFT
		pStart = util.PBOTTOM
		pDir = util.PTOP
		mb = 0
		tb = 0
		nb = 0
		Aref = &ATL
	} else {
		// from top-left to bottom-right to produce normal sequence (Q*C)
		pAstart = util.PTOPLEFT
		pAdir = util.PBOTTOMRIGHT
		pStart = util.PTOP
		pDir = util.PBOTTOM
		mb = imax(0, m(A)-n(A))
		nb = imax(0, n(A)-m(A))
		tb = imax(0, tau.Len()-n(A))
		Aref = &ABR
	}

	util.Partition2x2(
		&ATL, nil,
		nil, &ABR, A, mb, nb, pAstart)
	util.Partition2x1(
		&CT,
		&CB, C, mb, pStart)
	util.Partition2x1(
		&tT,
		&tB, tau, tb, pStart)

	transpose := flags&gomas.TRANS != 0
	// divide workspace for block reflector and temporart space
	T0.SetBuf(lb, lb, lb, W.Data())
	W0.SetBuf(n(C), lb, n(C), W.Data()[T0.Len():])

	for n(Aref) > 0 {
		util.Repartition2x2to3x3(&ATL,
			&A00, &A01, nil,
			nil, &A11, nil,
			nil, nil, &A22, A, lb, pAdir)
		util.Repartition2x1to3x1(&tT,
			&t0,
			&tau1,
			&t2, tau, lb, pDir)
		bsz := n(&A11)
		util.Repartition2x1to3x1(&CT,
			&C0,
			&C1,
			&C2, C, bsz, pDir)
		// --------------------------------------------------------
		// build block reflector for current block
		util.Merge2x1(&AL, &A01, &A11)
		T.SubMatrix(&T0, 0, 0, bsz, bsz)
		blasd.Scale(&T, 0.0)
		unblkQLBlockReflector(&T, &AL, &tau1)

		// update with (I - Y*T*Y.T) or (I - Y*T*Y.T).T
		Wrk.SubMatrix(&W0, 0, 0, n(&C1), bsz)
		updateQLLeft(&C1, &C0, &A11, &A01, &T, &Wrk, transpose, conf)
		// --------------------------------------------------------
		util.Continue3x3to2x2(
			&ATL, nil,
			nil, &ABR, &A00, &A11, &A22, A, pAdir)
		util.Continue3x1to2x1(
			&CT,
			&CB, &C0, &C1, C, pDir)
		util.Continue3x1to2x1(
			&tT,
			&tB, &t0, &tau1, tau, pDir)
	}
}
Beispiel #11
0
func blkMultRightQL(C, A, tau, W *cmat.FloatMatrix, flags, lb int, conf *gomas.Config) {
	var ATL, ABR, AL cmat.FloatMatrix
	var A00, A01, A11, A22 cmat.FloatMatrix
	var CL, CR, C0, C1, C2 cmat.FloatMatrix
	var tT, tB cmat.FloatMatrix
	var t0, tau1, t2 cmat.FloatMatrix
	var T0, T, W0, Wrk cmat.FloatMatrix

	var Aref *cmat.FloatMatrix
	var pAdir, pAstart, pDir, pStart, pCdir, pCstart util.Direction
	var mb, tb, nb, cb int

	// partitioning start and direction
	if flags&gomas.TRANS != 0 {
		// from top-left to bottom-right to produce transpose sequence (C*Q.T)
		pAstart = util.PTOPLEFT
		pAdir = util.PBOTTOMRIGHT
		pStart = util.PTOP
		pDir = util.PBOTTOM
		pCstart = util.PLEFT
		pCdir = util.PRIGHT
		mb = imax(0, m(A)-n(A))
		nb = imax(0, n(A)-m(A))
		cb = imax(0, n(C)-n(A))
		tb = imax(0, tau.Len()-n(A))
		Aref = &ABR
	} else {
		// A from bottom-right to top-left to produce normal sequence (C*Q)
		pAstart = util.PBOTTOMRIGHT
		pAdir = util.PTOPLEFT
		pStart = util.PBOTTOM
		pDir = util.PTOP
		pCstart = util.PRIGHT
		pCdir = util.PLEFT
		mb = 0
		tb = 0
		nb = 0
		cb = 0
		Aref = &ATL
	}

	util.Partition2x2(
		&ATL, nil,
		nil, &ABR /**/, A, mb, nb, pAstart)
	util.Partition1x2(
		&CL, &CR /**/, C, cb, pCstart)
	util.Partition2x1(
		&tT,
		&tB /**/, tau, tb, pStart)

	transpose := flags&gomas.TRANS != 0
	// divide workspace for block reflector and temporary work matrix
	T0.SetBuf(lb, lb, lb, W.Data())
	W0.SetBuf(m(C), lb, m(C), W.Data()[T0.Len():])

	for n(Aref) > 0 {
		util.Repartition2x2to3x3(&ATL,
			&A00, &A01, nil,
			nil, &A11, nil,
			nil, nil, &A22 /**/, A, lb, pAdir)
		bsz := n(&A11)
		util.Repartition1x2to1x3(&CL,
			&C0, &C1, &C2 /**/, C, bsz, pCdir)
		util.Repartition2x1to3x1(&tT,
			&t0,
			&tau1,
			&t2 /**/, tau, bsz, pDir)
		// --------------------------------------------------------
		util.Merge2x1(&AL, &A01, &A11)
		T.SubMatrix(&T0, 0, 0, bsz, bsz)
		blasd.Scale(&T, 0.0)
		unblkQLBlockReflector(&T, &AL, &tau1)

		Wrk.SubMatrix(&W0, 0, 0, m(C), bsz)
		updateQLRight(&C1, &C0, &A11, &A01, &T, &Wrk, transpose, conf)
		// --------------------------------------------------------
		util.Continue3x3to2x2(
			&ATL, nil,
			nil, &ABR /**/, &A00, &A11, &A22, A, pAdir)
		util.Continue1x3to1x2(
			&CL, &CR /**/, &C0, &C1, C, pCdir)
		util.Continue3x1to2x1(
			&tT,
			&tB /**/, &t0, &tau1, tau, pDir)
	}
}
Beispiel #12
0
/*
 * Blocked version for computing C = C*Q and C = C*Q.T from elementary
 * reflectors and scalar coefficients.
 *
 * Elementary reflectors and scalar coefficients are used to build block
 * reflector T. Matrix C is updated by applying block reflector T using
 * compact WY algorithm.
 */
func blockedMultRQRight(C, A, tau, W *cmat.FloatMatrix, flags, lb int, conf *gomas.Config) {
	var ATL, ABR, AL cmat.FloatMatrix
	var A00, A10, A11, A22 cmat.FloatMatrix
	var CL, CR, C0, C1, C2 cmat.FloatMatrix
	var tT, tB cmat.FloatMatrix
	var t0, tau1, t2 cmat.FloatMatrix
	var W0, Wrk, Tw, Twork cmat.FloatMatrix

	var Aref *cmat.FloatMatrix
	var pAdir, pAstart, pDir, pStart, pCstart, pCdir util.Direction
	var bsz, cb, mb, nb, tb int
	var transpose bool

	// partitioning start and direction
	if flags&gomas.TRANS != 0 {
		// from bottom-right to top-left to produce transpose sequence (C*Q.T)
		pAstart = util.PBOTTOMRIGHT
		pAdir = util.PTOPLEFT
		pStart = util.PBOTTOM
		pDir = util.PTOP
		pCstart = util.PRIGHT
		pCdir = util.PLEFT
		mb = 0
		nb = 0
		cb = 0
		tb = 0
		Aref = &ATL
		transpose = false
	} else {
		// from top-left to bottom-right to produce normal sequence (C*Q)
		pAstart = util.PTOPLEFT
		pAdir = util.PBOTTOMRIGHT
		pStart = util.PTOP
		pDir = util.PBOTTOM
		pCstart = util.PLEFT
		pCdir = util.PRIGHT
		mb = imax(0, m(A)-n(A))
		nb = imax(0, n(A)-m(A))
		cb = imax(0, n(C)-m(A))
		tb = imax(0, tau.Len()-m(A))
		Aref = &ABR
		transpose = true
	}

	// intermediate reflector at start of workspace
	Twork.SetBuf(lb, lb, lb, W.Data())
	W0.SetBuf(m(C), lb, m(C), W.Data()[Twork.Len():])

	util.Partition2x2(
		&ATL, nil,
		nil, &ABR /**/, A, mb, nb, pAstart)
	util.Partition1x2(
		&CL, &CR /**/, C, cb, pCstart)
	util.Partition2x1(
		&tT,
		&tB /**/, tau, tb, pStart)

	for m(Aref) > 0 && n(Aref) > 0 {
		util.Repartition2x2to3x3(&ATL,
			&A00, nil, nil,
			&A10, &A11, nil,
			nil, nil, &A22 /**/, A, lb, pAdir)
		bsz = m(&A11) // C1 block size must match A11
		util.Repartition2x1to3x1(&tT,
			&t0,
			&tau1,
			&t2 /**/, tau, bsz, pDir)
		util.Repartition1x2to1x3(&CL,
			&C0, &C1, &C2 /**/, C, bsz, pCdir)
		// --------------------------------------------------------
		// clear & build block reflector from current block
		util.Merge1x2(&AL, &A10, &A11)
		Tw.SubMatrix(&Twork, 0, 0, bsz, bsz)
		blasd.Scale(&Tw, 0.0)
		unblkBlockReflectorRQ(&Tw, &AL, &tau1)

		Wrk.SubMatrix(&W0, 0, 0, m(&C1), bsz)
		updateRightRQ(&C1, &C0, &A11, &A10, &Tw, &Wrk, transpose, conf)
		// --------------------------------------------------------
		util.Continue3x3to2x2(
			&ATL, nil,
			nil, &ABR /**/, &A00, &A11, &A22, A, pAdir)
		util.Continue1x3to1x2(
			&CL, &CR /**/, &C0, &C1, C, pCdir)
		util.Continue3x1to2x1(
			&tT,
			&tB /**/, &t0, &tau1, tau, pDir)
	}

}
Beispiel #13
0
/*
 * This is adaptation of BIRED_LAZY_UNB algorithm from (1).
 *
 * Z matrix accumulates updates of row transformations i.e. first
 * Householder that zeros off diagonal entries on row. Vector z21
 * is updates for current round, Z20 are already accumulated updates.
 * Vector z21 updates a12 before next transformation.
 *
 * Y matrix accumulates updates on column tranformations ie Householder
 * that zeros elements below sub-diagonal. Vector y21 is updates for current
 * round, Y20 are already accumulated updates.  Vector y21 updates
 * a21 befor next transformation.
 *
 * Z, Y matrices upper trigonal part is not needed, temporary vector
 * w00 that has maximum length of n(Y) is placed on the last column of
 * Z matrix on each iteration.
 */
func unblkBuildBidiagRight(A, tauq, taup, Y, Z *cmat.FloatMatrix) {
	var ATL, ABL, ABR cmat.FloatMatrix
	var A00, a01, A02, a10, a11, a12t, A20, a21, A22 cmat.FloatMatrix
	var YTL, YBR, ZTL, ZBR cmat.FloatMatrix
	var Y00, y10, Y20, y11, y21, Y22 cmat.FloatMatrix
	var Z00, z10, Z20, z11, z21, Z22 cmat.FloatMatrix
	var tqT, tqB, tq0, tauq1, tq2 cmat.FloatMatrix
	var tpT, tpB, tp0, taup1, tp2 cmat.FloatMatrix
	var w00 cmat.FloatMatrix
	var v0 float64

	// Y is workspace for building updates for first Householder.
	// And Z is space for build updates for second Householder
	// Y is n(A)-2,nb and Z is m(A)-1,nb

	util.Partition2x2(
		&ATL, nil,
		&ABL, &ABR, A, 0, 0, util.PTOPLEFT)
	util.Partition2x2(
		&YTL, nil,
		nil, &YBR, Y, 0, 0, util.PTOPLEFT)
	util.Partition2x2(
		&ZTL, nil,
		nil, &ZBR, Z, 0, 0, util.PTOPLEFT)
	util.Partition2x1(
		&tqT,
		&tqB, tauq, 0, util.PTOP)
	util.Partition2x1(
		&tpT,
		&tpB, taup, 0, util.PTOP)

	k := 0
	for k < n(Y) {
		util.Repartition2x2to3x3(&ATL,
			&A00, &a01, &A02,
			&a10, &a11, &a12t,
			&A20, &a21, &A22, A, 1, util.PBOTTOMRIGHT)
		util.Repartition2x2to3x3(&YTL,
			&Y00, nil, nil,
			&y10, &y11, nil,
			&Y20, &y21, &Y22, Y, 1, util.PBOTTOMRIGHT)
		util.Repartition2x2to3x3(&ZTL,
			&Z00, nil, nil,
			&z10, &z11, nil,
			&Z20, &z21, &Z22, Z, 1, util.PBOTTOMRIGHT)
		util.Repartition2x1to3x1(&tqT,
			&tq0,
			&tauq1,
			&tq2, tauq, 1, util.PBOTTOM)
		util.Repartition2x1to3x1(&tpT,
			&tp0,
			&taup1,
			&tp2, taup, 1, util.PBOTTOM)

		// set temp vectors for this round,
		w00.SubMatrix(Z, 0, n(Z)-1, m(&A02), 1)
		// ------------------------------------------------------
		// u10 == a10, U20 == A20, u21 == a21,
		// v10 == a01, V20 == A02, v21 == a12t
		if n(&Y20) > 0 {
			// a11 := a11 - u10t*z10 - y10*v10
			aa := blasd.Dot(&a10, &z10)
			aa += blasd.Dot(&y10, &a01)
			a11.Set(0, 0, a11.Get(0, 0)-aa)
			// a12t := a12t - V20*z10 - Z20*u10
			blasd.MVMult(&a12t, &A02, &y10, -1.0, 1.0, gomas.TRANS)
			blasd.MVMult(&a12t, &Z20, &a10, -1.0, 1.0, gomas.NONE)
			// a21 := a21 - Y20*v10 - U20*z10
			blasd.MVMult(&a21, &Y20, &a01, -1.0, 1.0, gomas.NONE)
			blasd.MVMult(&a21, &A20, &z10, -1.0, 1.0, gomas.NONE)
			// here restore bidiagonal entry
			a10.Set(0, -1, v0)
		}
		// Compute householder to zero superdiagonal entries
		computeHouseholder(&a11, &a12t, &taup1)
		taupv := taup1.Get(0, 0)

		// y21 := a21 + A22*v21 - Y20*U20.T*v21 - V20*Z20.T*v21
		blasd.Axpby(&y21, &a21, 1.0, 0.0)
		blasd.MVMult(&y21, &A22, &a12t, 1.0, 1.0, gomas.NONE)

		// w00 := U20.T*v21 [= A02*a12t]
		blasd.MVMult(&w00, &A02, &a12t, 1.0, 0.0, gomas.NONE)
		// y21 := y21 - U20*w00 [U20 == A20]
		blasd.MVMult(&y21, &Y20, &w00, -1.0, 1.0, gomas.NONE)
		// w00 := Z20.T*v21
		blasd.MVMult(&w00, &Z20, &a12t, 1.0, 0.0, gomas.TRANS)
		// y21 := y21 - V20*w00  [V20 == A02.T]
		blasd.MVMult(&y21, &A20, &w00, -1.0, 1.0, gomas.NONE)

		// a21 := a21 - taup*y21
		blasd.Scale(&y21, taupv)
		blasd.Axpy(&a21, &y21, -1.0)

		// Compute householder to zero elements below 1st subdiagonal
		computeHouseholderVec(&a21, &tauq1)
		v0 = a21.Get(0, 0)
		a21.Set(0, 0, 1.0)
		tauqv := tauq1.Get(0, 0)

		// z21 := tauq*(A22*y - V20*Y20.T*u - Z20*U20.T*u - beta*v)
		// [v == a12t, u == a21]
		beta := blasd.Dot(&y21, &a21)
		// z21 := beta*v
		blasd.Axpby(&z21, &a12t, beta, 0.0)
		// w00 = Y20.T*u
		blasd.MVMult(&w00, &Y20, &a21, 1.0, 0.0, gomas.TRANS)
		// z21 = z21 + V20*w00 == A02.T*w00
		blasd.MVMult(&z21, &A02, &w00, 1.0, 1.0, gomas.TRANS)
		// w00 := U20.T*u  (U20.T == A20.T)
		blasd.MVMult(&w00, &A20, &a21, 1.0, 0.0, gomas.TRANS)
		// z21 := z21 + Z20*w00
		blasd.MVMult(&z21, &Z20, &w00, 1.0, 1.0, gomas.NONE)
		// z21 := -tauq*z21 + tauq*A22*v
		blasd.MVMult(&z21, &A22, &a21, tauqv, -tauqv, gomas.TRANS)
		// ------------------------------------------------------
		k += 1
		util.Continue3x3to2x2(
			&ATL, nil,
			&ABL, &ABR, &A00, &a11, &A22, A, util.PBOTTOMRIGHT)
		util.Continue3x3to2x2(
			&YTL, nil,
			nil, &YBR, &Y00, &y11, &Y22, Y, util.PBOTTOMRIGHT)
		util.Continue3x3to2x2(
			&ZTL, nil,
			nil, &ZBR, &Z00, &z11, &Z22, Z, util.PBOTTOMRIGHT)
		util.Continue3x1to2x1(
			&tqT,
			&tqB, &tq0, &tauq1, tauq, util.PBOTTOM)
		util.Continue3x1to2x1(
			&tpT,
			&tpB, &tp0, &taup1, taup, util.PBOTTOM)
	}
	// restore
	ABL.Set(0, -1, v0)
}
Beispiel #14
0
/*
 * Blocked code for generating M by N matrix Q with orthogonal columns which
 * are defined as the last N columns of the product of K first elementary
 * reflectors.
 *
 * If the number K of elementary reflectors is not multiple of the blocking
 * factor lb, then unblocked code is used first to generate the upper left corner
 * of the matrix Q.
 *
 * Compatible with lapack.DORGQL subroutine.
 */
func blkBuildQL(A, Tvec, Twork, W *cmat.FloatMatrix, K, lb int, conf *gomas.Config) {
	var ATL, ATR, ABL, ABR, AL cmat.FloatMatrix
	var A00, A01, A10, A11, A21, A22 cmat.FloatMatrix
	var tT, tB cmat.FloatMatrix
	var t0, tau, t2, Wrk, D, T cmat.FloatMatrix

	nk := n(A) - K
	mk := m(A) - K
	uk := K % lb
	util.Partition2x2(
		&ATL, &ATR,
		&ABL, &ABR, A, mk+uk, nk+uk, util.PTOPLEFT)
	util.Partition2x1(
		&tT,
		&tB, Tvec, nk+uk, util.PTOP)

	// zero the left side
	if nk+uk > 0 {
		blasd.Scale(&ABL, 0.0)
		if uk > 0 {
			// number of reflectors is not multiple of blocking factor
			// do the first part with unblocked code.
			unblkBuildQL(&ATL, &tT, W, m(&ATL)-uk, n(&ATL)-uk, true)
		} else {
			// blocking factor is multiple of K
			blasd.Scale(&ATL, 0.0)
			D.Diag(&ATL)
			blasd.Add(&D, 1.0)
		}
	}

	for m(&ABR) > 0 && n(&ABR) > 0 {
		util.Repartition2x2to3x3(&ATL,
			&A00, &A01, nil,
			&A10, &A11, nil,
			nil, &A21, &A22, A, lb, util.PBOTTOMRIGHT)
		util.Repartition2x1to3x1(&tT,
			&t0,
			&tau,
			&t2, Tvec, lb, util.PBOTTOM)
		// ------------------------------------------------------
		util.Merge2x1(&AL, &A01, &A11)

		// build block reflector
		T.SubMatrix(Twork, 0, 0, n(&A11), n(&A11))
		unblkQLBlockReflector(&T, &AL, &tau)

		// update left side i.e. A10 and A00 with (I - Y*T*Y.T)
		ar, ac := A10.Size()
		Wrk.SubMatrix(W, 0, 0, ac, ar)
		updateQLLeft(&A10, &A00, &A11, &A01, &T, &Wrk, false, conf)

		// update current block
		unblkBuildQL(&AL, &tau, W, m(&A01), 0, false)

		// zero bottom rows
		blasd.Scale(&A21, 0.0)
		// ------------------------------------------------------
		util.Continue3x3to2x2(
			&ATL, &ATR,
			&ABL, &ABR, &A00, &A11, &A22, A, util.PBOTTOMRIGHT)
		util.Continue3x1to2x1(
			&tT,
			&tB, &t0, &tau, Tvec, util.PBOTTOM)
	}

}
Beispiel #15
0
/*
 * Generate one of the orthogonal matrices Q or P.T determined by BDReduce() when
 * reducing a real matrix A to bidiagonal form. Q and P.T are defined as products
 * elementary reflectors H(i) or G(i) respectively.
 *
 * Orthogonal matrix Q is generated if flag WANTQ is set. And matrix P respectively
 * if flag WANTP is set.
 */
func BDBuild(A, tau, W *cmat.FloatMatrix, K, flags int, confs ...*gomas.Config) *gomas.Error {
	var Qh, Ph, tauh, d, s cmat.FloatMatrix
	var err *gomas.Error = nil

	if m(A) == 0 || n(A) == 0 {
		return nil
	}

	if m(A) > n(A) || (m(A) == n(A) && flags&gomas.LOWER == 0) {
		switch flags & (gomas.WANTQ | gomas.WANTP) {
		case gomas.WANTQ:
			tauh.SubMatrix(tau, 0, 0, n(A), 1)
			err = QRBuild(A, &tauh, W, K, confs...)

		case gomas.WANTP:
			// Shift P matrix embedded in A down and fill first column and row
			// to unit vector
			for j := n(A) - 1; j > 0; j-- {
				s.SubMatrix(A, j-1, j, 1, n(A)-j)
				d.SubMatrix(A, j, j, 1, n(A)-j)
				blasd.Copy(&d, &s)
				A.Set(j, 0, 0.0)
			}
			// zero  first row and set first entry to one
			d.Row(A, 0)
			blasd.Scale(&d, 0.0)
			d.Set(0, 0, 1.0)

			Ph.SubMatrix(A, 1, 1, n(A)-1, n(A)-1)
			tauh.SubMatrix(tau, 0, 0, n(A)-1, 1)
			if K > n(A)-1 {
				K = n(A) - 1
			}
			err = LQBuild(&Ph, &tauh, W, K, confs...)
		}
	} else {
		switch flags & (gomas.WANTQ | gomas.WANTP) {
		case gomas.WANTQ:
			// Shift Q matrix embedded in A right and fill first column and row
			// to unit vector
			for j := m(A) - 1; j > 0; j-- {
				s.SubMatrix(A, j, j-1, m(A)-j, 1)
				d.SubMatrix(A, j, j, m(A)-j, 1)
				blasd.Copy(&d, &s)
				A.Set(0, j, 0.0)
			}
			// zero first column and set first entry to one
			d.Column(A, 0)
			blasd.Scale(&d, 0.0)
			d.Set(0, 0, 1.0)

			Qh.SubMatrix(A, 1, 1, m(A)-1, m(A)-1)
			tauh.SubMatrix(tau, 0, 0, m(A)-1, 1)
			if K > m(A)-1 {
				K = m(A) - 1
			}
			err = QRBuild(&Qh, &tauh, W, K, confs...)

		case gomas.WANTP:
			tauh.SubMatrix(tau, 0, 0, m(A), 1)
			err = LQBuild(A, &tauh, W, K, confs...)
		}
	}
	if err != nil {
		err.Update("BDBuild")
	}
	return err
}
Beispiel #16
0
func blkBuildLQ(A, Tvec, Twork, W *cmat.FloatMatrix, K, lb int, conf *gomas.Config) {
	var ATL, ATR, ABL, ABR, AL cmat.FloatMatrix
	var A00, A10, A11, A12, A21, A22 cmat.FloatMatrix
	var tT, tB cmat.FloatMatrix
	var t0, tau, t2, Wrk, D, T cmat.FloatMatrix

	nk := n(A) - K
	mk := m(A) - K
	uk := K % lb
	util.Partition2x2(
		&ATL, &ATR,
		&ABL, &ABR, A, mk+uk, nk+uk, util.PBOTTOMRIGHT)
	util.Partition2x1(
		&tT,
		&tB, Tvec, mk+uk, util.PBOTTOM)

	// zero the bottom part __CHECK HERE: nk? or mk?
	if nk+uk > 0 {
		blasd.Scale(&ABL, 0.0)
		if uk > 0 {
			// number of reflectors is not multiple of blocking factor
			// do the first part with unblocked code.
			unblkBuildLQ(&ABR, &tB, W, m(&ABR)-uk, n(&ABR)-uk, true)
		} else {
			// blocking factor is multiple of K
			blasd.Scale(&ABR, 0.0)
			D.Diag(&ABR)
			blasd.Add(&D, 1.0)
		}
	}

	for m(&ATL) > 0 && n(&ATL) > 0 {
		util.Repartition2x2to3x3(&ATL,
			&A00, nil, nil,
			&A10, &A11, &A12,
			nil, &A21, &A22, A, lb, util.PTOPLEFT)
		util.Repartition2x1to3x1(&tT,
			&t0,
			&tau,
			&t2, Tvec, lb, util.PTOP)
		// ------------------------------------------------------
		util.Merge1x2(&AL, &A11, &A12)

		// build block reflector
		T.SubMatrix(Twork, 0, 0, n(&A11), n(&A11))
		unblkBlockReflectorLQ(&T, &AL, &tau)

		// update A21 and A22 with (I - Y*T*Y.T) from right
		ar, ac := A21.Size()
		Wrk.SubMatrix(W, 0, 0, ar, ac)
		updateRightLQ(&A21, &A22, &A11, &A12, &T, &Wrk, false, conf)

		// update current block
		unblkBuildLQ(&AL, &tau, W, 0, n(&A12), false)

		// zero top rows
		blasd.Scale(&A10, 0.0)
		// ------------------------------------------------------
		util.Continue3x3to2x2(
			&ATL, &ATR,
			&ABL, &ABR, &A00, &A11, &A22, A, util.PTOPLEFT)
		util.Continue3x1to2x1(
			&tT,
			&tB, &t0, &tau, Tvec, util.PTOP)
	}
}
Beispiel #17
0
func svdSmall(S, U, V, A, W *cmat.FloatMatrix, bits int, conf *gomas.Config) (err *gomas.Error) {
	var r cmat.FloatMatrix
	var d0, d1, e0 float64

	err = nil
	K := m(A)
	if n(A) < K {
		K = n(A)
	}
	tau := cmat.NewMatrix(K, 1)
	if m(A) >= n(A) {
		if err = QRFactor(A, tau, W, conf); err != nil {
			return
		}
	} else {
		if err = LQFactor(A, tau, W, conf); err != nil {
			return
		}
	}
	if m(A) == 1 || n(A) == 1 {
		// either tall M-by-1 or wide 1-by-N
		S.SetAt(0, math.Abs(A.Get(0, 0)))

		if bits&gomas.WANTU != 0 {
			if n(A) == 1 {
				if n(U) == n(A) {
					// U is M-by-1
					U.Copy(A)
					QRBuild(U, tau, W, n(A), conf)
				} else {
					// U is M-by-M
					eye := cmat.FloatDiagonalSource{1.0}
					U.SetFrom(&eye, cmat.SYMM)
					if err = QRMult(U, A, tau, W, gomas.RIGHT, conf); err != nil {
						return
					}
				}
			} else {
				U.Set(0, 0, -1.0)
			}
		}
		if bits&gomas.WANTV != 0 {
			if m(A) == 1 {
				if m(V) == m(A) {
					// V is 1-by-N
					V.Copy(A)
					LQBuild(V, tau, W, m(A), conf)
				} else {
					// V is N-by-N
					eye := cmat.FloatDiagonalSource{1.0}
					V.SetFrom(&eye, cmat.SYMM)
					if err = LQMult(V, A, tau, W, gomas.RIGHT, conf); err != nil {
						return
					}
				}
			} else {
				// V is 1-by-1
				V.Set(0, 0, -1.0)
			}
		}
		return
	}

	// Use bdSvd2x2 functions
	d0 = A.Get(0, 0)
	d1 = A.Get(1, 1)
	if m(A) >= n(A) {
		e0 = A.Get(0, 1)
	} else {
		e0 = A.Get(1, 0)
	}

	if bits&(gomas.WANTU|gomas.WANTV) == 0 {
		// no vectors
		smin, smax := bdSvd2x2(d0, e0, d1)
		S.SetAt(0, math.Abs(smax))
		S.SetAt(1, math.Abs(smin))
		return
	}

	// at least left or right eigenvector wanted
	smin, smax, cosl, sinl, cosr, sinr := bdSvd2x2Vec(d0, e0, d1)
	if bits&gomas.WANTU != 0 {
		// left eigenvectors
		if m(A) >= n(A) {
			if n(U) == n(A) {
				U.Copy(A)
				if err = QRBuild(U, tau, W, n(A), conf); err != nil {
					return
				}
			} else {
				// U is M-by-M
				eye := cmat.FloatDiagonalSource{1.0}
				U.SetFrom(&eye, cmat.SYMM)
				if err = QRMult(U, A, tau, W, gomas.RIGHT, conf); err != nil {
					return
				}
			}
			ApplyGivensRight(U, 0, 1, 0, m(A), cosl, sinl)
		} else {
			// U is 2-by-2
			eye := cmat.FloatDiagonalSource{1.0}
			U.SetFrom(&eye, cmat.SYMM)
			ApplyGivensRight(U, 0, 1, 0, m(A), cosr, sinr)
		}
	}

	if bits&gomas.WANTV != 0 {
		if n(A) > m(A) {
			if m(V) == m(A) {
				V.Copy(A)
				if err = LQBuild(V, tau, W, m(A), conf); err != nil {
					return
				}
			} else {
				eye := cmat.FloatDiagonalSource{1.0}
				V.SetFrom(&eye, cmat.SYMM)
				if err = LQMult(V, A, tau, W, gomas.RIGHT, conf); err != nil {
					return
				}
			}
			ApplyGivensLeft(V, 0, 1, 0, n(A), cosl, sinl)
		} else {
			// V is 2-by-2
			eye := cmat.FloatDiagonalSource{1.0}
			V.SetFrom(&eye, cmat.SYMM)
			ApplyGivensLeft(V, 0, 1, 0, n(A), cosr, sinr)
		}
		if smax < 0.0 {
			r.Row(V, 0)
			blasd.Scale(&r, -1.0)
		}
		if smin < 0.0 {
			r.Row(V, 1)
			blasd.Scale(&r, -1.0)
		}
	}
	S.SetAt(0, math.Abs(smax))
	S.SetAt(1, math.Abs(smin))
	return
}