예제 #1
0
파일: qrtmult.go 프로젝트: hrautila/gomas
/*
 * Solve a system of linear equations A*X = B with general M-by-N
 * matrix A using the QR factorization computed by DecomposeQRT().
 *
 * If flags&gomas.TRANS != 0:
 *   find the minimum norm solution of an overdetermined system A.T * X = B.
 *   i.e min ||X|| s.t A.T*X = B
 *
 * Otherwise:
 *   find the least squares solution of an overdetermined system, i.e.,
 *   solve the least squares problem: min || B - A*X ||.
 *
 * Arguments:
 *  B     On entry, the right hand side N-by-P matrix B. On exit, the solution matrix X.
 *
 *  A     The elements on and above the diagonal contain the min(M,N)-by-N upper
 *        trapezoidal matrix R. The elements below the diagonal with the matrix 'T',
 *        represent the ortogonal matrix Q as product of elementary reflectors.
 *        Matrix A and T are as returned by DecomposeQRT()
 *
 *  T     The block reflector computed from elementary reflectors as returned by
 *        DecomposeQRT() or computed from elementary reflectors and scalar coefficients
 *        by BuildT()
 *
 *  W     Workspace, size as returned by WorkspaceMultQT()
 *
 *  flags Indicator flag
 *
 *  conf  Blocking configuration
 *
 * Compatible with lapack.GELS (the m >= n part)
 */
