/* * 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 }
func TestSubMatrixGob(t *testing.T) { var B, As cmat.FloatMatrix var network bytes.Buffer N := 32 A := cmat.NewMatrix(N, N) zeromean := cmat.NewFloatNormSource() A.SetFrom(zeromean) As.SubMatrix(A, 3, 3, N-6, N-6) enc := gob.NewEncoder(&network) dec := gob.NewDecoder(&network) // encode to network err := enc.Encode(&As) if err != nil { t.Logf("encode error: %v\n", err) t.FailNow() } // decode from network err = dec.Decode(&B) if err != nil { t.Logf("decode error: %v\n", err) t.FailNow() } ar, ac := As.Size() br, bc := B.Size() t.Logf("As[%d,%d] == B[%d,%d]: %v\n", ar, ac, br, bc, B.AllClose(&As)) }
/* * Compute QL factorization of a M-by-N matrix A: A = Q * L. * * Arguments: * A On entry, the M-by-N matrix A, M >= N. On exit, lower triangular matrix L * and the orthogonal matrix Q as product of elementary reflectors. * * tau On exit, the scalar factors of the elemenentary reflectors. * * W Workspace, N-by-nb matrix used for work space in blocked invocations. * * conf The blocking configuration. If nil then default blocking configuration * is used. Member conf.LB defines blocking size of blocked algorithms. * If it is zero then unblocked algorithm is used. * * Returns: * Error indicator. * * Additional information * * Ortogonal matrix Q is product of elementary reflectors H(k) * * Q = H(K-1)...H(1)H(0), where K = min(M,N) * * Elementary reflector H(k) is stored on column k of A above the diagonal with * implicit unit value on diagonal entry. The vector TAU holds scalar factors * of the elementary reflectors. * * Contents of matrix A after factorization is as follow: * * ( v0 v1 v2 v3 ) for M=6, N=4 * ( v0 v1 v2 v3 ) * ( l v1 v2 v3 ) * ( l l v2 v3 ) * ( l l l v3 ) * ( l l l l ) * * where l is element of L, vk is element of H(k). * * DecomposeQL is compatible with lapack.DGEQLF */ func QLFactor(A, tau, W *cmat.FloatMatrix, confs ...*gomas.Config) *gomas.Error { var err *gomas.Error = nil var tauh cmat.FloatMatrix conf := gomas.CurrentConf(confs...) if m(A) < n(A) { return gomas.NewError(gomas.ESIZE, "QLFactor") } wsmin := wsQL(A, 0) if W == nil || W.Len() < wsmin { return gomas.NewError(gomas.EWORK, "QLFactor", wsmin) } if tau.Len() < n(A) { return gomas.NewError(gomas.ESIZE, "QLFactor") } tauh.SubMatrix(tau, 0, 0, n(A), 1) lb := estimateLB(A, W.Len(), wsQL) lb = imin(lb, conf.LB) if lb == 0 || n(A) <= lb { unblockedQL(A, &tauh, W) } else { var Twork, Wrk cmat.FloatMatrix // block reflector T in first LB*LB elements in workspace // the rest, n(A)-LB*LB, is workspace for intermediate matrix operands Twork.SetBuf(conf.LB, conf.LB, -1, W.Data()) Wrk.SetBuf(n(A)-conf.LB, conf.LB, -1, W.Data()[Twork.Len():]) blockedQL(A, &tauh, &Twork, &Wrk, lb, conf) } return err }
// test: min ||X|| s.t A.T*X = B func TestSolveQR(t *testing.T) { M := 799 N := 711 K := 241 nb := 32 conf := gomas.NewConf() conf.LB = nb tau := cmat.NewMatrix(N, 1) A := cmat.NewMatrix(M, N) src := cmat.NewFloatNormSource() A.SetFrom(src) A0 := cmat.NewCopy(A) B0 := cmat.NewMatrix(M, K) B0.SetFrom(src) B := cmat.NewCopy(B0) W := lapackd.Workspace(lapackd.QRFactorWork(A, conf)) lapackd.QRFactor(A, tau, W, conf) lapackd.QRSolve(B, A, tau, W, gomas.TRANS, conf) var Bmin cmat.FloatMatrix Bmin.SubMatrix(B0, 0, 0, N, K) blasd.Mult(&Bmin, A0, B, 1.0, -1.0, gomas.TRANSA, conf) nrm := lapackd.NormP(&Bmin, lapackd.NORM_ONE) t.Logf("M=%d, N=%d ||B - A.T*X||_1: %e\n", M, N, nrm) }
// test: min || B - A.T*X || func TestLeastSquaresLQ(t *testing.T) { M := 723 N := 811 K := 273 nb := 32 conf := gomas.NewConf() conf.LB = nb tau := cmat.NewMatrix(M, 1) A := cmat.NewMatrix(M, N) src := cmat.NewFloatNormSource() A.SetFrom(src) B0 := cmat.NewMatrix(M, K) B0.SetFrom(src) B := cmat.NewMatrix(N, K) // B = A.T*B0 blasd.Mult(B, A, B0, 1.0, 0.0, gomas.TRANSA, conf) W := lapackd.Workspace(lapackd.LQFactorWork(A, conf)) lapackd.LQFactor(A, tau, W, conf) // B' = A.-1*B lapackd.LQSolve(B, A, tau, W, gomas.TRANS, conf) // expect B[0:M,0:K] == B0[0:M,0:K], B[M:N,0:K] == 0 var X cmat.FloatMatrix X.SubMatrix(B, 0, 0, M, K) blasd.Plus(&X, B0, 1.0, -1.0, gomas.NONE) nrm := lapackd.NormP(&X, lapackd.NORM_ONE) t.Logf("M=%d, N=%d ||B0 - min( ||A.T*X - B0|| ) ||_1: %e\n", M, N, nrm) }
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) }
func TestSubMatrixJSON(t *testing.T) { var B, As cmat.FloatMatrix var network bytes.Buffer N := 26 A := cmat.NewMatrix(N, N) zeromean := cmat.NewFloatNormSource() A.SetFrom(zeromean) As.SubMatrix(A, 3, 3, N-6, N-6) enc := json.NewEncoder(&network) dec := json.NewDecoder(&network) // encode to network err := enc.Encode(&As) //t.Logf("bytes: %v\n", string(network.Bytes())) if err != nil { t.Logf("encode error: %v\n", err) t.FailNow() } // decode from network err = dec.Decode(&B) if err != nil { t.Logf("decode error: %v\n", err) t.FailNow() } t.Logf("As == B: %v\n", B.AllClose(&As)) }
/* * Merge 1 by 1 block from 2 by 1 block. * * AT * Abkl <-- -- * AB * */ func Merge2x1(ABLK, AT, AB *cmat.FloatMatrix) { tr, tc := AT.Size() br, _ := AB.Size() if tr > 0 { ABLK.SubMatrix(AT, 0, 0, tr+br, tc) } else { ABLK.SubMatrix(AB, 0, 0, br, tc) } }
/* * Merge 1 by 1 block from 1 by 2 block. * * ABLK <-- AL | AR * */ func Merge1x2(ABLK, AL, AR *cmat.FloatMatrix) { lr, lc := AL.Size() _, rc := AR.Size() if lc > 0 { ABLK.SubMatrix(AL, 0, 0, lr, lc+rc) } else { ABLK.SubMatrix(AR, 0, 0, lr, rc) } }
func test_bdsvd(N, flags, kind int, verbose bool, t *testing.T) { var At, sD, sE, tmp cmat.FloatMatrix uplo := "upper" offdiag := 1 if flags&gomas.LOWER != 0 { offdiag = -1 uplo = "lower" } A0 := cmat.NewMatrix(N, N) desc := setDiagonals(A0, offdiag, kind) At.SubMatrix(A0, 0, 0, N, N) sD.Diag(A0, 0) sE.Diag(A0, offdiag) D := cmat.NewCopy(&sD) E := cmat.NewCopy(&sE) // unit singular vectors U := cmat.NewMatrix(N, N) sD.Diag(U, 0) sD.Add(1.0) V := cmat.NewMatrix(N, N) sD.Diag(V, 0) sD.Add(1.0) W := cmat.NewMatrix(4*N, 1) C := cmat.NewMatrix(N, N) lapackd.BDSvd(D, E, U, V, W, flags|gomas.WANTU|gomas.WANTV) blasd.Mult(C, U, U, 1.0, 0.0, gomas.TRANSA) sD.Diag(C) sD.Add(-1.0) nrmu := lapackd.NormP(C, lapackd.NORM_ONE) blasd.Mult(C, V, V, 1.0, 0.0, gomas.TRANSB) sD.Add(-1.0) nrmv := lapackd.NormP(C, lapackd.NORM_ONE) blasd.Mult(C, U, A0, 1.0, 0.0, gomas.TRANSA) blasd.Mult(&At, C, V, 1.0, 0.0, gomas.TRANSB) if verbose && N < 10 { t.Logf("D:\n%v\n", asRow(&tmp, D)) t.Logf("U:\n%v\n", U) t.Logf("V:\n%v\n", V) t.Logf("U.T*A*V\n%v\n", &At) } sD.Diag(&At) blasd.Axpy(&sD, D, -1.0) nrma := lapackd.NormP(&At, lapackd.NORM_ONE) t.Logf("N=%d [%s,%s] ||U.T*A*V - bdsvd(A)||_1: %e\n", N, uplo, desc, nrma) t.Logf(" ||I - U.T*U||_1: %e\n", nrmu) t.Logf(" ||I - V.T*V||_1: %e\n", nrmv) }
func swapCols(A *cmat.FloatMatrix, src, dst int) { var c0, c1 cmat.FloatMatrix ar, _ := A.Size() if src == dst || ar == 0 { return } c0.SubMatrix(A, 0, src, ar, 1) c1.SubMatrix(A, 0, dst, ar, 1) blasd.Swap(&c0, &c1) }
func swapRows(A *cmat.FloatMatrix, src, dst int) { var r0, r1 cmat.FloatMatrix ar, ac := A.Size() if src == dst || ar == 0 { return } r0.SubMatrix(A, src, 0, 1, ac) r1.SubMatrix(A, dst, 0, 1, ac) blasd.Swap(&r0, &r1) }
// Compute: (I - Y*T*Y.T).T*C = C - Y*(C.T*Y*T) func updateHessLeftWY(C, Y1, Y2, T, V *cmat.FloatMatrix, conf *gomas.Config) { var C1, C2 cmat.FloatMatrix if C.Len() == 0 { return } C1.SubMatrix(C, 1, 0, m(Y1), n(C)) C2.SubMatrix(C, 1+n(Y1), 0, m(Y2), n(C)) updateWithQTLeft(&C1, &C2, Y1, Y2, T, V, true, conf) }
// Compute: C*(I - Y*T*Y.T) = C - C*Y*T*Y.T = C - V*T*Y.T func updateHessRightWY(C, Y1, Y2, T, W *cmat.FloatMatrix, conf *gomas.Config) { var C1, C2 cmat.FloatMatrix if C.Len() == 0 { return } C1.SubMatrix(C, 0, 1, m(C), n(Y1)) C2.SubMatrix(C, 0, 1+n(Y1), m(C), m(Y2)) updateWithQTRight(&C1, &C2, Y1, Y2, T, W, false, conf) }
/* * Build block reflector for QL factorized matrix. */ func QLReflector(T, A, tau *cmat.FloatMatrix, confs ...*gomas.Config) *gomas.Error { var tauh cmat.FloatMatrix if n(T) < n(A) || m(T) < n(A) { return gomas.NewError(gomas.ESIZE, "QLReflector") } tauh.SubMatrix(tau, 0, 0, imin(m(A), n(A)), 1) unblkQLBlockReflector(T, A, &tauh) return nil }
/* * Unblocked QR decomposition with block reflector T. */ func unblockedQRT(A, T, W *cmat.FloatMatrix) *gomas.Error { var err *gomas.Error = nil var ATL, ATR, ABL, ABR cmat.FloatMatrix var A00, a10, a11, a12, A20, a21, A22 cmat.FloatMatrix var TTL, TTR, TBL, TBR cmat.FloatMatrix var T00, t01, T02, t11, t12, T22, w12 cmat.FloatMatrix util.Partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, util.PTOPLEFT) util.Partition2x2( &TTL, &TTR, &TBL, &TBR, T, 0, 0, util.PTOPLEFT) for m(&ABR) > 0 && n(&ABR) > 0 { util.Repartition2x2to3x3(&ATL, &A00, nil, nil, &a10, &a11, &a12, &A20, &a21, &A22, A, 1, util.PBOTTOMRIGHT) util.Repartition2x2to3x3(&TTL, &T00, &t01, &T02, nil, &t11, &t12, nil, nil, &T22, T, 1, util.PBOTTOMRIGHT) // ------------------------------------------------------ computeHouseholder(&a11, &a21, &t11) // H*[a12 A22].T w12.SubMatrix(W, 0, 0, a12.Len(), 1) applyHouseholder2x1(&t11, &a21, &a12, &A22, &w12, gomas.LEFT) // update T tauval := t11.Get(0, 0) if tauval != 0.0 { // t01 := -tauval*(a10.T + &A20.T*a21) //a10.CopyTo(&t01) blasd.Axpby(&t01, &a10, 1.0, 0.0) blasd.MVMult(&t01, &A20, &a21, -tauval, -tauval, gomas.TRANSA) // t01 := T00*t01 blasd.MVMultTrm(&t01, &T00, 1.0, gomas.UPPER) } // ------------------------------------------------------ util.Continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, util.PBOTTOMRIGHT) util.Continue3x3to2x2( &TTL, &TTR, &TBL, &TBR, &T00, &t11, &T22, T, util.PBOTTOMRIGHT) } return err }
/* * 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) } }
/* * 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) } }
func test_trdevd(N, flags, kind int, verbose bool, t *testing.T) { var At, sD, sE, tmp cmat.FloatMatrix A0 := cmat.NewMatrix(N, N) desc := setTrdDiagonals(A0, kind) At.SubMatrix(A0, 0, 0, N, N) sD.Diag(A0, 0) sE.Diag(A0, 1) D := cmat.NewCopy(&sD) E := cmat.NewCopy(&sE) V := cmat.NewMatrix(N, N) sD.Diag(V, 0) sD.Add(1.0) W := cmat.NewMatrix(4*N, 1) C := cmat.NewMatrix(N, N) if verbose && N < 10 { t.Logf("A0:\n%v\n", A0.ToString("%6.3f")) t.Logf("V.pre:\n%v\n", V.ToString("%6.3f")) } lapackd.TRDEigen(D, E, V, W, flags|gomas.WANTV) for k := 0; k < N-1; k++ { if E.GetAt(k) != 0.0 { t.Logf("E[%d] != 0.0 (%e)\n", k, E.GetAt(k)) } } blasd.Mult(C, V, V, 1.0, 0.0, gomas.TRANSB) sD.Diag(C) sD.Add(-1.0) nrmv := lapackd.NormP(C, lapackd.NORM_ONE) blasd.Mult(C, V, A0, 1.0, 0.0, gomas.TRANSA) blasd.Mult(&At, C, V, 1.0, 0.0, gomas.NONE) if verbose && N < 10 { t.Logf("D:\n%v\n", asRow(&tmp, D).ToString("%6.3f")) t.Logf("V:\n%v\n", V.ToString("%6.3f")) t.Logf("V.T*A*V\n%v\n", At.ToString("%6.3f")) } sD.Diag(&At) blasd.Axpy(&sD, D, -1.0) nrma := lapackd.NormP(&At, lapackd.NORM_ONE) t.Logf("N=%d [%s] ||V.T*A*V - eigen(A)||_1: %e\n", N, desc, nrma) t.Logf(" ||I - V.T*V||_1: %e\n", nrmv) }
func blockedQRT(A, T, W *cmat.FloatMatrix, conf *gomas.Config) *gomas.Error { var err *gomas.Error = nil var ATL, ATR, ABL, ABR, AL, AR cmat.FloatMatrix var A00, A01, A02, A10, A11, A12, A20, A21, A22 cmat.FloatMatrix var TL, TR, W2 cmat.FloatMatrix var T00, T01, T02 cmat.FloatMatrix util.Partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, util.PTOPLEFT) util.Partition1x2( &TL, &TR, T, 0, util.PLEFT) nb := conf.LB for m(&ABR)-nb > 0 && n(&ABR)-nb > 0 { util.Repartition2x2to3x3(&ATL, &A00, &A01, &A02, &A10, &A11, &A12, &A20, &A21, &A22, A, nb, util.PBOTTOMRIGHT) util.Repartition1x2to1x3(&TL, &T00, &T01, &T02, T, nb, util.PRIGHT) util.Partition1x2( &AL, &AR, &ABR, nb, util.PLEFT) // -------------------------------------------------------- // decompose left side AL == /A11\ // \A21/ unblockedQRT(&AL, &T01, W) // update A'tail i.e. A12 and A22 with (I - Y*T*Y.T).T * A'tail // compute: Q*T.C == C - Y*(C.T*Y*T).T ar, ac := A12.Size() W2.SubMatrix(W, 0, 0, ac, ar) updateWithQTLeft(&A12, &A22, &A11, &A21, &T01, &W2, true, conf) // -------------------------------------------------------- util.Continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &A11, &A22, A, util.PBOTTOMRIGHT) util.Continue1x3to1x2( &TL, &TR, &T00, &T01, T, util.PRIGHT) } if m(&ABR) > 0 && n(&ABR) > 0 { T01.SubMatrix(&TR, 0, 0, n(&ABR), n(&ABR)) unblockedQRT(&ABR, &T01, W) } return err }
// 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) }
func TestViews(t *testing.T) { var As cmat.FloatMatrix N := 7 A := cmat.NewMatrix(N, N) zeromean := cmat.NewFloatNormSource() A.SetFrom(zeromean) dlast := A.Get(-1, -1) t.Logf("A[-1,-1] = %10.3e\n", dlast) for i := 0; i < N; i++ { As.SubMatrix(A, i, i) As.Set(0, 0, As.Get(0, 0)+float64(i+1)) if N < 10 { t.Logf("A[%d,%d] = %10.3e\n", i, i, As.Get(0, 0)) } } ok := float64(N)+dlast == A.Get(-1, -1) nC := int(A.Get(-1, -1) - dlast) t.Logf("add 1.0 %d times [%10.3e to %10.3e]: %v\n", nC, dlast, A.Get(-1, -1), ok) }
/* * 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 }
func computeHouseholderRev(x, tau *cmat.FloatMatrix) { var alpha, x2 cmat.FloatMatrix r, _ := x.Size() if r == 1 { alpha.SubMatrix(x, 0, -1, 1, 1) x2.SubMatrix(x, 0, 0, 1, x.Len()-1) // row vector } else { alpha.SubMatrix(x, -1, 0, 1, 1) x2.SubMatrix(x, 0, 0, x.Len()-1, 1) } computeHouseholder(&alpha, &x2, tau) }
/* * Continue with 2 by 1 block from 3 by 1 block. * * AT A0 AT A0 * pBOTTOM: -- <-- A1 ; pTOP: -- <-- -- * AB -- AB A1 * A2 A2 */ func Continue3x1to2x1(AT, AB, A0, A1, A *cmat.FloatMatrix, pdir Direction) { ar, ac := A.Size() n0, _ := A0.Size() n1, _ := A1.Size() switch pdir { case PBOTTOM: AT.SubMatrix(A, 0, 0, n0+n1, ac) AB.SubMatrix(A, n0+n1, 0, ar-n0-n1, ac) case PTOP: AT.SubMatrix(A, 0, 0, n0, ac) AB.SubMatrix(A, n0, 0, ar-n0, ac) } }
/* * Partition p to 2 by 1 blocks. * * AT * A --> -- * AB * * Parameter nb is initial block size for AT (pTOP) or AB (pBOTTOM). */ func Partition2x1(AT, AB, A *cmat.FloatMatrix, nb int, side Direction) { ar, ac := A.Size() if nb > ar { nb = ar } switch side { case PTOP: AT.SubMatrix(A, 0, 0, nb, ac) AB.SubMatrix(A, nb, 0, ar-nb, ac) case PBOTTOM: AT.SubMatrix(A, 0, 0, ar-nb, ac) AB.SubMatrix(A, ar-nb, 0, nb, ac) } }
/* * Partition A to 1 by 2 blocks. * * A --> AL | AR * * Parameter nb is initial block size for AL (pLEFT) or AR (pRIGHT). */ func Partition1x2(AL, AR, A *cmat.FloatMatrix, nb int, side Direction) { ar, ac := A.Size() if nb > ac { nb = ac } switch side { case PLEFT: AL.SubMatrix(A, 0, 0, ar, nb) AR.SubMatrix(A, 0, nb, ar, ac-nb) case PRIGHT: AL.SubMatrix(A, 0, 0, ar, ac-nb) AR.SubMatrix(A, 0, ac-nb, ar, nb) } }
// test: min || B - A*X || func TestLeastSquaresQR(t *testing.T) { M := 811 N := 723 K := 311 nb := 32 conf := gomas.NewConf() conf.LB = nb tau := cmat.NewMatrix(N, 1) A := cmat.NewMatrix(M, N) src := cmat.NewFloatNormSource() A.SetFrom(src) B0 := cmat.NewMatrix(N, K) B0.SetFrom(src) B := cmat.NewMatrix(M, K) // B = A*B0 blasd.Mult(B, A, B0, 1.0, 0.0, gomas.NONE, conf) W := lapackd.Workspace(lapackd.QRFactorWork(A, conf)) err := lapackd.QRFactor(A, tau, W, conf) if err != nil { t.Logf("DecomposeQR: %v\n", err) } // B' = A.-1*B err = lapackd.QRSolve(B, A, tau, W, gomas.NONE, conf) if err != nil { t.Logf("SolveQR: %v\n", err) } // expect B[0:N,0:K] == B0[0:N,0:K], B[N:M,0:K] == 0 var X cmat.FloatMatrix X.SubMatrix(B, 0, 0, N, K) blasd.Plus(&X, B0, 1.0, -1.0, gomas.NONE) nrm := lapackd.NormP(&X, lapackd.NORM_ONE) t.Logf("M=%d, N=%d ||B0 - min( ||A*X - B0|| ) ||_1: %e\n", M, N, nrm) }
/* * Blocked LQ decomposition with compact WY transform. As implemented * in lapack.DGELQF subroutine. */ func blockedLQ(A, Tvec, Twork, W *cmat.FloatMatrix, lb int, conf *gomas.Config) { var ATL, ATR, ABL, ABR, AR cmat.FloatMatrix var A00, A11, A12, A21, A22 cmat.FloatMatrix var TT, TB cmat.FloatMatrix var t0, tau, t2 cmat.FloatMatrix var Wrk, w1 cmat.FloatMatrix util.Partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, util.PTOPLEFT) util.Partition2x1( &TT, &TB, Tvec, 0, util.PTOP) //nb := conf.LB for m(&ABR)-lb > 0 && n(&ABR)-lb > 0 { util.Repartition2x2to3x3(&ATL, &A00, nil, nil, nil, &A11, &A12, nil, &A21, &A22, A, lb, util.PBOTTOMRIGHT) util.Repartition2x1to3x1(&TT, &t0, &tau, &t2, Tvec, lb, util.PBOTTOM) // current block size cb, rb := A11.Size() if rb < cb { cb = rb } // -------------------------------------------------------- // decompose left side AL == /A11\ // \A21/ w1.SubMatrix(W, 0, 0, cb, 1) util.Merge1x2(&AR, &A11, &A12) unblockedLQ(&AR, &tau, &w1) // build block reflector unblkBlockReflectorLQ(Twork, &AR, &tau) // update A'tail i.e. A21 and A22 with A'*(I - Y*T*Y.T).T // compute: C - Y*(C.T*Y*T).T ar, ac := A21.Size() Wrk.SubMatrix(W, 0, 0, ar, ac) updateRightLQ(&A21, &A22, &A11, &A12, Twork, &Wrk, true, conf) // -------------------------------------------------------- util.Continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &A11, &A22, A, util.PBOTTOMRIGHT) util.Continue3x1to2x1( &TT, &TB, &t0, &tau, Tvec, util.PBOTTOM) } // last block with unblocked if m(&ABR) > 0 && n(&ABR) > 0 { w1.SubMatrix(W, 0, 0, m(&ABR), 1) unblockedLQ(&ABR, &t2, &w1) } }
/* * Blocked QR decomposition with compact WY transform. * * Compatible with lapack.DGEQRF. */ func blockedQL(A, Tvec, Twork, W *cmat.FloatMatrix, lb int, conf *gomas.Config) { var ATL, ATR, ABL, ABR, AL cmat.FloatMatrix var A00, A01, A10, A11, A22 cmat.FloatMatrix var TT, TB cmat.FloatMatrix var t0, tau, t2 cmat.FloatMatrix var Wrk, w1 cmat.FloatMatrix util.Partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, util.PBOTTOMRIGHT) util.Partition2x1( &TT, &TB, Tvec, 0, util.PBOTTOM) nb := lb for m(&ATL)-nb > 0 && n(&ATL)-nb > 0 { util.Repartition2x2to3x3(&ATL, &A00, &A01, nil, &A10, &A11, nil, nil, nil, &A22, A, nb, util.PTOPLEFT) util.Repartition2x1to3x1(&TT, &t0, &tau, &t2, Tvec, nb, util.PTOP) // current block size cb, rb := A11.Size() if rb < cb { cb = rb } // -------------------------------------------------------- // decompose righ side AL == /A01\ // \A11/ w1.SubMatrix(W, 0, 0, cb, 1) util.Merge2x1(&AL, &A01, &A11) unblockedQL(&AL, &tau, &w1) // build block reflector unblkQLBlockReflector(Twork, &AL, &tau) // update A'tail i.e. A10 and A00 with (I - Y*T*Y.T).T * A'tail // compute: C - Y*(C.T*Y*T).T ar, ac := A10.Size() Wrk.SubMatrix(W, 0, 0, ac, ar) updateQLLeft(&A10, &A00, &A11, &A01, Twork, &Wrk, true, conf) // -------------------------------------------------------- util.Continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &A11, &A22, A, util.PTOPLEFT) util.Continue3x1to2x1( &TT, &TB, &t0, &tau, Tvec, util.PTOP) } // last block with unblocked if m(&ATL) > 0 && n(&ATL) > 0 { w1.SubMatrix(W, 0, 0, n(&ATL), 1) unblockedQL(&ATL, &t0, &w1) } }