Пример #1
0
func kktChol2(G *matrix.FloatMatrix, dims *sets.DimensionSet, A *matrix.FloatMatrix, mnl int) (kktFactor, error) {

	if len(dims.At("q")) > 0 || len(dims.At("s")) > 0 {
		return nil, errors.New("'chol2' solver only for problems with no second-order or " +
			"semidefinite cone constraints")
	}

	p, n := A.Size()
	ml := dims.At("l")[0]
	F := &chol2Data{firstcall: true, singular: false, A: A, G: G, dims: dims}

	factor := func(W *sets.FloatMatrixSet, H, Df *matrix.FloatMatrix) (KKTFunc, error) {
		var err error = nil
		minor := 0
		if !checkpnt.MinorEmpty() {
			minor = checkpnt.MinorTop()
		}
		if F.firstcall {
			F.Gs = matrix.FloatZeros(F.G.Size())
			if mnl > 0 {
				F.Dfs = matrix.FloatZeros(Df.Size())
			}
			F.S = matrix.FloatZeros(n, n)
			F.K = matrix.FloatZeros(p, p)
			checkpnt.AddMatrixVar("Gs", F.Gs)
			checkpnt.AddMatrixVar("Dfs", F.Dfs)
			checkpnt.AddMatrixVar("S", F.S)
			checkpnt.AddMatrixVar("K", F.K)
		}

		if mnl > 0 {
			dnli := matrix.FloatZeros(mnl, mnl)
			dnli.SetIndexesFromArray(W.At("dnli")[0].FloatArray(), matrix.DiagonalIndexes(dnli)...)
			blas.GemmFloat(dnli, Df, F.Dfs, 1.0, 0.0)
		}
		checkpnt.Check("02factor_chol2", minor)
		di := matrix.FloatZeros(ml, ml)
		di.SetIndexesFromArray(W.At("di")[0].FloatArray(), matrix.DiagonalIndexes(di)...)
		err = blas.GemmFloat(di, G, F.Gs, 1.0, 0.0)
		checkpnt.Check("06factor_chol2", minor)

		if F.firstcall {
			blas.SyrkFloat(F.Gs, F.S, 1.0, 0.0, la.OptTrans)
			if mnl > 0 {
				blas.SyrkFloat(F.Dfs, F.S, 1.0, 1.0, la.OptTrans)
			}
			if H != nil {
				F.S.Plus(H)
			}
			checkpnt.Check("10factor_chol2", minor)
			err = lapack.Potrf(F.S)
			if err != nil {
				err = nil // reset error
				F.singular = true
				// original code recreates F.S as dense if it is sparse and
				// A is dense, we don't do it as currently no sparse matrices
				//F.S = matrix.FloatZeros(n, n)
				//checkpnt.AddMatrixVar("S", F.S)
				blas.SyrkFloat(F.Gs, F.S, 1.0, 0.0, la.OptTrans)
				if mnl > 0 {
					blas.SyrkFloat(F.Dfs, F.S, 1.0, 1.0, la.OptTrans)
				}
				checkpnt.Check("14factor_chol2", minor)
				blas.SyrkFloat(F.A, F.S, 1.0, 1.0, la.OptTrans)
				if H != nil {
					F.S.Plus(H)
				}
				lapack.Potrf(F.S)
			}
			F.firstcall = false
			checkpnt.Check("20factor_chol2", minor)
		} else {
			blas.SyrkFloat(F.Gs, F.S, 1.0, 0.0, la.OptTrans)
			if mnl > 0 {
				blas.SyrkFloat(F.Dfs, F.S, 1.0, 1.0, la.OptTrans)
			}
			if H != nil {
				F.S.Plus(H)
			}
			checkpnt.Check("40factor_chol2", minor)
			if F.singular {
				blas.SyrkFloat(F.A, F.S, 1.0, 1.0, la.OptTrans)
			}
			lapack.Potrf(F.S)
			checkpnt.Check("50factor_chol2", minor)
		}

		// Asct := L^{-1}*A'.  Factor K = Asct'*Asct.
		Asct := F.A.Transpose()
		blas.TrsmFloat(F.S, Asct, 1.0)
		blas.SyrkFloat(Asct, F.K, 1.0, 0.0, la.OptTrans)
		lapack.Potrf(F.K)
		checkpnt.Check("90factor_chol2", minor)

		solve := func(x, y, z *matrix.FloatMatrix) (err error) {
			// Solve
			//
			//     [ H          A'  GG'*W^{-1} ]   [ ux   ]   [ bx        ]
			//     [ A          0   0          ] * [ uy   ] = [ by        ]
			//     [ W^{-T}*GG  0   -I         ]   [ W*uz ]   [ W^{-T}*bz ]
			//
			// and return ux, uy, W*uz.
			//
			// If not F['singular']:
			//
			//     K*uy = A * S^{-1} * ( bx + GG'*W^{-1}*W^{-T}*bz ) - by
			//     S*ux = bx + GG'*W^{-1}*W^{-T}*bz - A'*uy
			//     W*uz = W^{-T} * ( GG*ux - bz ).
			//
			// If F['singular']:
			//
			//     K*uy = A * S^{-1} * ( bx + GG'*W^{-1}*W^{-T}*bz + A'*by )
			//            - by
			//     S*ux = bx + GG'*W^{-1}*W^{-T}*bz + A'*by - A'*y.
			//     W*uz = W^{-T} * ( GG*ux - bz ).

			minor := 0
			if !checkpnt.MinorEmpty() {
				minor = checkpnt.MinorTop()
			}

			// z := W^{-1} * z = W^{-1} * bz
			scale(z, W, true, true)
			checkpnt.Check("10solve_chol2", minor)

			// If not F['singular']:
			//     x := L^{-1} * P * (x + GGs'*z)
			//        = L^{-1} * P * (x + GG'*W^{-1}*W^{-T}*bz)
			//
			// If F['singular']:
			//     x := L^{-1} * P * (x + GGs'*z + A'*y))
			//        = L^{-1} * P * (x + GG'*W^{-1}*W^{-T}*bz + A'*y)
			if mnl > 0 {
				blas.GemvFloat(F.Dfs, z, x, 1.0, 1.0, la.OptTrans)
			}
			blas.GemvFloat(F.Gs, z, x, 1.0, 1.0, la.OptTrans, &la.IOpt{"offsetx", mnl})
			//checkpnt.Check("20solve_chol2", minor)
			if F.singular {
				blas.GemvFloat(F.A, y, x, 1.0, 1.0, la.OptTrans)
			}
			checkpnt.Check("30solve_chol2", minor)
			blas.TrsvFloat(F.S, x)
			//checkpnt.Check("50solve_chol2", minor)

			// y := K^{-1} * (Asc*x - y)
			//    = K^{-1} * (A * S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz) - by)
			//      (if not F['singular'])
			//    = K^{-1} * (A * S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz +
			//      A'*by) - by)
			//      (if F['singular']).
			blas.GemvFloat(Asct, x, y, 1.0, -1.0, la.OptTrans)
			//checkpnt.Check("55solve_chol2", minor)
			lapack.Potrs(F.K, y)
			//checkpnt.Check("60solve_chol2", minor)

			// x := P' * L^{-T} * (x - Asc'*y)
			//    = S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz - A'*y)
			//      (if not F['singular'])
			//    = S^{-1} * (bx + GG'*W^{-1}*W^{-T}*bz + A'*by - A'*y)
			//      (if F['singular'])
			blas.GemvFloat(Asct, y, x, -1.0, 1.0)
			blas.TrsvFloat(F.S, x, la.OptTrans)
			checkpnt.Check("70solve_chol2", minor)

			// W*z := GGs*x - z = W^{-T} * (GG*x - bz)
			if mnl > 0 {
				blas.GemvFloat(F.Dfs, x, z, 1.0, -1.0)
			}
			blas.GemvFloat(F.Gs, x, z, 1.0, -1.0, &la.IOpt{"offsety", mnl})

			checkpnt.Check("90solve_chol2", minor)
			return nil
		}
		return solve, err
	}
	return factor, nil
}
Пример #2
0
func mcsdp(w *matrix.FloatMatrix) (*Solution, error) {
	//
	// Returns solution x, z to
	//
	//    (primal)  minimize    sum(x)
	//              subject to  w + diag(x) >= 0
	//
	//    (dual)    maximize    -tr(w*z)
	//              subject to  diag(z) = 1
	//                          z >= 0.
	//
	n := w.Rows()
	G := &matrixFs{n}

	cngrnc := func(r, x *matrix.FloatMatrix, alpha float64) (err error) {
		// Congruence transformation
		//
		//    x := alpha * r'*x*r.
		//
		// r and x are square matrices.
		//
		err = nil

		// tx = matrix(x, (n,n)) is copying and reshaping
		// scale diagonal of x by 1/2, (x is (n,n))
		tx := x.Copy()
		matrix.Reshape(tx, n, n)
		tx.Diag().Scale(0.5)

		// a := tril(x)*r
		// (python: a = +r is really making a copy of r)
		a := r.Copy()

		err = blas.TrmmFloat(tx, a, 1.0, linalg.OptLeft)

		// x := alpha*(a*r' + r*a')
		err = blas.Syr2kFloat(r, a, tx, alpha, 0.0, linalg.OptTrans)

		// x[:] = tx[:]
		tx.CopyTo(x)
		return
	}

	Fkkt := func(W *sets.FloatMatrixSet) (KKTFunc, error) {

		//    Solve
		//                  -diag(z)                           = bx
		//        -diag(x) - inv(rti*rti') * z * inv(rti*rti') = bs
		//
		//    On entry, x and z contain bx and bs.
		//    On exit, they contain the solution, with z scaled
		//    (inv(rti)'*z*inv(rti) is returned instead of z).
		//
		//    We first solve
		//
		//        ((rti*rti') .* (rti*rti')) * x = bx - diag(t*bs*t)
		//
		//    and take z  = -rti' * (diag(x) + bs) * rti.

		var err error = nil
		rti := W.At("rti")[0]

		// t = rti*rti' as a nonsymmetric matrix.
		t := matrix.FloatZeros(n, n)
		err = blas.GemmFloat(rti, rti, t, 1.0, 0.0, linalg.OptTransB)
		if err != nil {
			return nil, err
		}

		// Cholesky factorization of tsq = t.*t.
		tsq := matrix.Mul(t, t)
		err = lapack.Potrf(tsq)
		if err != nil {
			return nil, err
		}

		f := func(x, y, z *matrix.FloatMatrix) (err error) {
			// tbst := t * zs * t = t * bs * t
			tbst := z.Copy()
			matrix.Reshape(tbst, n, n)
			cngrnc(t, tbst, 1.0)

			// x := x - diag(tbst) = bx - diag(rti*rti' * bs * rti*rti')
			diag := tbst.Diag().Transpose()
			x.Minus(diag)

			// x := (t.*t)^{-1} * x = (t.*t)^{-1} * (bx - diag(t*bs*t))
			err = lapack.Potrs(tsq, x)

			// z := z + diag(x) = bs + diag(x)
			// z, x are really column vectors here
			z.AddIndexes(matrix.MakeIndexSet(0, n*n, n+1), x.FloatArray())

			// z := -rti' * z * rti = -rti' * (diag(x) + bs) * rti
			cngrnc(rti, z, -1.0)
			return nil
		}
		return f, nil
	}

	c := matrix.FloatWithValue(n, 1, 1.0)

	// initial feasible x: x = 1.0 - min(lmbda(w))
	lmbda := matrix.FloatZeros(n, 1)
	wp := w.Copy()
	lapack.Syevx(wp, lmbda, nil, 0.0, nil, []int{1, 1}, linalg.OptRangeInt)
	x0 := matrix.FloatZeros(n, 1).Add(-lmbda.GetAt(0, 0) + 1.0)
	s0 := w.Copy()
	s0.Diag().Plus(x0.Transpose())
	matrix.Reshape(s0, n*n, 1)

	// initial feasible z is identity
	z0 := matrix.FloatIdentity(n)
	matrix.Reshape(z0, n*n, 1)

	dims := sets.DSetNew("l", "q", "s")
	dims.Set("s", []int{n})

	primalstart := sets.FloatSetNew("x", "s")
	dualstart := sets.FloatSetNew("z")
	primalstart.Set("x", x0)
	primalstart.Set("s", s0)
	dualstart.Set("z", z0)

	var solopts SolverOptions
	solopts.MaxIter = 30
	solopts.ShowProgress = false
	h := w.Copy()
	matrix.Reshape(h, h.NumElements(), 1)
	return ConeLpCustomMatrix(c, G, h, nil, nil, dims, Fkkt, &solopts, primalstart, dualstart)
}
Пример #3
0
//    Solution of KKT equations by reduction to a 2 x 2 system, a QR
//    factorization to eliminate the equality constraints, and a dense
//    Cholesky factorization of order n-p.
//
//    Computes the QR factorization
//
//        A' = [Q1, Q2] * [R; 0]
//
//    and returns a function that (1) computes the Cholesky factorization
//
//        Q_2^T * (H + GG^T * W^{-1} * W^{-T} * GG) * Q2 = L * L^T,
//
//    given H, Df, W, where GG = [Df; G], and (2) returns a function for
//    solving
//
//        [ H    A'   GG'    ]   [ ux ]   [ bx ]
//        [ A    0    0      ] * [ uy ] = [ by ].
//        [ GG   0    -W'*W  ]   [ uz ]   [ bz ]
//
//    H is n x n,  A is p x n, Df is mnl x n, G is N x n where
//    N = dims['l'] + sum(dims['q']) + sum( k**2 for k in dims['s'] ).
//
func kktChol(G *matrix.FloatMatrix, dims *sets.DimensionSet, A *matrix.FloatMatrix, mnl int) (kktFactor, error) {

	p, n := A.Size()
	cdim := mnl + dims.Sum("l", "q") + dims.SumSquared("s")
	cdim_pckd := mnl + dims.Sum("l", "q") + dims.SumPacked("s")

	QA := A.Transpose()
	tauA := matrix.FloatZeros(p, 1)
	lapack.Geqrf(QA, tauA)

	Gs := matrix.FloatZeros(cdim, n)
	K := matrix.FloatZeros(n, n)
	bzp := matrix.FloatZeros(cdim_pckd, 1)
	yy := matrix.FloatZeros(p, 1)
	checkpnt.AddMatrixVar("tauA", tauA)
	checkpnt.AddMatrixVar("Gs", Gs)
	checkpnt.AddMatrixVar("K", K)

	factor := func(W *sets.FloatMatrixSet, H, Df *matrix.FloatMatrix) (KKTFunc, error) {
		// Compute
		//
		//     K = [Q1, Q2]' * (H + GG' * W^{-1} * W^{-T} * GG) * [Q1, Q2]
		//
		// and take the Cholesky factorization of the 2,2 block
		//
		//     Q_2' * (H + GG^T * W^{-1} * W^{-T} * GG) * Q2.

		var err error = nil
		minor := 0
		if !checkpnt.MinorEmpty() {
			minor = checkpnt.MinorTop()
		}
		// Gs = W^{-T} * GG in packed storage.
		if mnl > 0 {
			Gs.SetSubMatrix(0, 0, Df)
		}
		Gs.SetSubMatrix(mnl, 0, G)
		checkpnt.Check("00factor_chol", minor)
		scale(Gs, W, true, true)
		pack2(Gs, dims, mnl)
		//checkpnt.Check("10factor_chol", minor)

		// K = [Q1, Q2]' * (H + Gs' * Gs) * [Q1, Q2].
		blas.SyrkFloat(Gs, K, 1.0, 0.0, la.OptTrans, &la.IOpt{"k", cdim_pckd})
		if H != nil {
			K.SetSubMatrix(0, 0, matrix.Plus(H, K.GetSubMatrix(0, 0, H.Rows(), H.Cols())))
		}
		//checkpnt.Check("20factor_chol", minor)
		symm(K, n, 0)
		lapack.Ormqr(QA, tauA, K, la.OptLeft, la.OptTrans)
		lapack.Ormqr(QA, tauA, K, la.OptRight)
		//checkpnt.Check("30factor_chol", minor)

		// Cholesky factorization of 2,2 block of K.
		lapack.Potrf(K, &la.IOpt{"n", n - p}, &la.IOpt{"offseta", p * (n + 1)})
		checkpnt.Check("40factor_chol", minor)

		solve := func(x, y, z *matrix.FloatMatrix) (err error) {
			// Solve
			//
			//     [ 0          A'  GG'*W^{-1} ]   [ ux   ]   [ bx        ]
			//     [ A          0   0          ] * [ uy   ] = [ by        ]
			//     [ W^{-T}*GG  0   -I         ]   [ W*uz ]   [ W^{-T}*bz ]
			//
			// and return ux, uy, W*uz.
			//
			// On entry, x, y, z contain bx, by, bz.  On exit, they contain
			// the solution ux, uy, W*uz.
			//
			// If we change variables ux = Q1*v + Q2*w, the system becomes
			//
			//     [ K11 K12 R ]   [ v  ]   [Q1'*(bx+GG'*W^{-1}*W^{-T}*bz)]
			//     [ K21 K22 0 ] * [ w  ] = [Q2'*(bx+GG'*W^{-1}*W^{-T}*bz)]
			//     [ R^T 0   0 ]   [ uy ]   [by                           ]
			//
			//     W*uz = W^{-T} * ( GG*ux - bz ).
			minor := 0
			if !checkpnt.MinorEmpty() {
				minor = checkpnt.MinorTop()
			}

			// bzp := W^{-T} * bz in packed storage
			scale(z, W, true, true)
			pack(z, bzp, dims, &la.IOpt{"mnl", mnl})

			// x := [Q1, Q2]' * (x + Gs' * bzp)
			//    = [Q1, Q2]' * (bx + Gs' * W^{-T} * bz)
			blas.GemvFloat(Gs, bzp, x, 1.0, 1.0, la.OptTrans, &la.IOpt{"m", cdim_pckd})
			lapack.Ormqr(QA, tauA, x, la.OptLeft, la.OptTrans)

			// y := x[:p]
			//    = Q1' * (bx + Gs' * W^{-T} * bz)
			blas.Copy(y, yy)
			blas.Copy(x, y, &la.IOpt{"n", p})

			// x[:p] := v = R^{-T} * by
			blas.Copy(yy, x)
			lapack.Trtrs(QA, x, la.OptUpper, la.OptTrans, &la.IOpt{"n", p})

			// x[p:] := K22^{-1} * (x[p:] - K21*x[:p])
			//        = K22^{-1} * (Q2' * (bx + Gs' * W^{-T} * bz) - K21*v)
			blas.GemvFloat(K, x, x, -1.0, 1.0, &la.IOpt{"m", n - p}, &la.IOpt{"n", p},
				&la.IOpt{"offseta", p}, &la.IOpt{"offsety", p})
			lapack.Potrs(K, x, &la.IOpt{"n", n - p}, &la.IOpt{"offseta", p * (n + 1)},
				&la.IOpt{"offsetb", p})

			// y := y - [K11, K12] * x
			//    = Q1' * (bx + Gs' * W^{-T} * bz) - K11*v - K12*w
			blas.GemvFloat(K, x, y, -1.0, 1.0, &la.IOpt{"m", p}, &la.IOpt{"n", n})

			// y := R^{-1}*y
			//    = R^{-1} * (Q1' * (bx + Gs' * W^{-T} * bz) - K11*v
			//      - K12*w)
			lapack.Trtrs(QA, y, la.OptUpper, &la.IOpt{"n", p})

			// x := [Q1, Q2] * x
			lapack.Ormqr(QA, tauA, x, la.OptLeft)

			// bzp := Gs * x - bzp.
			//      = W^{-T} * ( GG*ux - bz ) in packed storage.
			// Unpack and copy to z.
			blas.GemvFloat(Gs, x, bzp, 1.0, -1.0, &la.IOpt{"m", cdim_pckd})
			unpack(bzp, z, dims, &la.IOpt{"mnl", mnl})

			checkpnt.Check("90solve_chol", minor)
			return nil
		}
		return solve, err
	}
	return factor, nil
}