func QRTSolve(B, A, T, W *cmat.FloatMatrix, flags int, confs ...*gomas.Config) *gomas.Error {
	var err *gomas.Error = nil
	var R, BT cmat.FloatMatrix
	conf := gomas.CurrentConf(confs...)

	if flags&gomas.TRANS != 0 {
		// Solve overdetermined system A.T*X = B

		// B' = R.-1*B
		R.SubMatrix(A, 0, 0, n(A), n(A))
		BT.SubMatrix(B, 0, 0, n(A), n(B))
		err = blasd.SolveTrm(&BT, &R, 1.0, gomas.LEFT|gomas.UPPER|gomas.TRANSA, conf)

		// Clear bottom part of B
		BT.SubMatrix(B, n(A), 0)
		BT.SetFrom(cmat.NewFloatConstSource(0.0))

		// X = Q*B'
		err = QRTMult(B, A, T, W, gomas.LEFT, conf)
	} else {
		// solve least square problem min ||A*X - B||

		// B' = Q.T*B
		err = QRTMult(B, A, T, W, gomas.LEFT|gomas.TRANS, conf)
		if err != nil {
			return err
		}

		// X = R.-1*B'
		R.SubMatrix(A, 0, 0, n(A), n(A))
		BT.SubMatrix(B, 0, 0, n(A), n(B))
		err = blasd.SolveTrm(&BT, &R, 1.0, gomas.LEFT|gomas.UPPER, conf)
	}
	return err
}
예제 #2
0
파일: trmm_test.go 프로젝트: hrautila/gomas
func TestDTrmmUnitUpperRight(t *testing.T) {
	var d cmat.FloatMatrix
	N := 563
	K := 171

	A := cmat.NewMatrix(N, N)
	B := cmat.NewMatrix(K, N)
	B0 := cmat.NewMatrix(K, N)
	C := cmat.NewMatrix(K, N)

	zeros := cmat.NewFloatConstSource(0.0)
	ones := cmat.NewFloatConstSource(1.0)
	zeromean := cmat.NewFloatNormSource()

	A.SetFrom(zeromean, cmat.UPPER|cmat.UNIT)
	B.SetFrom(ones)
	B0.SetFrom(ones)
	// B = B*A
	blasd.MultTrm(B, A, 1.0, gomas.UPPER|gomas.RIGHT|gomas.UNIT)
	d.Diag(A).SetFrom(ones)
	blasd.Mult(C, B0, A, 1.0, 0.0, gomas.NONE)
	ok := C.AllClose(B)
	t.Logf("trmm(B, A, R|U|N|U) == gemm(C, B, TriUU(A))   : %v\n", ok)

	B.SetFrom(ones)
	// B = B*A.T
	d.SetFrom(zeros)
	blasd.MultTrm(B, A, 1.0, gomas.UPPER|gomas.RIGHT|gomas.TRANSA|gomas.UNIT)
	d.SetFrom(ones)
	blasd.Mult(C, B0, A, 1.0, 0.0, gomas.TRANSB)
	ok = C.AllClose(B)
	t.Logf("trmm(B, A, R|U|T|U) == gemm(C, B, TriUU(A).T) : %v\n", ok)
}
예제 #3
0
파일: part_test.go 프로젝트: hrautila/gomas
func TestPartition2D(t *testing.T) {
	var ATL, ATR, ABL, ABR, As cmat.FloatMatrix
	var A00, a01, A02, a10, a11, a12, A20, a21, A22 cmat.FloatMatrix

	csource := cmat.NewFloatConstSource(1.0)
	A := cmat.NewMatrix(6, 6)
	As.SubMatrix(A, 1, 1, 4, 4)
	As.SetFrom(csource)

	Partition2x2(&ATL, &ATR, &ABL, &ABR, &As, 0, 0, PTOPLEFT)
	t.Logf("ATL:\n%v\n", &ATL)

	t.Logf("n(ATL)=%d, n(As)=%d\n", n(&ATL), n(&As))
	k := 0
	for n(&ATL) < n(&As) && k < n(&As) {
		Repartition2x2to3x3(&ATL,
			&A00, &a01, &A02,
			&a10, &a11, &a12,
			&A20, &a21, &A22, &As, 1, PBOTTOMRIGHT)
		t.Logf("n(A00)=%d, n(a01)=%d, n(A02)=%d\n", n(&A00), n(&a01), n(&A02))
		t.Logf("n(a10)=%d, n(a11)=%d, n(a12)=%d\n", n(&a10), n(&a11), n(&a12))
		t.Logf("n(A20)=%d, n(a21)=%d, n(A22)=%d\n", n(&A20), n(&a21), n(&A22))
		//t.Logf("n(a12)=%d [%d], n(a11)=%d\n", n(&a12), a12.Len(), a11.Len())
		a11.Set(0, 0, a11.Get(0, 0)+1.0)
		addConst(&a21, -2.0)

		Continue3x3to2x2(&ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, &As, PBOTTOMRIGHT)
		t.Logf("n(ATL)=%d, n(As)=%d\n", n(&ATL), n(&As))
		k += 1
	}
	t.Logf("A:\n%v\n", A)
}
예제 #4
0
// Simple and slow LQ decomposition with Givens rotations
func TestGivensLQ(t *testing.T) {
	var d cmat.FloatMatrix
	M := 149
	N := 167
	A := cmat.NewMatrix(M, N)
	A1 := cmat.NewCopy(A)

	ones := cmat.NewFloatConstSource(1.0)
	src := cmat.NewFloatNormSource()
	A.SetFrom(src)
	A0 := cmat.NewCopy(A)

	Qt := cmat.NewMatrix(N, N)
	d.Diag(Qt)
	d.SetFrom(ones)

	// R = G(n)...G(2)G(1)*A; Q = G(1).T*G(2).T...G(n).T ;  Q.T = G(n)...G(2)G(1)
	for i := 0; i < M; i++ {
		// zero elements right of diagonal
		for j := N - 2; j >= i; j-- {
			c, s, r := lapackd.ComputeGivens(A.Get(i, j), A.Get(i, j+1))
			A.Set(i, j, r)
			A.Set(i, j+1, 0.0)
			// apply rotation to this column starting from row i+1
			lapackd.ApplyGivensRight(A, j, j+1, i+1, M-i-1, c, s)
			// update Qt = G(k)*Qt
			lapackd.ApplyGivensRight(Qt, j, j+1, 0, N, c, s)
		}
	}
	// A = L*Q
	blasd.Mult(A1, A, Qt, 1.0, 0.0, gomas.TRANSB)
	blasd.Plus(A0, A1, 1.0, -1.0, gomas.NONE)
	nrm := lapackd.NormP(A0, lapackd.NORM_ONE)
	t.Logf("M=%d, N=%d ||A - L*G(1)..G(n)||_1: %e\n", M, N, nrm)
}
예제 #5
0
파일: ql_test.go 프로젝트: hrautila/gomas
// test: C = C*Q.T
func TestQLMultRightTrans(t *testing.T) {
	var d, di0, di1 cmat.FloatMatrix
	M := 891
	N := 853
	lb := 36
	conf := gomas.NewConf()

	A := cmat.NewMatrix(M, N)
	src := cmat.NewFloatNormSource()
	A.SetFrom(src)

	C0 := cmat.NewMatrix(N, M)
	d.Diag(C0, M-N)
	ones := cmat.NewFloatConstSource(1.0)
	d.SetFrom(ones)
	C1 := cmat.NewCopy(C0)

	I0 := cmat.NewMatrix(N, N)
	I1 := cmat.NewCopy(I0)
	di0.Diag(I0)
	di1.Diag(I1)

	tau := cmat.NewMatrix(N, 1)
	W := cmat.NewMatrix(lb*(M+N), 1)

	conf.LB = lb
	lapackd.QLFactor(A, tau, W, conf)

	conf.LB = 0
	lapackd.QLMult(C0, A, tau, W, gomas.RIGHT|gomas.TRANS, conf)
	// I = Q*Q.T - I
	blasd.Mult(I0, C0, C0, 1.0, 0.0, gomas.TRANSB, conf)
	blasd.Add(&di0, -1.0)
	n0 := lapackd.NormP(I0, lapackd.NORM_ONE)

	conf.LB = lb
	lapackd.QLMult(C1, A, tau, W, gomas.RIGHT|gomas.TRANS, conf)
	// I = Q*Q.T - I
	blasd.Mult(I1, C1, C1, 1.0, 0.0, gomas.TRANSB, conf)
	blasd.Add(&di1, -1.0)
	n1 := lapackd.NormP(I1, lapackd.NORM_ONE)

	if N < 10 {
		t.Logf("unblk C0*Q:\n%v\n", C0)
		t.Logf("blk. C2*Q:\n%v\n", C1)
	}
	blasd.Plus(C0, C1, 1.0, -1.0, gomas.NONE)
	n2 := lapackd.NormP(C0, lapackd.NORM_ONE)

	t.Logf("M=%d, N=%d ||unblk.QLMult(C) - blk.QLMult(C)||_1: %e\n", M, N, n2)
	t.Logf("unblk M=%d, N=%d ||I - Q*Q.T||_1: %e\n", M, N, n0)
	t.Logf("blk   M=%d, N=%d ||I - Q*Q.T||_1: %e\n", M, N, n1)
}
예제 #6
0
파일: hess_test.go 프로젝트: hrautila/gomas
// test: A - Q*Hess(A)*Q.T  == 0
func TestMultHess(t *testing.T) {
	N := 377
	nb := 16

	conf := gomas.NewConf()
	conf.LB = nb

	A := cmat.NewMatrix(N, N)
	tau := cmat.NewMatrix(N, 1)
	zeromean := cmat.NewFloatNormSource()
	A.SetFrom(zeromean)
	A0 := cmat.NewCopy(A)

	// reduction
	W := lapackd.Workspace(lapackd.HessReduceWork(A, conf))
	lapackd.HessReduce(A, tau, W, conf)

	var Hlow cmat.FloatMatrix
	H := cmat.NewCopy(A)

	// set triangular part below first subdiagonal to zeros
	zeros := cmat.NewFloatConstSource(0.0)
	Hlow.SubMatrix(H, 1, 0, N-1, N-1)
	Hlow.SetFrom(zeros, cmat.LOWER|cmat.UNIT)
	H1 := cmat.NewCopy(H)

	// H := Q*H*Q.T
	conf.LB = nb
	lapackd.HessMult(H, A, tau, W, gomas.LEFT, conf)
	lapackd.HessMult(H, A, tau, W, gomas.RIGHT|gomas.TRANS, conf)

	// H := Q*H*Q.T
	conf.LB = 0
	lapackd.HessMult(H1, A, tau, W, gomas.LEFT, conf)
	lapackd.HessMult(H1, A, tau, W, gomas.RIGHT|gomas.TRANS, conf)

	// compute ||Q*Hess(A)*Q.T - A||_1
	blasd.Plus(H, A0, 1.0, -1.0, gomas.NONE)
	nrm := lapackd.NormP(H, lapackd.NORM_ONE)
	t.Logf("  blk.|| Q*Hess(A)*Q.T - A ||_1 : %e\n", nrm)

	blasd.Plus(H1, A0, 1.0, -1.0, gomas.NONE)
	nrm = lapackd.NormP(H1, lapackd.NORM_ONE)
	t.Logf("unblk.|| Q*Hess(A)*Q.T - A ||_1 : %e\n", nrm)
}
예제 #7
0
파일: evd_test.go 프로젝트: hrautila/gomas
func testEigen(N int, bits int, t *testing.T) {
	var A, A0, W, D, V *cmat.FloatMatrix
	var sD cmat.FloatMatrix
	var s string = "lower"

	if bits&gomas.UPPER != 0 {
		s = "upper"
	}

	wsize := N * N
	if wsize < 100 {
		wsize = 100
	}

	D = cmat.NewMatrix(N, 1)
	A = cmat.NewMatrix(N, N)
	V = cmat.NewMatrix(N, N)

	src := cmat.NewFloatNormSource()
	A.SetFrom(src, cmat.SYMM)
	A0 = cmat.NewCopy(A)
	W = cmat.NewMatrix(wsize, 1)

	if err := lapackd.EigenSym(D, A, W, bits|gomas.WANTV); err != nil {
		t.Errorf("EigenSym error: %v\n", err)
		return
	}

	// ||I - V.T*V||
	sD.Diag(V)
	blasd.Mult(V, A, A, 1.0, 0.0, gomas.TRANSA)
	blasd.Add(&sD, -1.0)
	nrm1 := lapackd.NormP(V, lapackd.NORM_ONE)

	// left vectors are M-by-N
	V.Copy(A)
	lapackd.MultDiag(V, D, gomas.RIGHT)
	blasd.Mult(A0, V, A, -1.0, 1.0, gomas.TRANSB)
	nrm2 := lapackd.NormP(A0, lapackd.NORM_ONE)

	t.Logf("N=%d, [%s] ||A - V*D*V.T||_1 :%e\n", N, s, nrm2)
	t.Logf("  ||I - V.T*V||_1 : %e\n", nrm1)
}
예제 #8
0
파일: lqmult.go 프로젝트: hrautila/gomas
/*
 * Solve a system of linear equations A.T*X = B with general M-by-N
 * matrix A using the QR factorization computed by LQFactor().
 *
 * If flags&TRANS != 0:
 *   find the minimum norm solution of an overdetermined system A.T * X = B.
 *   i.e min ||X|| s.t A.T*X = B
 *
 * Otherwise:
 *   find the least squares solution of an overdetermined system, i.e.,
 *   solve the least squares problem: min || B - A*X ||.
 *
 * Arguments:
 *  B     On entry, the right hand side N-by-P matrix B. On exit, the solution matrix X.
 *
 *  A     The elements on and below the diagonal contain the M-by-min(M,N) lower
 *        trapezoidal matrix L. The elements right of the diagonal with the vector 'tau',
 *        represent the ortogonal matrix Q as product of elementary reflectors.
 *        Matrix A is as returned by LQFactor()
 *
 *  tau   The vector of N scalar coefficients that together with trilu(A) define
 *        the ortogonal matrix Q as Q = H(N)H(N-1)...H(1)
 *
 *  W     Workspace, size required returned WorksizeMultLQ().
 *
 *  flags Indicator flags
 *
 *  conf  Optinal blocking configuration. If not given default will be used. Unblocked
 *        invocation is indicated with conf.LB == 0.
 *
 * Compatible with lapack.GELS (the m < n part)
 */
