Example #1
0
/*
 * 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
}
Example #2
0
/*
 * 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
}