/* * 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 }