func LQSolve(B, A, tau, W *cmat.FloatMatrix, flags int, confs ...*gomas.Config) *gomas.Error {
	var err *gomas.Error = nil
	var L, BL cmat.FloatMatrix

	conf := gomas.CurrentConf(confs...)

	wsmin := wsMultLQLeft(B, 0)
	if W.Len() < wsmin {
		return gomas.NewError(gomas.EWORK, "SolveLQ", wsmin)
	}

	if flags&gomas.TRANS != 0 {
		// solve: MIN ||A.T*X - B||

		// B' = Q.T*B
		err = LQMult(B, A, tau, W, gomas.LEFT, conf)
		if err != nil {
			return err
		}

		// X = L.-1*B'
		L.SubMatrix(A, 0, 0, m(A), m(A))
		BL.SubMatrix(B, 0, 0, m(A), n(B))
		err = blasd.SolveTrm(&BL, &L, 1.0, gomas.LEFT|gomas.LOWER|gomas.TRANSA, conf)

	} else {
		// Solve underdetermined system A*X = B

		// B' = L.-1*B
		L.SubMatrix(A, 0, 0, m(A), m(A))
		BL.SubMatrix(B, 0, 0, m(A), n(B))
		err = blasd.SolveTrm(&BL, &L, 1.0, gomas.LEFT|gomas.LOWER, conf)

		// Clear bottom part of B
		BL.SubMatrix(B, m(A), 0)
		BL.SetFrom(cmat.NewFloatConstSource(0.0))

		// X = Q.T*B'
		err = LQMult(B, A, tau, W, gomas.LEFT|gomas.TRANS, conf)

	}
	return err
}
예제 #9
0
// Simple and slow QR decomposition with Givens rotations
func TestGivensQR(t *testing.T) {
	var d cmat.FloatMatrix
	M := 181
	N := 159
	A := cmat.NewMatrix(M, N)
	A1 := cmat.NewCopy(A)

	ones := cmat.NewFloatConstSource(1.0)
	src := cmat.NewFloatNormSource()
	A.SetFrom(src)
	A0 := cmat.NewCopy(A)

	Qt := cmat.NewMatrix(M, M)
	d.Diag(Qt)
	d.SetFrom(ones)

	// R = G(n)...G(2)G(1)*A; Q = G(1).T*G(2).T...G(n).T ;  Q.T = G(n)...G(2)G(1)

	// for all columns ...
	for j := 0; j < N; j++ {
		// ... zero elements below diagonal, starting from bottom
		for i := M - 2; i >= j; i-- {
			c, s, r := lapackd.ComputeGivens(A.Get(i, j), A.Get(i+1, j))
			A.Set(i, j, r)
			A.Set(i+1, j, 0.0)
			// apply rotations on this row starting from column j, N-j column
			lapackd.ApplyGivensLeft(A, i, i+1, j+1, N-j-1, c, s)
			// update Qt = G(k)*Qt
			lapackd.ApplyGivensLeft(Qt, i, i+1, 0, M, c, s)
		}
	}
	// check: A = Q*R
	blasd.Mult(A1, Qt, A, 1.0, 0.0, gomas.TRANSA)
	blasd.Plus(A0, A1, 1.0, -1.0, gomas.NONE)
	nrm := lapackd.NormP(A0, lapackd.NORM_ONE)
	t.Logf("M=%d, N=%d ||A - G(n)..G(1)*R||_1: %e\n", M, N, nrm)
}
예제 #10
0
파일: svd_test.go 프로젝트: hrautila/gomas
// test: M < N, U=[m,m] and V=[m,n] or V=[n,n] (square)
func testWide(M, N int, square bool, t *testing.T) {
	var A, A0, W, S, U, Uu, V, Vv *cmat.FloatMatrix
	var sD cmat.FloatMatrix
	var s string

	wsize := M * N
	if wsize < 100 {
		wsize = 100
	}

	S = cmat.NewMatrix(M, 1)
	A = cmat.NewMatrix(M, N)
	U = cmat.NewMatrix(M, M)
	Uu = cmat.NewMatrix(M, M)
	if square {
		V = cmat.NewMatrix(N, N)
		Vv = cmat.NewMatrix(N, N)
	} else {
		V = cmat.NewMatrix(M, N)
		Vv = cmat.NewMatrix(M, M)
	}

	src := cmat.NewFloatNormSource()
	A.SetFrom(src)
	A0 = cmat.NewCopy(A)
	W = cmat.NewMatrix(wsize, 1)

	if err := lapackd.SVD(S, U, V, A, W, gomas.WANTU|gomas.WANTV); err != nil {
		t.Errorf("SVD error: %v\n", err)
		return
	}

	// ||I - U.T*U||
	sD.Diag(Uu)
	blasd.Mult(Uu, U, U, 1.0, 0.0, gomas.TRANSA)
	blasd.Add(&sD, -1.0)
	nrm0 := lapackd.NormP(Uu, lapackd.NORM_ONE)

	// ||I - V*V.T||
	sD.Diag(Vv)
	blasd.Mult(Vv, V, V, 1.0, 0.0, gomas.TRANSB)
	blasd.Add(&sD, -1.0)
	nrm1 := lapackd.NormP(Vv, lapackd.NORM_ONE)

	if square {
		// right vectors are N-by-N
		Sg := cmat.NewMatrix(M, N)
		A1 := cmat.NewMatrix(M, N)
		sD.Diag(Sg)
		blasd.Copy(&sD, S)
		blasd.Mult(A1, Sg, V, 1.0, 0.0, gomas.NONE)
		blasd.Mult(A0, U, A1, -1.0, 1.0, gomas.NONE)
		s = "U=[m,m], V=[n,n]"
	} else {
		// right vectors are M-by-N
		lapackd.MultDiag(V, S, gomas.LEFT)
		blasd.Mult(A0, U, V, -1.0, 1.0, gomas.NONE)
		s = "U=[m,m], V=[m,n]"
	}
	nrm2 := lapackd.NormP(A0, lapackd.NORM_ONE)

	if N < 10 {
		t.Logf("A - U*S*V.T:\n%v\n", A0)
	}
	t.Logf("M=%d, N=%d, %s ||A - U*S*V.T||_1 :%e\n", M, N, s, nrm2)
	t.Logf("  ||I - U.T*U||_1 : %e\n", nrm0)
	t.Logf("  ||I - V*V.T||_1 : %e\n", nrm1)
}
예제 #11
0
파일: svd.go 프로젝트: hrautila/gomas
func svdWide(S, U, V, A, W *cmat.FloatMatrix, bits int, conf *gomas.Config) (err *gomas.Error) {
	var uu, vv *cmat.FloatMatrix
	var tauq, taup, Wred, sD, sE, L, Vm cmat.FloatMatrix

	if (bits & (gomas.WANTU | gomas.WANTV)) != 0 {
		if W.Len() < 4*n(A) {
			err = gomas.NewError(gomas.ESIZE, "SVD")
			return
		}
	}
	tauq.SetBuf(m(A)-1, 1, m(A)-1, W.Data())
	taup.SetBuf(m(A), 1, m(A), W.Data()[tauq.Len():])
	wrl := W.Len() - 2*m(A) - 1
	Wred.SetBuf(wrl, 1, wrl, W.Data()[2*m(A)-1:])

	if svdCrossover(n(A), m(A)) {
		goto do_n_much_bigger
	}

	// reduce to bidiagonal form
	if err = BDReduce(A, &tauq, &taup, &Wred, conf); err != nil {
		return
	}

	sD.Diag(A)
	sE.Diag(A, -1)
	blasd.Copy(S, &sD)

	// leftt vectors
	if bits&gomas.WANTU != 0 {
		L.SubMatrix(A, 0, 0, m(A), m(A))
		U.Copy(&L)
		cmat.TriL(U, 0)
		if err = BDBuild(U, &tauq, &Wred, m(U), gomas.WANTQ|gomas.LOWER, conf); err != nil {
			return
		}
		uu = U
	}
	// right vectors
	if bits&gomas.WANTV != 0 {
		if m(V) == m(A) {
			// V is M-by-N; copy and make upper triangular
			V.Copy(A)
			//cmat.TriU(V, 0)
			if err = BDBuild(V, &taup, &Wred, m(V), gomas.WANTP, conf); err != nil {
				return
			}
		} else {
			// V is N-by-N
			eye := cmat.FloatDiagonalSource{1.0}
			V.SetFrom(&eye, cmat.SYMM)
			err = BDMult(V, A, &taup, &Wred, gomas.MULTP|gomas.LEFT|gomas.TRANS, conf)
			if err != nil {
				return
			}
		}
		vv = V
	}
	err = BDSvd(S, &sE, uu, vv, W, bits|gomas.LOWER)
	return

do_n_much_bigger:
	// here N >> M, use LQ factor first
	if err = LQFactor(A, &taup, &Wred, conf); err != nil {
		return
	}
	if bits&gomas.WANTV != 0 {
		if m(V) == m(A) {
			V.Copy(A)
			if err = LQBuild(V, &taup, &Wred, m(A), conf); err != nil {
				return
			}
		} else {
			// V is N-by-N
			eye := cmat.FloatDiagonalSource{1.0}
			V.SetFrom(&eye, cmat.SYMM)
			if err = LQMult(V, A, &taup, &Wred, gomas.RIGHT, conf); err != nil {
				return
			}
		}
	}
	L.SubMatrix(A, 0, 0, m(A), m(A))
	cmat.TriL(&L, 0)

	// resize tauq/taup for UPPER bidiagonal reduction
	tauq.SetBuf(m(A), 1, m(A), W.Data())
	taup.SetBuf(m(A)-1, 1, m(A)-1, W.Data()[tauq.Len():])

	// bidiagonal reduce
	if err = BDReduce(&L, &tauq, &taup, &Wred, conf); err != nil {
		return
	}

	if bits&gomas.WANTV != 0 {
		Vm.SubMatrix(V, 0, 0, m(A), n(A))
		err = BDMult(&Vm, &L, &taup, &Wred, gomas.MULTP|gomas.LEFT|gomas.TRANS, conf)
		if err != nil {
			return
		}
		vv = V
	}
	if bits&gomas.WANTU != 0 {
		U.Copy(&L)
		if err = BDBuild(U, &tauq, &Wred, m(U), gomas.WANTQ, conf); err != nil {
			return
		}
		uu = U
	}

	sD.Diag(A)
	sE.Diag(A, 1)
	blasd.Copy(S, &sD)

	err = BDSvd(S, &sE, uu, vv, W, bits|gomas.UPPER, conf)
	return
}
예제 #12
0
파일: svd.go 프로젝트: hrautila/gomas
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
}
예제 #13
0
파일: svd.go 프로젝트: hrautila/gomas
// Compute SVD when m(A) >= n(A)
func svdTall(S, U, V, A, W *cmat.FloatMatrix, bits int, conf *gomas.Config) (err *gomas.Error) {
	var uu, vv *cmat.FloatMatrix
	var tauq, taup, Wred, sD, sE, R, Un cmat.FloatMatrix

	if (bits & (gomas.WANTU | gomas.WANTV)) != 0 {
		if W.Len() < 4*n(A) {
			err = gomas.NewError(gomas.ESIZE, "SVD")
			return
		}
	}
	tauq.SetBuf(n(A), 1, n(A), W.Data())
	taup.SetBuf(n(A)-1, 1, n(A)-1, W.Data()[tauq.Len():])
	wrl := W.Len() - 2*n(A) - 1
	Wred.SetBuf(wrl, 1, wrl, W.Data()[2*n(A)-1:])

	if svdCrossover(m(A), n(A)) {
		goto do_m_much_bigger
	}

	// reduce to bidiagonal form
	if err = BDReduce(A, &tauq, &taup, &Wred, conf); err != nil {
		return
	}

	sD.Diag(A)
	sE.Diag(A, 1)
	blasd.Copy(S, &sD)

	// left vectors
	if bits&gomas.WANTU != 0 {
		if n(U) == n(A) {
			// U is M-by-N; copy and make lower triangular
			U.Copy(A)
			cmat.TriL(U, 0)
			if err = BDBuild(U, &tauq, &Wred, n(U), gomas.WANTQ, conf); err != nil {
				return
			}
		} else {
			// U is M-by-M
			eye := cmat.FloatDiagonalSource{1.0}
			U.SetFrom(&eye, cmat.SYMM)
			if err = BDMult(U, A, &tauq, &Wred, gomas.MULTQ|gomas.RIGHT, conf); err != nil {
				return
			}
		}
		uu = U
	}
	// right vectors
	if bits&gomas.WANTV != 0 {
		R.SubMatrix(A, 0, 0, n(A), n(A))
		V.Copy(&R)
		cmat.TriU(V, 0)
		if err = BDBuild(V, &taup, &Wred, m(V), gomas.WANTP, conf); err != nil {
			return
		}
		vv = V
	}
	err = BDSvd(S, &sE, uu, vv, W, bits|gomas.UPPER)
	return

do_m_much_bigger:
	// M >> N here; first use QR factorization
	if err = QRFactor(A, &tauq, &Wred, conf); err != nil {
		return
	}
	if bits&gomas.WANTU != 0 {
		if n(U) == n(A) {
			U.Copy(A)
			if err = QRBuild(U, &tauq, &Wred, n(U), 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, &tauq, &Wred, gomas.LEFT, conf); err != nil {
				return
			}
		}
	}
	R.SubMatrix(A, 0, 0, n(A), n(A))
	cmat.TriU(&R, 0)

	// bidiagonal reduce
	if err = BDReduce(&R, &tauq, &taup, &Wred, conf); err != nil {
		return
	}

	if bits&gomas.WANTU != 0 {
		Un.SubMatrix(U, 0, 0, m(A), n(A))
		if err = BDMult(&Un, &R, &tauq, &Wred, gomas.MULTQ|gomas.RIGHT, conf); err != nil {
			return
		}
		uu = U
	}
	if bits&gomas.WANTV != 0 {
		V.Copy(&R)
		if err = BDBuild(V, &taup, &Wred, m(V), gomas.WANTP, conf); err != nil {
			return
		}
		vv = V
	}

	sD.Diag(A)
	sE.Diag(A, 1)
	blasd.Copy(S, &sD)

	err = BDSvd(S, &sE, uu, vv, W, bits|gomas.UPPER, conf)
	return
}