func blkDecompBKUpper(A, W *cmat.FloatMatrix, p *Pivots, conf *gomas.Config) (err *gomas.Error) { var ATL, ATR, ABL, ABR cmat.FloatMatrix var A00, A01, A02, A11, A12, A22 cmat.FloatMatrix var wrk cmat.FloatMatrix var pT, pB, p0, p1, p2 Pivots var nblk int = 0 err = nil util.Partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, util.PBOTTOMRIGHT) partitionPivot2x1( &pT, &pB, *p, 0, util.PBOTTOM) nb := conf.LB for n(&ATL) >= nb { err, nblk = unblkBoundedBKUpper(&ATL, W, &pT, nb, conf) // repartition nblk size util.Repartition2x2to3x3(&ATL, &A00, &A01, &A02, nil, &A11, &A12, nil, nil, &A22, A, nblk, util.PTOPLEFT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, *p, nblk, util.PTOP) // -------------------------------------------------------- // here [A01;A11] has been decomposed by unblkBoundedBKUpper() // Now we need update A00 // wrk is original A01 wrk.SubMatrix(W, 0, n(W)-nblk, m(&A01), nblk) // A00 = A00 - L01*D1*L01.T = A22 - A01*W.T blasd.UpdateTrm(&A00, &A01, &wrk, -1.0, 1.0, gomas.UPPER|gomas.TRANSB) // partially undo row pivots right of diagonal for k := 0; k < nblk; k++ { var s, d cmat.FloatMatrix r := p1[k] colno := n(&A00) + k np := 1 if r < 0 { r = -r np = 2 } rlen := n(&ATL) - colno - np if r == colno+1 && p1[k] > 0 { // no pivot continue } s.SubMatrix(&ATL, colno, colno+np, 1, rlen) d.SubMatrix(&ATL, r-1, colno+np, 1, rlen) blasd.Swap(&d, &s) if p1[k] < 0 { k++ // skip other entry in 2x2 pivots } } // --------------------------------------------------------- util.Continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &A11, &A22, A, util.PTOPLEFT) contPivot3x1to2x1( &pT, &pB, p0, p1, *p, util.PTOP) } // do the last part with unblocked code if n(&ATL) > 0 { unblkDecompBKUpper(&ATL, W, pT, conf) } return }
func blkDecompBKLower(A, W *cmat.FloatMatrix, p *Pivots, conf *gomas.Config) (err *gomas.Error) { var ATL, ATR, ABL, ABR cmat.FloatMatrix var A00, A10, A11, A20, A21, A22 cmat.FloatMatrix var wrk cmat.FloatMatrix var pT, pB, p0, p1, p2 Pivots var nblk int = 0 err = nil util.Partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, util.PTOPLEFT) partitionPivot2x1( &pT, &pB, *p, 0, util.PTOP) nb := conf.LB for n(&ABR) >= nb { err, nblk = unblkBoundedBKLower(&ABR, W, &pB, nb, conf) // repartition nblk size util.Repartition2x2to3x3(&ATL, &A00, nil, nil, &A10, &A11, nil, &A20, &A21, &A22, A, nblk, util.PBOTTOMRIGHT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, *p, nblk, util.PBOTTOM) // -------------------------------------------------------- // here [A11;A21] has been decomposed by unblkBoundedBKLower() // Now we need update A22 // wrk is original A21 wrk.SubMatrix(W, nblk, 0, m(&A21), nblk) // A22 = A22 - L21*D1*L21.T = A22 - L21*W.T blasd.UpdateTrm(&A22, &A21, &wrk, -1.0, 1.0, gomas.LOWER|gomas.TRANSB) // partially undo row pivots left of diagonal for k := nblk; k > 0; k-- { var s, d cmat.FloatMatrix r := p1[k-1] rlen := k - 1 if r < 0 { r = -r rlen-- } if r == k && p1[k-1] > 0 { // no pivot continue } s.SubMatrix(&ABR, k-1, 0, 1, rlen) d.SubMatrix(&ABR, r-1, 0, 1, rlen) blasd.Swap(&d, &s) if p1[k-1] < 0 { k-- // skip other entry in 2x2 pivots } } // shift pivot values for k, n := range p1 { if n > 0 { p1[k] += m(&ATL) } else { p1[k] -= m(&ATL) } } // zero work for debuging //blasd.Scale(W, 0.0) // --------------------------------------------------------- util.Continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &A11, &A22, A, util.PBOTTOMRIGHT) contPivot3x1to2x1( &pT, &pB, p0, p1, *p, util.PBOTTOM) } // do the last part with unblocked code if n(&ABR) > 0 { unblkDecompBKLower(&ABR, W, pB, conf) // shift pivot values for k, n := range pB { if n > 0 { pB[k] += m(&ATL) } else { pB[k] -= m(&ATL) } } } return }
/* * Unblocked Bunch-Kauffman LDL factorization. * * Corresponds lapack.DSYTF2 */ func unblkDecompBKUpper(A, wrk *cmat.FloatMatrix, p Pivots, conf *gomas.Config) (*gomas.Error, int) { var err *gomas.Error = nil var ATL, ATR, ABL, ABR cmat.FloatMatrix var A00, a01, A02, a11, a12, A22, a11inv cmat.FloatMatrix var cwrk cmat.FloatMatrix var pT, pB, p0, p1, p2 Pivots err = nil nc := 0 util.Partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, util.PBOTTOMRIGHT) partitionPivot2x1( &pT, &pB, p, 0, util.PBOTTOM) // permanent working space for symmetric inverse of a11 a11inv.SubMatrix(wrk, 0, n(wrk)-2, 2, 2) a11inv.Set(1, 0, -1.0) a11inv.Set(0, 1, -1.0) for n(&ATL) > 0 { nr := m(&ATL) - 1 r, np := findBKPivotUpper(&ATL) if r != -1 { cwrk.SubMatrix(&ATL, 0, n(&ATL)-np, m(&ATL), np) // pivoting needed; do swaping here applyBKPivotSymUpper(&ATL, m(&ATL)-np, r) if np == 2 { /* [r, r] | [r, nr] * a11 == ---------------- 2-by-2 pivot, swapping [nr-1,nr] and [r,nr] * [nr,r] | [nr,nr] (nr is the current diagonal entry) */ t := ATL.Get(nr-1, nr) ATL.Set(nr-1, nr, ATL.Get(r, nr)) ATL.Set(r, nr, t) } } // repartition according the pivot size util.Repartition2x2to3x3(&ATL, &A00, &a01, &A02, nil, &a11, &a12, nil, nil, &A22 /**/, A, np, util.PTOPLEFT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, np, util.PTOP) // ------------------------------------------------------------ if np == 1 { // A00 = A00 - a01*a01.T/a11 blasd.MVUpdateTrm(&A00, &a01, &a01, -1.0/a11.Get(0, 0), gomas.UPPER) // a01 = a01/a11 blasd.InvScale(&a01, a11.Get(0, 0)) // store pivot point relative to original matrix if r == -1 { p1[0] = m(&ATL) } else { p1[0] = r + 1 } } else if np == 2 { /* see comments on unblkDecompBKLower() */ a := a11.Get(0, 0) b := a11.Get(0, 1) d := a11.Get(1, 1) a11inv.Set(0, 0, d/b) a11inv.Set(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 cwrk.SubMatrix(wrk, 2, 0, m(&a01), n(&a01)) blasd.Copy(&cwrk, &a01) // a01 = a01*a11.-1 blasd.Mult(&a01, &cwrk, &a11inv, scale, 0.0, gomas.NONE, conf) // A00 = A00 - a01*a11.-1*a01.T = A00 - a01*cwrk.T blasd.UpdateTrm(&A00, &a01, &cwrk, -1.0, 1.0, gomas.UPPER|gomas.TRANSB, conf) // store pivot point relative to original matrix p1[0] = -(r + 1) p1[1] = p1[0] } // ------------------------------------------------------------ nc += np util.Continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, util.PTOPLEFT) contPivot3x1to2x1( &pT, &pB, p0, p1, p, util.PTOP) } return err, nc }
/* * Unblocked Bunch-Kauffman LDL factorization. * * Corresponds lapack.DSYTF2 */ func unblkDecompBKLower(A, wrk *cmat.FloatMatrix, p Pivots, conf *gomas.Config) (*gomas.Error, int) { var err *gomas.Error = nil var ATL, ATR, ABL, ABR cmat.FloatMatrix var A00, a10t, a11, A20, a21, A22, a11inv cmat.FloatMatrix var cwrk cmat.FloatMatrix var pT, pB, p0, p1, p2 Pivots err = nil nc := 0 util.Partition2x2( &ATL, &ATR, &ABL, &ABR, A, 0, 0, util.PTOPLEFT) partitionPivot2x1( &pT, &pB, p, 0, util.PTOP) // permanent working space for symmetric inverse of a11 a11inv.SubMatrix(wrk, 0, n(wrk)-2, 2, 2) a11inv.Set(1, 0, -1.0) a11inv.Set(0, 1, -1.0) for n(&ABR) > 0 { r, np := findBKPivotLower(&ABR) if r != 0 && r != np-1 { // pivoting needed; do swaping here applyBKPivotSymLower(&ABR, np-1, r) if np == 2 { /* [0,0] | [r,0] * a11 == ------------- 2-by-2 pivot, swapping [1,0] and [r,0] * [r,0] | [r,r] */ t := ABR.Get(1, 0) ABR.Set(1, 0, ABR.Get(r, 0)) ABR.Set(r, 0, t) } } // repartition according the pivot size util.Repartition2x2to3x3(&ATL, &A00, nil, nil, &a10t, &a11, nil, &A20, &a21, &A22 /**/, A, np, util.PBOTTOMRIGHT) repartPivot2x1to3x1(&pT, &p0, &p1, &p2 /**/, p, np, util.PBOTTOM) // ------------------------------------------------------------ if np == 1 { // A22 = A22 - a21*a21.T/a11 blasd.MVUpdateTrm(&A22, &a21, &a21, -1.0/a11.Get(0, 0), gomas.LOWER) // a21 = a21/a11 blasd.InvScale(&a21, a11.Get(0, 0)) // store pivot point relative to original matrix p1[0] = r + m(&ATL) + 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.Get(0, 0) b := a11.Get(1, 0) d := a11.Get(1, 1) a11inv.Set(0, 0, d/b) a11inv.Set(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 cwrk.SubMatrix(wrk, 2, 0, m(&a21), n(&a21)) blasd.Copy(&cwrk, &a21) // a21 = a21*a11.-1 blasd.Mult(&a21, &cwrk, &a11inv, scale, 0.0, gomas.NONE, conf) // A22 = A22 - a21*a11.-1*a21.T = A22 - a21*cwrk.T blasd.UpdateTrm(&A22, &a21, &cwrk, -1.0, 1.0, gomas.LOWER|gomas.TRANSB, conf) // store pivot point relative to original matrix p1[0] = -(r + m(&ATL) + 1) p1[1] = p1[0] } // ------------------------------------------------------------ nc += np util.Continue3x3to2x2( &ATL, &ATR, &ABL, &ABR, &A00, &a11, &A22, A, util.PBOTTOMRIGHT) contPivot3x1to2x1( &pT, &pB, p0, p1, p, util.PBOTTOM) } return err, nc }