// unblocked LU decomposition w/o pivots, FLAME LU nopivots variant 5 func unblockedLUnoPiv(A *matrix.FloatMatrix) (err error) { var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a10, a11, a12, A20, a21, A22 matrix.FloatMatrix err = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) for ATL.Rows() < A.Rows() { repartition2x2to3x3(&ATL, &A00, &a01, &A02, &a10, &a11, &a12, &A20, &a21, &A22, A, 1, pBOTTOMRIGHT) // a21 = a21/a11 //a21.Scale(1.0/a11.Float()) InvScale(&a21, a11.Float()) // A22 = A22 - a21*a12 err = MVRankUpdate(&A22, &a21, &a12, -1.0) continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) } return }
// Inverse NON-UNIT diagonal tridiagonal matrix func unblockedInverseLower(A *matrix.FloatMatrix) (err error) { var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a10t, a11, A20, a21, A22 matrix.FloatMatrix err = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) for ATL.Rows() < A.Rows() { repartition2x2to3x3(&ATL, &A00, nil, nil, &a10t, &a11, nil, &A20, &a21, &A22, A, 1, pBOTTOMRIGHT) // ------------------------------------------------- aval := a11.Float() // a21 = -a21/a11 InvScale(&a21, -aval) // A20 = A20 + a21*a10.t MVRankUpdate(&A20, &a21, &a10t, 1.0) // a10 = a10/a11 InvScale(&a10t, aval) // a11 = 1.0/a11 a11.SetAt(0, 0, 1.0/aval) // ------------------------------------------------- continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) } return }
// Inverse NON-UNIT diagonal tridiagonal matrix func unblockedInverseUpper(A *matrix.FloatMatrix) (err error) { var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a11, a12t, A22 matrix.FloatMatrix err = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) for ATL.Rows() < A.Rows() { repartition2x2to3x3(&ATL, &A00, &a01, &A02, nil, &a11, &a12t, nil, nil, &A22, A, 1, pBOTTOMRIGHT) // ------------------------------------------------- aval := a11.Float() // a12 = -a12/a11 InvScale(&a12t, -aval) // A02 = A02 + a01*a12 MVRankUpdate(&A02, &a01, &a12t, 1.0) // a01 = a01/a11 InvScale(&a01, aval) // a11 = 1.0/a11 a11.SetAt(0, 0, 1.0/aval) // ------------------------------------------------- continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) } return }
func _TestViewUpdate(t *testing.T) { Adata2 := [][]float64{ []float64{4.0, 2.0, 2.0}, []float64{6.0, 4.0, 2.0}, []float64{4.0, 6.0, 1.0}, } A := matrix.FloatMatrixFromTable(Adata2, matrix.RowOrder) N := A.Rows() // simple LU decomposition without pivoting var A11, a10, a01, a00 matrix.FloatMatrix for k := 1; k < N; k++ { a00.SubMatrixOf(A, k-1, k-1, 1, 1) a01.SubMatrixOf(A, k-1, k, 1, A.Cols()-k) a10.SubMatrixOf(A, k, k-1, A.Rows()-k, 1) A11.SubMatrixOf(A, k, k) //t.Logf("A11: %v a01: %v\n", A11, a01) a10.Scale(1.0 / a00.Float()) MVRankUpdate(&A11, &a10, &a01, -1.0) } Ld := TriLU(A.Copy()) Ud := TriU(A) t.Logf("Ld:\n%v\nUd:\n%v\n", Ld, Ud) An := matrix.FloatZeros(N, N) Mult(An, Ld, Ud, 1.0, 1.0, NOTRANS) t.Logf("A == Ld*Ud: %v\n", An.AllClose(An)) }
/* * ( A11 a12 ) ( U11 u12 )( D1 0 )( U11.t 0 ) * ( a21 a22 ) ( 0 1 )( 0 d2 )( u12.t 1 ) * * a22 = d2 * a01 = u12*d2 => u12 = a12/d2 * A11 = u12*d2*u12.t + U11*D1*U11.t => U11 = A11 - u12*d2*u12.t */ func unblkUpperLDLnoPiv(A *matrix.FloatMatrix) (err error) { var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a11, a12, A22 matrix.FloatMatrix err = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pBOTTOMRIGHT) for ATL.Rows() > 0 { repartition2x2to3x3(&ATL, &A00, &a01, &A02, nil, &a11, &a12, nil, nil, &A22, A, 1, pTOPLEFT) // -------------------------------------------------------- // A00 = A00 - u01*d11*u01.T = A00 - a01*a01.T/a11; triangular update err = MVUpdateTrm(&A00, &a01, &a01, -1.0/a11.Float(), UPPER) // u01 = a01/a11 InvScale(&a01, a11.Float()) // --------------------------------------------------------- continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pTOPLEFT) } return }
/* * ( a11 a12 ) ( 1 0 )( d1 0 )( l l21.t ) * ( a21 A22 ) ( l21 L22 )( 0 A22 )( 0 L22.t ) * * a11 = d1 * a21 = l21*d1 => l21 = a21/d1 * A22 = l21*d1*l21.t + L22*D2*L22.t => L22 = A22 - l21*d1*l21t */ func unblkLowerLDLnoPiv(A *matrix.FloatMatrix) (err error) { var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a10, a11, A20, a21, A22 matrix.FloatMatrix err = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) for ATL.Rows() < A.Rows() { repartition2x2to3x3(&ATL, &A00, nil, nil, &a10, &a11, nil, &A20, &a21, &A22, A, 1, pBOTTOMRIGHT) // -------------------------------------------------------- // d11 = a11; no-op // A22 = A22 - l21*d11*l21.T = A22 - a21*a21.T/a11; triangular update err = MVUpdateTrm(&A22, &a21, &a21, -1.0/a11.Float(), LOWER) // l21 = a21/a11 InvScale(&a21, a11.Float()) // --------------------------------------------------------- continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) } return }
func _TestPartition1Dh(t *testing.T) { var AL, AR, A0, a1, A2 matrix.FloatMatrix A := matrix.FloatZeros(1, 6) partition1x2(&AL, &AR, A, 0, pRIGHT) t.Logf("m(AL)=%d, m(AR)=%d\n", AL.Cols(), AR.Cols()) for AL.Cols() < A.Cols() { AR.Add(1.0) t.Logf("m(AR)=%d; %v\n", AR.Cols(), AR) repartition1x2to1x3(&AL, &A0, &a1, &A2, A, 1, pRIGHT) t.Logf("m(A0)=%d, m(A2)=%d, a1=%.1f\n", A0.Cols(), A2.Cols(), a1.Float()) continue1x3to1x2(&AL, &AR, &A0, &a1, A, pRIGHT) } }
/* * ( A11 a12 ) ( U11 u12 )( D1 0 )( U11.t 0 ) * ( a21 a22 ) ( 0 1 )( 0 d2 )( u12.t 1 ) * * a22 = d2 * a01 = u12*d2 => u12 = a12/d2 * A11 = u12*d2*u12.t + U11*D1*U11.t => U11 = A11 - u12*d2*u12.t */ func unblkUpperLDL(A *matrix.FloatMatrix, p *pPivots) (err error) { var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a11, a12, A22 matrix.FloatMatrix var AL, AR, acol matrix.FloatMatrix var pT, pB, p0, p1, p2 pPivots err = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pBOTTOMRIGHT) partitionPivot2x1( &pT, &pB, p, 0, pBOTTOM) for ATL.Rows() > 0 { repartition2x2to3x3(&ATL, &A00, &a01, &A02, nil, &a11, &a12, nil, nil, &A22, A, 1, pTOPLEFT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, 1, pTOP) // -------------------------------------------------------- // search diagonal; diag(A00;a11) ATL.Diag(&acol) //merge2x1(&acol, &a01, &a11) imax := IAMax(&acol) if imax < ATL.Rows()-1 { merge1x2(&AL, &ATL, &ATR) merge1x2(&AR, &a11, &a12) // pivot diagonal in symmetric matrix; will swap a11 and [imax,imax] applyPivotSym(&AL, &AR, imax, UPPER) p1.pivots[0] = imax + 1 } else { p1.pivots[0] = 0 } if a11.Float() == 0.0 { err = onError("zero on diagonal.") return } // A00 = A00 - u01*d11*u01.T = A00 - a01*a01.T/a11; triangular update err = MVUpdateTrm(&A00, &a01, &a01, -1.0/a11.Float(), UPPER) // u01 = a01/a11 InvScale(&a01, a11.Float()) // --------------------------------------------------------- continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pTOPLEFT) contPivot3x1to2x1( &pT, &pB, &p0, &p1, p, pTOP) } return }
func unblockedCHOL(A *matrix.FloatMatrix, flags Flags, nr int) (err error) { var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a10, a11, a12, A20, a21, A22 matrix.FloatMatrix err = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) for ATL.Rows() < A.Rows() { repartition2x2to3x3(&ATL, &A00, &a01, &A02, &a10, &a11, &a12, &A20, &a21, &A22, A, 1, pBOTTOMRIGHT) // a11 = sqrt(a11) aval := math.Sqrt(a11.Float()) if math.IsNaN(aval) { panic(fmt.Sprintf("illegal value at %d: %e", nr+ATL.Rows(), a11.Float())) } a11.SetAt(0, 0, aval) if flags&LOWER != 0 { // a21 = a21/a11 InvScale(&a21, a11.Float()) // A22 = A22 - a21*a21' (SYR) err = MVRankUpdateSym(&A22, &a21, -1.0, flags) } else { // a21 = a12/a11 InvScale(&a12, a11.Float()) // A22 = A22 - a12'*a12 (SYR) err = MVRankUpdateSym(&A22, &a12, -1.0, flags) } continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) } return }
func unblkBoundedBKUpper(A, wrk *matrix.FloatMatrix, p *pPivots, ncol int) (error, int) { var err error var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a11, a12t, A22, a11inv matrix.FloatMatrix var w00, w01, w11 matrix.FloatMatrix var cwrk matrix.FloatMatrix var wx, Ax, wz matrix.FloatMatrix var pT, pB, p0, p1, p2 pPivots err = nil nc := 0 if ncol > A.Cols() { ncol = A.Cols() } partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pBOTTOMRIGHT) partitionPivot2x1( &pT, &pB, p, 0, pBOTTOM) // permanent working space for symmetric inverse of a11 wrk.SubMatrix(&a11inv, wrk.Rows()-2, 0, 2, 2) a11inv.SetAt(0, 1, -1.0) a11inv.SetAt(1, 0, -1.0) for ATL.Cols() > 0 && nc < ncol { partition2x2( &w00, &w01, nil, &w11, wrk, nc, nc, pBOTTOMRIGHT) merge1x2(&wx, &w00, &w01) merge1x2(&Ax, &ATL, &ATR) //fmt.Printf("ATL:\n%v\n", &ATL) r, np := findAndBuildBKPivotUpper(&ATL, &ATR, &w00, &w01, nc) //fmt.Printf("[w00;w01]:\n%v\n", &wx) //fmt.Printf("after find: r=%d, np=%d, ncol=%d, nc=%d\n", r, np, ncol, nc) w00.SubMatrix(&wz, 0, w00.Cols()-2, w00.Rows(), 2) if np > ncol-nc { // next pivot does not fit into ncol columns, restore last column, // return with number of factorized columns return err, nc } if r != -1 { // pivoting needed; np == 1, last row; np == 2; next to last rows nrow := ATL.Rows() - np applyBKPivotSym(&ATL, nrow, r, UPPER) // swap left hand rows to get correct updates swapRows(&ATR, nrow, r) swapRows(&w01, nrow, r) if np == 2 { /* pivot block on diagonal; -1,-1 * [r, r] | [r ,-1] * ---------------- 2-by-2 pivot, swapping [1,0] and [r,0] * [r,-1] | [-1,-1] */ t0 := w00.GetAt(-2, -1) tr := w00.GetAt(r, -1) //fmt.Printf("nc=%d, t0=%e, tr=%e\n", nc, t0, tr) w00.SetAt(-2, -1, tr) w00.SetAt(r, -1, t0) // interchange diagonal entries on w11[:,1] t0 = w00.GetAt(-2, -2) tr = w00.GetAt(r, -2) w00.SetAt(-2, -2, tr) w00.SetAt(r, -2, t0) //fmt.Printf("wrk:\n%v\n", &wz) } //fmt.Printf("pivoted A:\n%v\n", &Ax) //fmt.Printf("pivoted wrk:\n%v\n", &wx) } // repartition according the pivot size repartition2x2to3x3(&ATL, &A00, &a01, &A02, nil, &a11, &a12t, nil, nil, &A22 /**/, A, np, pTOPLEFT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, np, pTOP) // ------------------------------------------------------------ wlc := w00.Cols() - np //wlr := w00.Rows() - 1 w00.SubMatrix(&cwrk, 0, wlc, a01.Rows(), np) if np == 1 { //fmt.Printf("wz:\n%v\n", &wz) //fmt.Printf("a11 <-- %e\n", w00.GetAt(a01.Rows(), wlc)) //w00.SubMatrix(&cwrk, 0, wlc-np+1, a01.Rows(), np) a11.SetAt(0, 0, w00.GetAt(a01.Rows(), wlc)) // a21 = a21/a11 //fmt.Printf("np == 1: pre-update a01\n%v\n", &a01) cwrk.CopyTo(&a01) InvScale(&a01, a11.Float()) //fmt.Printf("np == 1: cwrk\n%v\na21\n%v\n", &cwrk, &a21) // store pivot point relative to original matrix if r == -1 { p1.pivots[0] = ATL.Rows() } else { p1.pivots[0] = r + 1 } } else if np == 2 { /* d | b * w00 == ------ * . | a */ a := w00.GetAt(-1, -1) b := w00.GetAt(-2, -1) d := w00.GetAt(-2, -2) a11inv.SetAt(1, 1, d/b) a11inv.SetAt(0, 0, a/b) // denominator: (a/b)*(d/b)-1.0 == (a*d - b^2)/b^2 scale := 1.0 / ((a/b)*(d/b) - 1.0) scale /= b //fmt.Printf("a11inv:\n%v\n", &a11inv) // a01 = a01*a11.-1 Mult(&a01, &cwrk, &a11inv, scale, 0.0, NOTRANS) a11.SetAt(1, 1, a) a11.SetAt(0, 1, b) a11.SetAt(0, 0, d) // store pivot point relative to original matrix p1.pivots[0] = -(r + 1) p1.pivots[1] = p1.pivots[0] } //fmt.Printf("end-of-loop: Ax r=%d, nc=%d. np=%d\n%v\n", r, nc, np, &Ax) //fmt.Printf("wx m(wblk)=%d:\n%v\n", m(&wx), &wx) // ------------------------------------------------------------ nc += np continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pTOPLEFT) contPivot3x1to2x1( &pT, &pB, &p0, &p1, p, pTOP) } return err, nc }
func unblkBoundedLowerLDL(A, W *matrix.FloatMatrix, p *pPivots, ncol int) (error, int) { var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a10, a11, A20, a21, A22, adiag, wcol matrix.FloatMatrix var w00, w10, w11 matrix.FloatMatrix var pT, pB, p0, p1, p2 pPivots var err error = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) partitionPivot2x1( &pT, &pB, p, 0, pTOP) // copy current diagonal to last column of workspace W.SubMatrix(&wcol, 0, W.Cols()-1, A.Rows(), 1) A.Diag(&adiag) adiag.CopyTo(&wcol) //fmt.Printf("initial diagonal:\n%v\n", &wcol) nc := 0 for ABR.Cols() > 0 && nc < ncol { partition2x2( &w00, nil, &w10, &w11, W, nc, nc, pTOPLEFT) dmax := findAndBuildPivot(&ABL, &ABR, &w10, &w11, nc) //fmt.Printf("dmax=%d\n", dmax) if dmax > 0 { // pivot diagonal in symmetric matrix; will swap a11 [0,0] and [imax,imax] applyPivotSym(&ABL, &ABR, dmax, LOWER) swapRows(&w10, 0, dmax) pB.pivots[0] = dmax + ATL.Rows() + 1 } else { pB.pivots[0] = 0 } //fmt.Printf("blk pivoted %d, A:\n%v\nW:\n%v\n", dmax, A, W) repartition2x2to3x3(&ATL, &A00, nil, nil, &a10, &a11, nil, &A20, &a21, &A22, A, 1, pBOTTOMRIGHT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, 1, pBOTTOM) // -------------------------------------------------------- // Copy updated column from working space w11.SubMatrix(&wcol, 1, 0, a21.Rows(), 1) wcol.CopyTo(&a21) a11.SetAt(0, 0, w11.GetAt(0, 0)) // l21 = a21/a11 InvScale(&a21, a11.Float()) // here: wcol == l21*d11 == a21 if ncol-nc > 1 { // update diagonal in workspace if not last column of block w11.SubMatrix(&adiag, 1, w11.Cols()-1, a21.Rows(), 1) MVUpdateDiag(&adiag, &wcol, &wcol, -1.0/a11.Float()) } //fmt.Printf("nc=%d, a11=%e\n", nc, a11.Float()) //fmt.Printf("l21\n%v\n", &a21) //fmt.Printf("a21\n%v\n", &wcol) //fmt.Printf("diag\n%v\n", &adiag) //var Ablk, wblk matrix.FloatMatrix //merge1x2(&Ablk, &ABL, &ABR) //merge1x2(&wblk, &w10, &w11) //fmt.Printf("unblk Ablk:\n%v\n", &Ablk) //fmt.Printf("unblk wblk:\n%v\n", &wblk) // --------------------------------------------------------- nc++ continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) contPivot3x1to2x1( &pT, &pB, &p0, &p1, p, pBOTTOM) } return err, nc }
/* * Unblocked Bunch-Kauffman LDL factorization. * * Corresponds lapack.DSYTF2 */ func unblkDecompBKUpper(A, wrk *matrix.FloatMatrix, p *pPivots) (error, int) { var err error var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a12t, a11, A22, a11inv matrix.FloatMatrix var cwrk matrix.FloatMatrix var pT, pB, p0, p1, p2 pPivots err = nil nc := 0 partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pBOTTOMRIGHT) partitionPivot2x1( &pT, &pB, p, 0, pBOTTOM) // permanent working space for symmetric inverse of a11 wrk.SubMatrix(&a11inv, 0, wrk.Cols()-2, 2, 2) a11inv.SetAt(1, 0, -1.0) a11inv.SetAt(0, 1, -1.0) for ATL.Cols() > 0 { nr := ATL.Rows() - 1 r, np := findBKPivot(&ATL, UPPER) if r != -1 /*&& r != np-1*/ { // pivoting needed; do swaping here //fmt.Printf("pre-pivot ATL [%d]:\n%v\n", ATL.Rows()-np, &ATL) applyBKPivotSym(&ATL, ATL.Rows()-np, r, UPPER) if np == 2 { /* * [r,r] | [r, nr] * a11 == --------------- 2-by-2 pivot, swapping [nr-1,nr] and [r,nr] * [r,0] | [nr,nr] */ t := ATL.GetAt(nr-1, nr) ATL.SetAt(nr-1, nr, ATL.GetAt(r, nr)) ATL.SetAt(r, nr, t) } //fmt.Printf("unblk: ATL after %d pivot [r=%d]:\n%v\n", np, r, &ATL) } // repartition according the pivot size repartition2x2to3x3(&ATL, &A00, &a01, &A02, nil, &a11, &a12t, nil, nil, &A22 /**/, A, np, pTOPLEFT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, np, pTOP) // ------------------------------------------------------------ if np == 1 { // A00 = A00 - a01*a01.T/a11 MVUpdateTrm(&A00, &a01, &a01, -1.0/a11.Float(), UPPER) // a01 = a01/a11 InvScale(&a01, a11.Float()) if r == -1 { p1.pivots[0] = ATL.Rows() } else { p1.pivots[0] = r + 1 } } else if np == 2 { /* * See comments on unblkDecompBKLower(). */ a := a11.GetAt(0, 0) b := a11.GetAt(0, 1) d := a11.GetAt(1, 1) a11inv.SetAt(0, 0, d/b) a11inv.SetAt(1, 1, a/b) // denominator: (a/b)*(d/b)-1.0 == (a*d - b^2)/b^2 scale := 1.0 / ((a/b)*(d/b) - 1.0) scale /= b // cwrk = a21 wrk.SubMatrix(&cwrk, 2, 0, a01.Rows(), a01.Cols()) a01.CopyTo(&cwrk) //fmt.Printf("cwrk:\n%v\n", &cwrk) //fmt.Printf("a11inv:\n%v\n", &a11inv) // a01 = a01*a11.-1 Mult(&a01, &cwrk, &a11inv, scale, 0.0, NOTRANS) // A00 = A00 - a01*a11.-1*a01.T = A00 - a01*cwrk.T UpdateTrm(&A00, &a01, &cwrk, -1.0, 1.0, UPPER|TRANSB) p1.pivots[0] = -(r + 1) p1.pivots[1] = p1.pivots[0] } // ------------------------------------------------------------ nc += np continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pTOPLEFT) contPivot3x1to2x1( &pT, &pB, &p0, &p1, p, pTOP) } return err, nc }
/* * Unblocked, bounded Bunch-Kauffman LDL factorization for at most ncol columns. * At most ncol columns are factorized and trailing matrix updates are restricted * to ncol columns. Also original columns are accumulated to working matrix, which * is used by calling blocked algorithm to update the trailing matrix with BLAS3 * update. * * Corresponds lapack.DLASYF */ func unblkBoundedBKLower(A, wrk *matrix.FloatMatrix, p *pPivots, ncol int) (error, int) { var err error var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a10t, a11, A20, a21, A22, a11inv matrix.FloatMatrix var w00, w10, w11 matrix.FloatMatrix var cwrk matrix.FloatMatrix //var s, d matrix.FloatMatrix var pT, pB, p0, p1, p2 pPivots err = nil nc := 0 if ncol > A.Cols() { ncol = A.Cols() } partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) partitionPivot2x1( &pT, &pB, p, 0, pTOP) // permanent working space for symmetric inverse of a11 wrk.SubMatrix(&a11inv, 0, wrk.Cols()-2, 2, 2) a11inv.SetAt(1, 0, -1.0) a11inv.SetAt(0, 1, -1.0) for ABR.Cols() > 0 && nc < ncol { partition2x2( &w00, nil, &w10, &w11, wrk, nc, nc, pTOPLEFT) //fmt.Printf("ABR:\n%v\n", &ABR) r, np := findAndBuildBKPivotLower(&ABL, &ABR, &w10, &w11, nc) //fmt.Printf("after find: r=%d, np=%d, ncol=%d, nc=%d\n", r, np, ncol, nc) if np > ncol-nc { // next pivot does not fit into ncol columns, restore last column, // return with number of factorized columns //fmt.Printf("np > ncol-nc: %d > %d\n", np, ncol-nc) return err, nc //goto undo } if r != 0 && r != np-1 { // pivoting needed; do swaping here applyBKPivotSym(&ABR, np-1, r, LOWER) // swap left hand rows to get correct updates swapRows(&ABL, np-1, r) swapRows(&w10, np-1, r) //ABL.SubMatrix(&s, np-1, 0, 1, ABL.Cols()) //ABL.SubMatrix(&d, r, 0, 1, ABL.Cols()) //Swap(&s, &d) //w10.SubMatrix(&s, np-1, 0, 1, w10.Cols()) //w10.SubMatrix(&d, r, 0, 1, w10.Cols()) //Swap(&s, &d) if np == 2 { /* * [0,0] | [r,0] * a11 == ------------- 2-by-2 pivot, swapping [1,0] and [r,0] * [r,0] | [r,r] */ t0 := w11.GetAt(1, 0) tr := w11.GetAt(r, 0) //fmt.Printf("nc=%d, t0=%e, tr=%e\n", nc, t0, tr) w11.SetAt(1, 0, tr) w11.SetAt(r, 0, t0) // interchange diagonal entries on w11[:,1] t0 = w11.GetAt(1, 1) tr = w11.GetAt(r, 1) w11.SetAt(1, 1, tr) w11.SetAt(r, 1, t0) } //fmt.Printf("pivoted A:\n%v\n", A) //fmt.Printf("pivoted wrk:\n%v\n", wrk) } // repartition according the pivot size repartition2x2to3x3(&ATL, &A00, nil, nil, &a10t, &a11, nil, &A20, &a21, &A22 /**/, A, np, pBOTTOMRIGHT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, np, pBOTTOM) // ------------------------------------------------------------ if np == 1 { // w11.SubMatrix(&cwrk, np, 0, a21.Rows(), np) a11.SetAt(0, 0, w11.GetAt(0, 0)) // a21 = a21/a11 //fmt.Printf("np == 1: pre-update a21\n%v\n", &a21) cwrk.CopyTo(&a21) InvScale(&a21, a11.Float()) //fmt.Printf("np == 1: cwrk\n%v\na21\n%v\n", &cwrk, &a21) // store pivot point relative to original matrix p1.pivots[0] = r + ATL.Rows() + 1 } else if np == 2 { /* * See comments for this block in unblkDecompBKLower(). */ a := w11.GetAt(0, 0) b := w11.GetAt(1, 0) d := w11.GetAt(1, 1) a11inv.SetAt(0, 0, d/b) a11inv.SetAt(1, 1, a/b) // denominator: (a/b)*(d/b)-1.0 == (a*d - b^2)/b^2 scale := 1.0 / ((a/b)*(d/b) - 1.0) scale /= b w11.SubMatrix(&cwrk, np, 0, a21.Rows(), np) // a21 = a21*a11.-1 Mult(&a21, &cwrk, &a11inv, scale, 0.0, NOTRANS) a11.SetAt(0, 0, a) a11.SetAt(1, 0, b) a11.SetAt(1, 1, d) // store pivot point relative to original matrix p1.pivots[0] = -(r + ATL.Rows() + 1) p1.pivots[1] = p1.pivots[0] } /* if m(&ABR) < 5 { var Ablk, wblk, w5 matrix.FloatMatrix merge1x2(&Ablk, &ABL, &ABR) merge1x2(&wblk, &w10, &w11) wblk.SubMatrix(&w5, 0, 0, Ablk.Rows(), wblk.Cols()) fmt.Printf("blocked EOL: Ablk r=%d, nc=%d. np=%d\n%v\n", r, nc, np, &Ablk) fmt.Printf("wblk m(wblk)=%d:\n%v\n", m(&w5), &w5) } */ // ------------------------------------------------------------ nc += np continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) contPivot3x1to2x1( &pT, &pB, &p0, &p1, p, pBOTTOM) } // undo applied partial row pivots (AL, w00) //undo: return err, nc }
/* * Unblocked Bunch-Kauffman LDL factorization. * * Corresponds lapack.DSYTF2 */ func unblkDecompBKLower(A, wrk *matrix.FloatMatrix, p *pPivots) (error, int) { var err error var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a10t, a11, A20, a21, A22, a11inv matrix.FloatMatrix var cwrk matrix.FloatMatrix var pT, pB, p0, p1, p2 pPivots err = nil nc := 0 partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) partitionPivot2x1( &pT, &pB, p, 0, pTOP) // permanent working space for symmetric inverse of a11 wrk.SubMatrix(&a11inv, 0, wrk.Cols()-2, 2, 2) a11inv.SetAt(1, 0, -1.0) a11inv.SetAt(0, 1, -1.0) for ABR.Cols() > 0 { r, np := findBKPivot(&ABR, LOWER) if r != 0 && r != np-1 { // pivoting needed; do swaping here applyBKPivotSym(&ABR, np-1, r, LOWER) if np == 2 { /* * [0,0] | [r,0] * a11 == ------------- 2-by-2 pivot, swapping [1,0] and [r,0] * [r,0] | [r,r] */ t := ABR.GetAt(1, 0) ABR.SetAt(1, 0, ABR.GetAt(r, 0)) ABR.SetAt(r, 0, t) } //fmt.Printf("unblk: ABR after %d pivot [r=%d]:\n%v\n", np, r, &ABR) } // repartition according the pivot size repartition2x2to3x3(&ATL, &A00, nil, nil, &a10t, &a11, nil, &A20, &a21, &A22 /**/, A, np, pBOTTOMRIGHT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, np, pBOTTOM) // ------------------------------------------------------------ if np == 1 { // A22 = A22 - a21*a21.T/a11 MVUpdateTrm(&A22, &a21, &a21, -1.0/a11.Float(), LOWER) // a21 = a21/a11 InvScale(&a21, a11.Float()) // store pivot point relative to original matrix p1.pivots[0] = r + ATL.Rows() + 1 } else if np == 2 { /* from Bunch-Kaufmann 1977: * (E2 C.T) = ( I2 0 )( E 0 )( I[n-2] E.-1*C.T ) * (C B ) ( C*E.-1 I[n-2] )( 0 A[n-2] )( 0 I2 ) * * A[n-2] = B - C*E.-1*C.T * * E.-1 is inverse of a symmetric matrix, cannot use * triangular solve. We calculate inverse of 2x2 matrix. * Following is inspired by lapack.SYTF2 * * a | b 1 d | -b b d/b | -1 * inv ----- = ------ * ------ = ----------- * -------- * b | d (ad-b^2) -b | a (a*d - b^2) -1 | a/b * */ a := a11.GetAt(0, 0) b := a11.GetAt(1, 0) d := a11.GetAt(1, 1) a11inv.SetAt(0, 0, d/b) a11inv.SetAt(1, 1, a/b) // denominator: (a/b)*(d/b)-1.0 == (a*d - b^2)/b^2 scale := 1.0 / ((a/b)*(d/b) - 1.0) scale /= b // cwrk = a21 wrk.SubMatrix(&cwrk, 2, 0, a21.Rows(), a21.Cols()) a21.CopyTo(&cwrk) // a21 = a21*a11.-1 Mult(&a21, &cwrk, &a11inv, scale, 0.0, NOTRANS) // A22 = A22 - a21*a11.-1*a21.T = A22 - a21*cwrk.T UpdateTrm(&A22, &a21, &cwrk, -1.0, 1.0, LOWER|TRANSB) // store pivot point relative to original matrix p1.pivots[0] = -(r + ATL.Rows() + 1) p1.pivots[1] = p1.pivots[0] } /* if m(&ABR) < 5 { var Ablk matrix.FloatMatrix merge1x2(&Ablk, &ABL, &ABR) fmt.Printf("unblocked EOL: Ablk r=%d, nc=%d. np=%d\n%v\n", r, nc, np, &Ablk) } */ // ------------------------------------------------------------ nc += np continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) contPivot3x1to2x1( &pT, &pB, &p0, &p1, p, pBOTTOM) } return err, nc }
func unblkSolveBKUpper(B, A *matrix.FloatMatrix, p *pPivots, phase int) error { var err error var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a11, a12t, A22 matrix.FloatMatrix var Aref *matrix.FloatMatrix var BT, BB, B0, b1, B2, Bx matrix.FloatMatrix var pT, pB, p0, p1, p2 pPivots var aStart, aDir, bStart, bDir pDirection var nc int err = nil np := 0 if phase == 2 { aStart = pTOPLEFT aDir = pBOTTOMRIGHT bStart = pTOP bDir = pBOTTOM nc = 1 Aref = &ABR } else { aStart = pBOTTOMRIGHT aDir = pTOPLEFT bStart = pBOTTOM bDir = pTOP nc = A.Rows() Aref = &ATL } partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, aStart) partition2x1( &BT, &BB, B, 0, bStart) partitionPivot2x1( &pT, &pB, p, 0, bStart) // ABR.Cols() == 0 is end of matrix, for Aref.Cols() > 0 { // see if next diagonal block is 1x1 or 2x2 np = 1 if p.pivots[nc-1] < 0 { np = 2 } fmt.Printf("nc=%d, np=%d, m(ABR)=%d\n", nc, np, m(&ABR)) // repartition according the pivot size repartition2x2to3x3(&ATL, &A00, &a01, &A02, nil, &a11, &a12t, nil, nil, &A22 /**/, A, np, aDir) repartition2x1to3x1(&BT, &B0, &b1, &B2 /**/, B, np, bDir) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, np, bDir) // ------------------------------------------------------------ switch phase { case 1: // computes D.-1*(L.-1*B) if np == 1 { if p1.pivots[0] != nc { // swap rows in top part of B //fmt.Printf("1x1 pivot top with %d [%d]\n", p1.pivots[0], p1.pivots[0]-BT.Rows()) swapRows(&BT, BT.Rows()-1, p1.pivots[0]-1) } // B2 = B2 - a21*b1 MVRankUpdate(&B2, &a01, &b1, -1.0) // b1 = b1/d1 InvScale(&b1, a11.Float()) nc += 1 } else if np == 2 { if p1.pivots[0] != -nc { // swap rows on bottom part of B //fmt.Printf("2x2 pivot %d with %d [%d]\n", nc+1, -p1.pivots[0]) //fmt.Printf("pre :\n%v\n", B) swapRows(&BT, BT.Rows()-2, -p1.pivots[0]-1) //fmt.Printf("post:\n%v\n", B) } b := a11.GetAt(0, 1) apb := a11.GetAt(0, 0) / b dpb := a11.GetAt(1, 1) / b // (a/b)*(d/b)-1.0 == (a*d - b^2)/b^2 scale := apb*dpb - 1.0 scale *= b // B2 = B2 - a21*b1 Mult(&B2, &a01, &b1, -1.0, 1.0, NOTRANS) // b1 = a11.-1*b1.T //(2x2 block, no subroutine for doing this in-place) for k := 0; k < b1.Cols(); k++ { s0 := b1.GetAt(0, k) s1 := b1.GetAt(1, k) b1.SetAt(0, k, (dpb*s0-s1)/scale) b1.SetAt(1, k, (apb*s1-s0)/scale) } nc += 2 } case 2: if np == 1 { MVMult(&b1, &B2, &a01, -1.0, 1.0, TRANSA) if p1.pivots[0] != nc { // swap rows on bottom part of B //fmt.Printf("1x1 pivot top with %d [%d]\n", p1.pivots[0], p1.pivots[0]-BT.Rows()) merge2x1(&Bx, &B0, &b1) swapRows(&Bx, Bx.Rows()-1, p1.pivots[0]-1) } nc -= 1 } else if np == 2 { Mult(&b1, &a01, &B2, -1.0, 1.0, TRANSA) if p1.pivots[0] != -nc { // swap rows on bottom part of B //fmt.Printf("2x2 pivot %d with %d\n", nc, -p1.pivots[0]) merge2x1(&Bx, &B0, &b1) //fmt.Printf("pre :\n%v\n", B) swapRows(&Bx, Bx.Rows()-2, -p1.pivots[0]-1) //fmt.Printf("post:\n%v\n", B) } nc -= 2 } } // ------------------------------------------------------------ continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, aDir) continue3x1to2x1( &BT, &BB, &B0, &b1, B, bDir) contPivot3x1to2x1( &pT, &pB, &p0, &p1, p, bDir) } return err }
// Build Q in place by applying elementary reflectors in reverse order to // an implied identity matrix. This forms Q = H(1)H(2) ... H(k) // // this is compatibe with lapack.DORG2R func unblockedBuildQ(A, tau, w *matrix.FloatMatrix, kb int) error { var err error = nil var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a10t, a11, a12t, A20, a21, A22 matrix.FloatMatrix var tT, tB matrix.FloatMatrix var t0, tau1, t2, w1 matrix.FloatMatrix var mb int var rowvec bool mb = A.Rows() - A.Cols() rowvec = tau.Rows() == 1 partition2x2( &ATL, &ATR, &ABL, &ABR, A, mb, 0, pBOTTOMRIGHT) if rowvec { partition1x2( &tT, &tB, tau, 0, pRIGHT) } else { partition2x1( &tT, &tB, tau, 0, pBOTTOM) } // clearing of the columns of the right and setting ABR to unit diagonal // (only if not applying all reflectors, kb > 0) for ATL.Rows() > 0 && ATL.Cols() > 0 { repartition2x2to3x3(&ATL, &A00, &a01, &A02, &a10t, &a11, &a12t, &A20, &a21, &A22, A, 1, pTOPLEFT) if rowvec { repartition1x2to1x3(&tT, &t0, &tau1, &t2, tau, 1, pLEFT) } else { repartition2x1to3x1(&tT, &t0, &tau1, &t2, tau, 1, pTOP) } // -------------------------------------------------------- // adjust workspace to correct size w.SubMatrix(&w1, 0, 0, 1, a12t.Cols()) // apply Householder reflection from left applyHHTo2x1(&tau1, &a21, &a12t, &A22, &w1, LEFT) // apply (in-place) current elementary reflector to unit vector a21.Scale(-tau1.Float()) a11.SetAt(0, 0, 1.0-tau1.Float()) // zero the upper part a01.SetIndexes(0.0) // -------------------------------------------------------- continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pTOPLEFT) if rowvec { continue1x3to1x2( &tT, &tB, &t0, &tau1, tau, pLEFT) } else { continue3x1to2x1( &tT, &tB, &t0, &tau1, tau, pTOP) } } return err }
/* * ( a11 a12 ) ( 1 0 )( d1 0 )( l l21.t ) * ( a21 A22 ) ( l21 L22 )( 0 A22 )( 0 L22.t ) * * a11 = d1 * a21 = l21*d1 => l21 = a21/d1 * A22 = l21*d1*l21.t + L22*D2*L22.t => L22 = A22 - l21*d1*l21t */ func unblkLowerLDL(A *matrix.FloatMatrix, p *pPivots) (err error) { var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a10, a11, A20, a21, A22, acol matrix.FloatMatrix var pT, pB, p0, p1, p2 pPivots err = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) partitionPivot2x1( &pT, &pB, p, 0, pTOP) for ATL.Rows() < A.Rows() { repartition2x2to3x3(&ATL, &A00, nil, nil, &a10, &a11, nil, &A20, &a21, &A22, A, 1, pBOTTOMRIGHT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, 1, pBOTTOM) // -------------------------------------------------------- ABR.Diag(&acol) //merge2x1(&acol, &a11, &a21) imax := IAMax(&acol) //fmt.Printf("imax=%d, val=%e\n", imax, acol.GetAt(0, imax)) if imax > 0 { // pivot diagonal in symmetric matrix; will swap a11 and [imax,imax] applyPivotSym(&ABL, &ABR, imax, LOWER) p1.pivots[0] = imax + ATL.Rows() + 1 } else { p1.pivots[0] = 0 } if a11.Float() == 0.0 { err = onError("zero value on diagonal") return } //fmt.Printf("unblk pivoted %d, a11=%e, A:\n%v\n", imax, a11.Float(), A) //var Ablk matrix.FloatMatrix //merge1x2(&Ablk, &a21, &A22) //fmt.Printf("unblk update with a11=%e, a21|A22:\n%v\n", a11.Float(), &Ablk) // A22 = A22 - l21*d11*l21.T = A22 - a21*a21.T/a11; triangular update err = MVUpdateTrm(&A22, &a21, &a21, -1.0/a11.Float(), LOWER) // l21 = a21/a11 InvScale(&a21, a11.Float()) //merge1x2(&Ablk, &ABL, &ABR) //fmt.Printf("unblk imax=%d, Ablk:\n%v\n", imax, &Ablk) // --------------------------------------------------------- continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) contPivot3x1to2x1( &pT, &pB, &p0, &p1, p, pBOTTOM) } return }
// unblocked LU decomposition with pivots: FLAME LU variant 3 func unblockedLUpiv(A *matrix.FloatMatrix, p *pPivots) error { var err error var ATL, ATR, ABL, ABR matrix.FloatMatrix var A00, a01, A02, a10, a11, a12, A20, a21, A22 matrix.FloatMatrix var AL, AR, A0, a1, A2, aB1, AB0 matrix.FloatMatrix var pT, pB, p0, p1, p2 pPivots err = nil partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, pTOPLEFT) partition1x2( &AL, &AR, A, 0, pLEFT) partitionPivot2x1( &pT, &pB, p, 0, pTOP) for ATL.Rows() < A.Rows() && ATL.Cols() < A.Cols() { repartition2x2to3x3(&ATL, &A00, &a01, &A02, &a10, &a11, &a12, &A20, &a21, &A22 /**/, A, 1, pBOTTOMRIGHT) repartition1x2to1x3(&AL, &A0, &a1, &A2 /**/, A, 1, pRIGHT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, 1, pBOTTOM) // apply previously computed pivots applyPivots(&a1, &p0) // a01 = trilu(A00) \ a01 (TRSV) MVSolveTrm(&a01, &A00, 1.0, LOWER|UNIT) // a11 = a11 - a10 *a01 a11.Add(Dot(&a10, &a01, -1.0)) // a21 = a21 -A20*a01 MVMult(&a21, &A20, &a01, -1.0, 1.0, NOTRANS) // pivot index on current column [a11, a21].T aB1.SubMatrixOf(&ABR, 0, 0, ABR.Rows(), 1) pivotIndex(&aB1, &p1) // pivots to current column applyPivots(&aB1, &p1) // a21 = a21 / a11 InvScale(&a21, a11.Float()) // apply pivots to previous columns AB0.SubMatrixOf(&ABL, 0, 0) applyPivots(&AB0, &p1) // scale last pivots to origin matrix row numbers p1.pivots[0] += ATL.Rows() continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, pBOTTOMRIGHT) continue1x3to1x2( &AL, &AR, &A0, &a1, A, pRIGHT) contPivot3x1to2x1( &pT, &pB, &p0, &p1, p, pBOTTOM) } if ATL.Cols() < A.Cols() { applyPivots(&ATR, p) SolveTrm(&ATR, &ATL, 1.0, LEFT|UNIT|LOWER) } return err }