Пример #1
0
//
// Solves a geometric program
//
//   minimize    log sum exp (F0*x+g0)
//   subject to  log sum exp (Fi*x+gi) <= 0,  i=1,...,m
//               G*x <= h      
//               A*x = b
//
func Gp(K []int, F, g, G, h, A, b *matrix.FloatMatrix, solopts *SolverOptions) (sol *Solution, err error) {

    if err = checkArgK(K); err != nil {
        return
    }
    l := sumdim(K)

    if F == nil || F.Rows() != l {
        err = errors.New(fmt.Sprintf("'F' must matrix with %d rows", l))
        return
    }

    if g == nil || !g.SizeMatch(l, 1) {
        err = errors.New(fmt.Sprintf("'g' must matrix with size (%d,1)", l))
        return
    }
    n := F.Cols()

    if G == nil {
        G = matrix.FloatZeros(0, n)
    }
    if h == nil {
        h = matrix.FloatZeros(0, 1)
    }
    if G.Cols() != n {
        err = errors.New(fmt.Sprintf("'G' must matrix with size %d columns", n))
        return
    }
    ml := G.Rows()
    if h == nil || !h.SizeMatch(ml, 1) {
        err = errors.New(fmt.Sprintf("'h' must matrix with size (%d,1)", ml))
        return
    }

    if A == nil {
        A = matrix.FloatZeros(0, n)
    }
    if b == nil {
        b = matrix.FloatZeros(0, 1)
    }
    if A.Cols() != n {
        err = errors.New(fmt.Sprintf("'A' must matrix with size %d columns", n))
        return
    }
    p := A.Rows()
    if b == nil || !b.SizeMatch(p, 1) {
        err = errors.New(fmt.Sprintf("'b' must matrix with size (%d,1)", p))
        return
    }

    dims := sets.NewDimensionSet("l", "q", "s")
    dims.Set("l", []int{ml})
    gpProg := createGpProg(K, F, g)

    return Cp(gpProg, G, h, A, b, dims, solopts)
}
Пример #2
0
// Solves a pair of primal and dual LPs
//
//      minimize    c'*x
//      subject to  G*x + s = h
//                  A*x = b
//                  s >= 0
//
//      maximize    -h'*z - b'*y
//      subject to  G'*z + A'*y + c = 0
//                    z >= 0.
//
func Lp(c, G, h, A, b *matrix.FloatMatrix, solopts *SolverOptions,
	primalstart, dualstart *sets.FloatMatrixSet) (sol *Solution, err error) {

	if c == nil {
		err = errors.New("'c' must a column matrix")
		return
	}
	n := c.Rows()
	if n < 1 {
		err = errors.New("Number of variables must be at least 1")
		return
	}
	if G == nil || G.Cols() != n {
		err = errors.New(fmt.Sprintf("'G' must be matrix with %d columns", n))
		return
	}
	m := G.Rows()
	if h == nil || !h.SizeMatch(m, 1) {
		err = errors.New(fmt.Sprintf("'h' must be matrix of size (%d,1)", m))
		return
	}
	if A == nil {
		A = matrix.FloatZeros(0, n)
	}
	if A.Cols() != n {
		err = errors.New(fmt.Sprintf("'A' must be matrix with %d columns", n))
		return
	}
	p := A.Rows()
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if !b.SizeMatch(p, 1) {
		err = errors.New(fmt.Sprintf("'b' must be matrix of size (%d,1)", p))
		return
	}
	dims := sets.NewDimensionSet("l", "q", "s")
	dims.Set("l", []int{m})

	return ConeLp(c, G, h, A, b, dims, solopts, primalstart, dualstart)
}
Пример #3
0
// min(x) st. x+y = 1, x >= y
func TestSimple(t *testing.T) {

	A := matrix.FloatNew(2, 3, []float64{1.0, -1.0, 0.0, 1.0, 0.0, 1.0})
	b := matrix.FloatNew(2, 1, []float64{1.0, 0.0})
	c := matrix.FloatNew(3, 1, []float64{0.0, 1.0, 0.0})
	G := matrix.FloatNew(1, 3, []float64{0.0, -1.0, 1.0})
	h := matrix.FloatNew(1, 1, []float64{0.0})
	dims := sets.NewDimensionSet("l", "q", "s")
	dims.Set("l", []int{1})

	t.Logf("A=\n%v\n", A)
	t.Logf("b=\n%v\n", b)
	t.Logf("G=\n%v\n", G)
	t.Logf("h=\n%v\n", h)
	t.Logf("c=\n%v\n", c)

	// this should work...
	t.Logf("Ldl solver ...\n")
	sol, err := solve("ldl", c, G, h, A, b)
	if sol != nil && sol.Status == Optimal {
		x := sol.Result.At("x")[0]
		s := sol.Result.At("s")[0]
		z := sol.Result.At("z")[0]
		t.Logf("x=\n%v\n", x.ToString("%.9f"))
		t.Logf("s=\n%v\n", s.ToString("%.9f"))
		t.Logf("z=\n%v\n", z.ToString("%.9f"))
	} else {
		t.Logf("status: %v\n", err)
		t.Fail()
	}

	// this should work too
	t.Logf("chol2 solver ...\n")
	sol, err = solve("chol2", c, G, h, A, b)
	if err != nil {
		t.Logf("chol2 status: %v\n", err)
		t.Fail()
	}
}
Пример #4
0
// The analytic centering with cone constraints example of section 9.1
// (Problems with nonlinear objectives).
func TestCp(t *testing.T) {

	xref := []float64{0.41132359189354400, 0.55884774432611484, -0.72007090016957931}

	F := &acenterProg{3, 1}

	gdata := [][]float64{
		[]float64{0., -1., 0., 0., -21., -11., 0., -11., 10., 8., 0., 8., 5.},
		[]float64{0., 0., -1., 0., 0., 10., 16., 10., -10., -10., 16., -10., 3.},
		[]float64{0., 0., 0., -1., -5., 2., -17., 2., -6., 8., -17., -7., 6.}}

	G := matrix.FloatMatrixFromTable(gdata)
	h := matrix.FloatVector(
		[]float64{1.0, 0.0, 0.0, 0.0, 20., 10., 40., 10., 80., 10., 40., 10., 15.})

	var solopts SolverOptions
	solopts.MaxIter = 40
	solopts.ShowProgress = false

	dims := sets.NewDimensionSet("l", "q", "s")
	dims.Set("l", []int{0})
	dims.Set("q", []int{4})
	dims.Set("s", []int{3})

	sol, err := Cp(F, G, h, nil, nil, dims, &solopts)
	if err == nil && sol.Status == Optimal {
		x := sol.Result.At("x")[0]
		t.Logf("x = \n%v\n", x.ToString("%.9f"))
		xe, _ := nrmError(matrix.FloatVector(xref), x)
		if xe > TOL {
			t.Logf("x differs [%.3e] from exepted too much.", xe)
			t.Fail()
		}
	} else {
		t.Logf("result: %v\n", err)
		t.Fail()
	}
}
Пример #5
0
// Solves a pair of primal and dual SOCPs
//
//     minimize    c'*x
//     subject to  Gl*x + sl = hl
//                 Gq[k]*x + sq[k] = hq[k],  k = 0, ..., N-1
//                 A*x = b
//                 sl >= 0,
//                 sq[k] >= 0, k = 0, ..., N-1
//
//     maximize   -hl'*z - sum_k hq[k]'*zq[k] - b'*y
//     subject to  Gl'*zl + sum_k Gq[k]'*zq[k] + A'*y + c = 0
//                 zl >= 0,  zq[k] >= 0, k = 0, ..., N-1.
//
// The inequalities sl >= 0 and zl >= 0 are elementwise vector
// inequalities.  The inequalities sq[k] >= 0, zq[k] >= 0 are second
// order cone inequalities, i.e., equivalent to
//
//     sq[k][0] >= || sq[k][1:] ||_2,  zq[k][0] >= || zq[k][1:] ||_2.
//
func Socp(c, Gl, hl, A, b *matrix.FloatMatrix, Ghq *sets.FloatMatrixSet, solopts *SolverOptions,
	primalstart, dualstart *sets.FloatMatrixSet) (sol *Solution, err error) {
	if c == nil {
		err = errors.New("'c' must a column matrix")
		return
	}
	n := c.Rows()
	if n < 1 {
		err = errors.New("Number of variables must be at least 1")
		return
	}
	if Gl == nil {
		Gl = matrix.FloatZeros(0, n)
	}
	if Gl.Cols() != n {
		err = errors.New(fmt.Sprintf("'G' must be matrix with %d columns", n))
		return
	}
	ml := Gl.Rows()
	if hl == nil {
		hl = matrix.FloatZeros(0, 1)
	}
	if !hl.SizeMatch(ml, 1) {
		err = errors.New(fmt.Sprintf("'hl' must be matrix of size (%d,1)", ml))
		return
	}
	Gqset := Ghq.At("Gq")
	mq := make([]int, 0)
	for i, Gq := range Gqset {
		if Gq.Cols() != n {
			err = errors.New(fmt.Sprintf("'Gq' must be list of matrices with %d columns", n))
			return
		}
		if Gq.Rows() == 0 {
			err = errors.New(fmt.Sprintf("the number of rows of 'Gq[%d]' is zero", i))
			return
		}
		mq = append(mq, Gq.Rows())
	}
	hqset := Ghq.At("hq")
	if len(Gqset) != len(hqset) {
		err = errors.New(fmt.Sprintf("'hq' must be a list of %d matrices", len(Gqset)))
		return
	}
	for i, hq := range hqset {
		if !hq.SizeMatch(Gqset[i].Rows(), 1) {
			s := fmt.Sprintf("hq[%d] has size (%d,%d). Expected size is (%d,1)",
				i, hq.Rows(), hq.Cols(), Gqset[i].Rows())
			err = errors.New(s)
			return
		}
	}
	if A == nil {
		A = matrix.FloatZeros(0, n)
	}
	if A.Cols() != n {
		err = errors.New(fmt.Sprintf("'A' must be matrix with %d columns", n))
		return
	}
	p := A.Rows()
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if !b.SizeMatch(p, 1) {
		err = errors.New(fmt.Sprintf("'b' must be matrix of size (%d,1)", p))
		return
	}
	dims := sets.NewDimensionSet("l", "q", "s")
	dims.Set("l", []int{ml})
	dims.Set("q", mq)
	//N := dims.Sum("l", "q")

	hargs := make([]*matrix.FloatMatrix, 0, len(hqset)+1)
	hargs = append(hargs, hl)
	hargs = append(hargs, hqset...)
	h, indh := matrix.FloatMatrixStacked(matrix.StackDown, hargs...)

	Gargs := make([]*matrix.FloatMatrix, 0, len(Gqset)+1)
	Gargs = append(Gargs, Gl)
	Gargs = append(Gargs, Gqset...)
	G, indg := matrix.FloatMatrixStacked(matrix.StackDown, Gargs...)

	var pstart, dstart *sets.FloatMatrixSet = nil, nil
	if primalstart != nil {
		pstart = sets.NewFloatSet("x", "s")
		pstart.Set("x", primalstart.At("x")[0])
		slset := primalstart.At("sl")
		margs := make([]*matrix.FloatMatrix, 0, len(slset)+1)
		margs = append(margs, primalstart.At("s")[0])
		margs = append(margs, slset...)
		sl, _ := matrix.FloatMatrixStacked(matrix.StackDown, margs...)
		pstart.Set("s", sl)
	}

	if dualstart != nil {
		dstart = sets.NewFloatSet("y", "z")
		dstart.Set("y", dualstart.At("y")[0])
		zlset := primalstart.At("zl")
		margs := make([]*matrix.FloatMatrix, 0, len(zlset)+1)
		margs = append(margs, dualstart.At("z")[0])
		margs = append(margs, zlset...)
		zl, _ := matrix.FloatMatrixStacked(matrix.StackDown, margs...)
		dstart.Set("z", zl)
	}

	sol, err = ConeLp(c, G, h, A, b, dims, solopts, pstart, dstart)
	// unpack sol.Result
	if err == nil {
		s := sol.Result.At("s")[0]
		sl := matrix.FloatVector(s.FloatArray()[:ml])
		sol.Result.Append("sl", sl)
		ind := ml
		for _, k := range indh[1:] {
			sk := matrix.FloatVector(s.FloatArray()[ind : ind+k])
			sol.Result.Append("sq", sk)
			ind += k
		}

		z := sol.Result.At("z")[0]
		zl := matrix.FloatVector(z.FloatArray()[:ml])
		sol.Result.Append("zl", zl)
		ind = ml
		for _, k := range indg[1:] {
			zk := matrix.FloatVector(z.FloatArray()[ind : ind+k])
			sol.Result.Append("zq", zk)
			ind += k
		}
	}
	sol.Result.Remove("s")
	sol.Result.Remove("z")

	return
}
Пример #6
0
// Solves a convex optimization problem with a linear objective
//
//        minimize    c'*x
//        subject to  f(x) <= 0
//                    G*x <= h
//                    A*x = b.
//
// f is vector valued, convex and twice differentiable.  The linear
// inequalities are with respect to a cone C defined as the Cartesian
// product of N + M + 1 cones:
//
//        C = C_0 x C_1 x .... x C_N x C_{N+1} x ... x C_{N+M}.
//
// The first cone C_0 is the nonnegative orthant of dimension ml.  The
// next N cones are second order cones of dimension r[0], ..., r[N-1].
// The second order cone of dimension m is defined as
//
//        { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }.
//
// The next M cones are positive semidefinite cones of order t[0], ..., t[M-1] >= 0.
//
// The structure of C is specified by DimensionSet dims which holds following sets
//
//   dims.At("l")  l, the dimension of the nonnegative orthant (array of length 1)
//   dims.At("q")  r[0], ... r[N-1], list with the dimesions of the second-order cones
//   dims.At("s")  t[0], ... t[M-1], array with the dimensions of the positive
//                 semidefinite cones
//
// The default value for dims is l: []int{h.Rows()}, q: []int{}, s: []int{}.
//
// On exit Solution contains the result and information about the accurancy of the
// solution. if SolutionStatus is Optimal then Solution.Result contains solutions
// for the problems.
//
//   Result.At("x")[0]    primal solution
//   Result.At("snl")[0]  non-linear constraint slacks
//   Result.At("sl")[0]   linear constraint slacks
//   Result.At("y")[0]    values for linear equality constraints y
//   Result.At("znl")[0]  values of dual variables for nonlinear inequalities
//   Result.At("zl")[0]   values of dual variables for linear inequalities
//
// If err is non-nil then sol is nil and err contains information about the argument or
// computation error.
//
func Cpl(F ConvexProg, c, G, h, A, b *matrix.FloatMatrix, dims *sets.DimensionSet, solopts *SolverOptions) (sol *Solution, err error) {

	var mnl int
	var x0 *matrix.FloatMatrix

	mnl, x0, err = F.F0()
	if err != nil {
		return
	}

	if x0.Cols() != 1 {
		err = errors.New("'x0' must be matrix with one column")
		return
	}
	if c == nil {
		err = errors.New("'c' must be non nil matrix")
		return
	}
	if !c.SizeMatch(x0.Size()) {
		err = errors.New(fmt.Sprintf("'c' must be matrix of size (%d,1)", x0.Rows()))
		return
	}

	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() > 1 {
		err = errors.New("'h' must be matrix with 1 column")
		return
	}

	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}

	cdim := dims.Sum("l", "q") + dims.SumSquared("s")
	//cdim_pckd := dims.Sum("l", "q") + dims.SumPacked("s")
	//cdim_diag := dims.Sum("l", "q", "s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	if G == nil {
		G = matrix.FloatZeros(0, c.Rows())
	}
	if !G.SizeMatch(cdim, c.Rows()) {
		estr := fmt.Sprintf("'G' must be of size (%d,%d)", cdim, c.Rows())
		err = errors.New(estr)
		return
	}

	// Check A and set defaults if it is nil
	if A == nil {
		// zeros rows reduces Gemv to vector products
		A = matrix.FloatZeros(0, c.Rows())
	}
	if A.Cols() != c.Rows() {
		estr := fmt.Sprintf("'A' must have %d columns", c.Rows())
		err = errors.New(estr)
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}
	if b.Rows() != A.Rows() {
		estr := fmt.Sprintf("'b' must have length %d", A.Rows())
		err = errors.New(estr)
		return
	}

	var mc = matrixVar{c}
	var mb = matrixVar{b}
	var mA = matrixVarA{A}
	var mG = matrixVarG{G, dims}

	solvername := solopts.KKTSolverName
	if len(solvername) == 0 {
		if len(dims.At("q")) > 0 || len(dims.At("s")) > 0 {
			solvername = "chol"
		} else {
			solvername = "chol2"
		}
	}

	var factor kktFactor
	var kktsolver KKTCpSolver = nil
	if kktfunc, ok := solvers[solvername]; ok {
		// kkt function returns us problem spesific factor function.
		factor, err = kktfunc(G, dims, A, mnl)
		// solver is
		kktsolver = func(W *sets.FloatMatrixSet, x, z *matrix.FloatMatrix) (KKTFunc, error) {
			_, Df, H, err := F.F2(x, z)
			if err != nil {
				return nil, err
			}
			return factor(W, H, Df)
		}
	} else {
		err = errors.New(fmt.Sprintf("solver '%s' not known", solvername))
		return
	}

	//return CplCustom(F, c, &mG, h, &mA, b, dims, kktsolver, solopts)
	return cpl_problem(F, &mc, &mG, h, &mA, &mb, dims, kktsolver, solopts, x0, mnl)
}
Пример #7
0
// Solves a convex optimization problem with a linear objective
//
//        minimize    c'*x
//        subject to  f(x) <= 0
//                    G*x <= h
//                    A*x = b.
//
// using custom KTT equation solver and custom constraints G and A.
//
func CplCustomMatrix(F ConvexProg, c *matrix.FloatMatrix, G MatrixG, h *matrix.FloatMatrix,
	A MatrixA, b *matrix.FloatMatrix, dims *sets.DimensionSet, kktsolver KKTCpSolver,
	solopts *SolverOptions) (sol *Solution, err error) {

	var mnl int
	var x0 *matrix.FloatMatrix

	mnl, x0, err = F.F0()
	if err != nil {
		return
	}

	if x0.Cols() != 1 {
		err = errors.New("'x0' must be matrix with one column")
		return
	}
	if c == nil {
		err = errors.New("'c' must be non nil matrix")
		return
	}
	if !c.SizeMatch(x0.Size()) {
		err = errors.New(fmt.Sprintf("'c' must be matrix of size (%d,1)", x0.Rows()))
		return
	}

	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() > 1 {
		err = errors.New("'h' must be matrix with 1 column")
		return
	}

	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}

	cdim := dims.Sum("l", "q") + dims.SumSquared("s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}

	mc := matrixVar{c}
	mb := matrixVar{b}
	var mG MatrixVarG
	var mA MatrixVarA

	if G == nil {
		mG = &matrixVarG{matrix.FloatZeros(0, c.Rows()), dims}
	} else {
		mG = &matrixIfG{G}
	}
	if A == nil {
		mA = &matrixVarA{matrix.FloatZeros(0, c.Rows())}
	} else {
		mA = &matrixIfA{A}
	}

	return cpl_problem(F, &mc, mG, h, mA, &mb, dims, kktsolver, solopts, x0, mnl)
}
Пример #8
0
// Solves a convex optimization problem with a linear objective
//
//        minimize    c'*x
//        subject to  f(x) <= 0
//                    G*x <= h
//                    A*x = b.
//
// using custom KTT equation solver.
//
func CplCustomKKT(F ConvexProg, c *matrix.FloatMatrix, G, h, A, b *matrix.FloatMatrix,
	dims *sets.DimensionSet, kktsolver KKTCpSolver,
	solopts *SolverOptions) (sol *Solution, err error) {

	var mnl int
	var x0 *matrix.FloatMatrix

	mnl, x0, err = F.F0()
	if err != nil {
		return
	}

	if x0.Cols() != 1 {
		err = errors.New("'x0' must be matrix with one column")
		return
	}
	if c == nil {
		err = errors.New("'c' must be non nil matrix")
		return
	}
	if !c.SizeMatch(x0.Size()) {
		err = errors.New(fmt.Sprintf("'c' must be matrix of size (%d,1)", x0.Rows()))
		return
	}

	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() > 1 {
		err = errors.New("'h' must be matrix with 1 column")
		return
	}

	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}

	cdim := dims.Sum("l", "q") + dims.SumSquared("s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	if G == nil {
		G = matrix.FloatZeros(0, c.Rows())
	}
	if !G.SizeMatch(cdim, c.Rows()) {
		estr := fmt.Sprintf("'G' must be of size (%d,%d)", cdim, c.Rows())
		err = errors.New(estr)
		return
	}

	// Check A and set defaults if it is nil
	if A == nil {
		// zeros rows reduces Gemv to vector products
		A = matrix.FloatZeros(0, c.Rows())
	}
	if A.Cols() != c.Rows() {
		estr := fmt.Sprintf("'A' must have %d columns", c.Rows())
		err = errors.New(estr)
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}
	if b.Rows() != A.Rows() {
		estr := fmt.Sprintf("'b' must have length %d", A.Rows())
		err = errors.New(estr)
		return
	}

	var mc = matrixVar{c}
	var mb = matrixVar{b}
	var mA = matrixVarA{A}
	var mG = matrixVarG{G, dims}

	return cpl_problem(F, &mc, &mG, h, &mA, &mb, dims, kktsolver, solopts, x0, mnl)
}
Пример #9
0
// Solves a pair of primal and dual convex quadratic cone programs
//
//        minimize    (1/2)*x'*P*x + q'*x
//        subject to  G*x + s = h
//                    A*x = b
//                    s >= 0
//
//        maximize    -(1/2)*(q + G'*z + A'*y)' * pinv(P) * (q + G'*z + A'*y)
//                    - h'*z - b'*y
//        subject to  q + G'*z + A'*y in range(P)
//                    z >= 0.
//
// The inequalities are with respect to a cone C defined as the Cartesian
// product of N + M + 1 cones:
//
//        C = C_0 x C_1 x .... x C_N x C_{N+1} x ... x C_{N+M}.
//
// The first cone C_0 is the nonnegative orthant of dimension ml.
// The next N cones are 2nd order cones of dimension r[0], ..., r[N-1].
// The second order cone of dimension m is defined as
//
//        { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }.
//
// The next M cones are positive semidefinite cones of order t[0], ..., t[M-1] >= 0.
//
// The structure of C is specified by DimensionSet dims which holds following sets
//
//   dims.At("l")  l, the dimension of the nonnegative orthant (array of length 1)
//   dims.At("q")  r[0], ... r[N-1], list with the dimesions of the second-order cones
//   dims.At("s")  t[0], ... t[M-1], array with the dimensions of the positive
//                 semidefinite cones
//
// The default value for dims is l: []int{G.Rows()}, q: []int{}, s: []int{}.
//
// Argument initval contains optional starting points for primal and
// dual problems. If non-nil then initval is a FloatMatrixSet having following entries.
//
//  initvals.At("x")[0]  starting point for x
//  initvals.At("s")[0]  starting point for s
//  initvals.At("y")[0]  starting point for y
//  initvals.At("z")[0]  starting point for z
//
// On exit Solution contains the result and information about the accurancy of the
// solution. if SolutionStatus is Optimal then Solution.Result contains solutions
// for the problems.
//
//   Result.At("x")[0]  solution for x
//   Result.At("y")[0]  solution for y
//   Result.At("s")[0]  solution for s
//   Result.At("z")[0]  solution for z
//
func ConeQp(P, q, G, h, A, b *matrix.FloatMatrix, dims *sets.DimensionSet, solopts *SolverOptions,
	initvals *sets.FloatMatrixSet) (sol *Solution, err error) {

	if q == nil || q.Cols() != 1 {
		err = errors.New("'q' must be non-nil matrix with one column")
		return
	}
	if P == nil || P.Rows() != q.Rows() || P.Cols() != q.Rows() {
		err = errors.New(fmt.Sprintf("'P' must be non-nil matrix of size (%d, %d)",
			q.Rows(), q.Rows()))
		return
	}

	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() != 1 {
		err = errors.New("'h' must be non-nil matrix with one column")
		return
	}
	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}

	err = checkConeQpDimensions(dims)
	if err != nil {
		return
	}

	cdim := dims.Sum("l", "q") + dims.SumSquared("s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	if G == nil {
		G = matrix.FloatZeros(0, q.Rows())
	}
	if !G.SizeMatch(cdim, q.Rows()) {
		estr := fmt.Sprintf("'G' must be of size (%d,%d)", cdim, q.Rows())
		err = errors.New(estr)
		return
	}

	// Check A and set defaults if it is nil
	if A == nil {
		// zeros rows reduces Gemv to vector products
		A = matrix.FloatZeros(0, q.Rows())
	}
	if A.Cols() != q.Rows() {
		estr := fmt.Sprintf("'A' must have %d columns", q.Rows())
		err = errors.New(estr)
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}
	if b.Rows() != A.Rows() {
		estr := fmt.Sprintf("'b' must have length %d", A.Rows())
		err = errors.New(estr)
		return
	}

	solvername := solopts.KKTSolverName
	if len(solvername) == 0 {
		if len(dims.At("q")) > 0 || len(dims.At("s")) > 0 {
			solvername = "ldl"
		} else {
			solvername = "chol2"
		}
	}

	var factor kktFactor
	var kktsolver KKTConeSolver = nil
	if kktfunc, ok := solvers[solvername]; ok {
		// kkt function returns us problem spesific factor function.
		factor, err = kktfunc(G, dims, A, 0)
		if err != nil {
			return nil, err
		}
		kktsolver = func(W *sets.FloatMatrixSet) (KKTFunc, error) {
			return factor(W, P, nil)
		}
	} else {
		err = errors.New(fmt.Sprintf("solver '%s' not known", solvername))
		return
	}

	mA := &matrixVarA{A}
	mG := &matrixVarG{G, dims}
	mP := &matrixVarP{P}
	mq := &matrixVar{q}
	mb := &matrixVar{b}

	return coneqp_problem(mP, mq, mG, h, mA, mb, dims, kktsolver, solopts, initvals)
}
Пример #10
0
// Solves a convex optimization problem with a linear objective
//
//       minimize    f0(x)
//       subject to  fk(x) <= 0, k = 1, ..., mnl
//                   G*x   <= h
//                   A*x    = b.
//
// f is vector valued, convex and twice differentiable.  The linear
// inequalities are with respect to a cone C defined as the Cartesian
// product of N + M + 1 cones:
//
//        C = C_0 x C_1 x .... x C_N x C_{N+1} x ... x C_{N+M}.
//
// The first cone C_0 is the nonnegative orthant of dimension ml.  The
// next N cones are second order cones of dimension r[0], ..., r[N-1].
// The second order cone of dimension m is defined as
//
//        { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }.
//
// The next M cones are positive semidefinite cones of order t[0], ..., t[M-1] >= 0.
//
// The structure of C is specified by DimensionSet dims which holds following sets
//
//   dims.At("l")  l, the dimension of the nonnegative orthant (array of length 1)
//   dims.At("q")  r[0], ... r[N-1], list with the dimesions of the second-order cones
//   dims.At("s")  t[0], ... t[M-1], array with the dimensions of the positive
//                 semidefinite cones
//
// The default value for dims is l: []int{h.Rows()}, q: []int{}, s: []int{}.
//
// On exit Solution contains the result and information about the accurancy of the
// solution. if SolutionStatus is Optimal then Solution.Result contains solutions
// for the problems.
//
//   Result.At("x")[0]    primal solution
//   Result.At("snl")[0]  non-linear constraint slacks
//   Result.At("sl")[0]   linear constraint slacks
//   Result.At("y")[0]    values for linear equality constraints y
//   Result.At("znl")[0]  values of dual variables for nonlinear inequalities
//   Result.At("zl")[0]   values of dual variables for linear inequalities
//
// If err is non-nil then sol is nil and err contains information about the argument or
// computation error.
//
func Cp(F ConvexProg, G, h, A, b *matrix.FloatMatrix, dims *sets.DimensionSet, solopts *SolverOptions) (sol *Solution, err error) {

	var mnl int
	var x0 *matrix.FloatMatrix

	mnl, x0, err = F.F0()
	if err != nil {
		return
	}

	if x0.Cols() != 1 {
		err = errors.New("'x0' must be matrix with one column")
		return
	}
	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() > 1 {
		err = errors.New("'h' must be matrix with 1 column")
		return
	}

	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}
	if err = checkConeLpDimensions(dims); err != nil {
		return
	}
	cdim := dims.Sum("l", "q") + dims.SumSquared("s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	if G == nil {
		G = matrix.FloatZeros(0, x0.Rows())
	}
	if !G.SizeMatch(cdim, x0.Rows()) {
		estr := fmt.Sprintf("'G' must be of size (%d,%d)", cdim, x0.Rows())
		err = errors.New(estr)
		return
	}

	// Check A and set defaults if it is nil
	if A == nil {
		// zeros rows reduces Gemv to vector products
		A = matrix.FloatZeros(0, x0.Rows())
	}
	if A.Cols() != x0.Rows() {
		estr := fmt.Sprintf("'A' must have %d columns", x0.Rows())
		err = errors.New(estr)
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}
	if b.Rows() != A.Rows() {
		estr := fmt.Sprintf("'b' must have length %d", A.Rows())
		err = errors.New(estr)
		return
	}

	solvername := solopts.KKTSolverName
	if len(solvername) == 0 {
		if len(dims.At("q")) > 0 || len(dims.At("s")) > 0 {
			solvername = "chol"
		} else {
			solvername = "chol2"
		}
	}

	c_e := newEpigraph(x0, 1.0)
	blas.ScalFloat(c_e.m(), 0.0)
	//F_e := &cpProg{F}
	G_e := epMatrixG{G, dims}
	A_e := epMatrixA{A}
	b_e := matrixVar{b}

	var factor kktFactor
	var kktsolver KKTCpSolver = nil
	if kktfunc, ok := solvers[solvername]; ok {
		// kkt function returns us problem spesific factor function.
		factor, err = kktfunc(G, dims, A, mnl)
		if err != nil {
			return nil, err
		}
		// solver is
		kktsolver = func(W *sets.FloatMatrixSet, x, z *matrix.FloatMatrix) (KKTFunc, error) {
			_, Df, H, err := F.F2(x, z)
			if err != nil {
				return nil, err
			}
			return factor(W, H, Df.GetSubMatrix(1, 0))
		}
	} else {
		err = errors.New(fmt.Sprintf("solver '%s' not known", solvername))
		return
	}

	return cp_problem(F, c_e, &G_e, h, &A_e, &b_e, dims, kktsolver, solopts, x0, mnl)
}
Пример #11
0
// Solves a pair of primal and dual cone programs using custom KKT solver and custom
// matrices P, G and A.
//
// P must implement interface MatrixP, G must implement interface MatrixG
// and A must implement interface MatrixA.
//
func ConeQpCustomMatrix(P MatrixP, q *matrix.FloatMatrix, G MatrixG, h *matrix.FloatMatrix,
	A MatrixA, b *matrix.FloatMatrix, dims *sets.DimensionSet, kktsolver KKTConeSolver,
	solopts *SolverOptions, initvals *sets.FloatMatrixSet) (sol *Solution, err error) {

	err = nil

	if q == nil || q.Cols() != 1 {
		err = errors.New("'q' must be non-nil matrix with one column")
		return
	}

	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() != 1 {
		err = errors.New("'h' must be non-nil matrix with one column")
		return
	}
	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}

	err = checkConeQpDimensions(dims)
	if err != nil {
		return
	}

	cdim := dims.Sum("l", "q") + dims.SumSquared("s")
	//cdim_diag := dims.Sum("l", "q", "s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	if P == nil {
		err = errors.New("'P' must be non-nil MatrixP interface.")
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}

	if b.Rows() > q.Rows() {
		err = errors.New("Rank(A) < p or Rank[G; A] < n")
		return
	}

	if kktsolver == nil {
		err = errors.New("nil kktsolver not allowed.")
		return
	}

	var mG MatrixVarG
	var mP MatrixVarP
	var mA MatrixVarA

	if A == nil {
		mA = &matrixVarA{matrix.FloatZeros(0, q.Rows())}
	} else {
		mA = &matrixIfA{A}
	}
	if G == nil {
		mG = &matrixVarG{matrix.FloatZeros(0, q.Rows()), dims}
	} else {
		mG = &matrixIfG{G}
	}
	mP = &matrixIfP{P}

	mq := &matrixVar{q}
	mb := &matrixVar{b}

	return coneqp_problem(mP, mq, mG, h, mA, mb, dims, kktsolver, solopts, initvals)
}
Пример #12
0
// Solves a pair of primal and dual convex quadratic cone programs using custom KKT solver.
//
func ConeQpCustomKKT(P, q, G, h, A, b *matrix.FloatMatrix, dims *sets.DimensionSet, kktsolver KKTConeSolver,
	solopts *SolverOptions, initvals *sets.FloatMatrixSet) (sol *Solution, err error) {

	if q == nil || q.Cols() != 1 {
		err = errors.New("'q' must be non-nil matrix with one column")
		return
	}
	if P == nil || P.Rows() != q.Rows() || P.Cols() != q.Rows() {
		err = errors.New(fmt.Sprintf("'P' must be non-nil matrix of size (%d, %d)",
			q.Rows(), q.Rows()))
		return
	}

	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() != 1 {
		err = errors.New("'h' must be non-nil matrix with one column")
		return
	}
	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}

	err = checkConeQpDimensions(dims)
	if err != nil {
		return
	}

	cdim := dims.Sum("l", "q") + dims.SumSquared("s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	if G == nil {
		G = matrix.FloatZeros(0, q.Rows())
	}
	if !G.SizeMatch(cdim, q.Rows()) {
		estr := fmt.Sprintf("'G' must be of size (%d,%d)", cdim, q.Rows())
		err = errors.New(estr)
		return
	}

	// Check A and set defaults if it is nil
	if A == nil {
		// zeros rows reduces Gemv to vector products
		A = matrix.FloatZeros(0, q.Rows())
	}
	if A.Cols() != q.Rows() {
		estr := fmt.Sprintf("'A' must have %d columns", q.Rows())
		err = errors.New(estr)
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}
	if b.Rows() != A.Rows() {
		estr := fmt.Sprintf("'b' must have length %d", A.Rows())
		err = errors.New(estr)
		return
	}

	if kktsolver == nil {
		err = errors.New("nil kktsolver not allowed")
		return
	}

	mA := &matrixVarA{A}
	mG := &matrixVarG{G, dims}
	mP := &matrixVarP{P}
	mq := &matrixVar{q}
	mb := &matrixVar{b}

	return coneqp_problem(mP, mq, mG, h, mA, mb, dims, kktsolver, solopts, initvals)
}
Пример #13
0
// Solves a pair of primal and dual cone programs  using custom KKT solver.
//
func ConeLpCustomKKT(c, G, h, A, b *matrix.FloatMatrix, dims *sets.DimensionSet,
	kktsolver KKTConeSolver, solopts *SolverOptions, primalstart,
	dualstart *sets.FloatMatrixSet) (sol *Solution, err error) {

	if c == nil || c.Cols() > 1 {
		err = errors.New("'c' must be matrix with 1 column")
		return
	}
	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() > 1 {
		err = errors.New("'h' must be matrix with 1 column")
		return
	}

	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}
	cdim := dims.Sum("l", "q") + dims.SumSquared("s")
	cdim_pckd := dims.Sum("l", "q") + dims.SumPacked("s")
	//cdim_diag := dims.Sum("l", "q", "s")

	if G == nil {
		G = matrix.FloatZeros(0, c.Rows())
	}
	if !G.SizeMatch(cdim, c.Rows()) {
		estr := fmt.Sprintf("'G' must be of size (%d,%d)", cdim, c.Rows())
		err = errors.New(estr)
		return
	}

	// Check A and set defaults if it is nil
	if A == nil {
		// zeros rows reduces Gemv to vector products
		A = matrix.FloatZeros(0, c.Rows())
	}
	if A.Cols() != c.Rows() {
		estr := fmt.Sprintf("'A' must have %d columns", c.Rows())
		err = errors.New(estr)
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}
	if b.Rows() != A.Rows() {
		estr := fmt.Sprintf("'b' must have length %d", A.Rows())
		err = errors.New(estr)
		return
	}

	if b.Rows() > c.Rows() || b.Rows()+cdim_pckd < c.Rows() {
		err = errors.New("Rank(A) < p or Rank([G; A]) < n")
		return
	}

	mA := &matrixVarA{A}
	mG := &matrixVarG{G, dims}
	mc := &matrixVar{c}
	mb := &matrixVar{b}

	return conelp_problem(mc, mG, h, mA, mb, dims, kktsolver, solopts, primalstart, dualstart)
}
Пример #14
0
// Solves a pair of primal and dual cone programs
//
//        minimize    c'*x
//        subject to  G*x + s = h
//                    A*x = b
//                    s >= 0
//
//        maximize    -h'*z - b'*y
//        subject to  G'*z + A'*y + c = 0
//                    z >= 0.
//
// The inequalities are with respect to a cone C defined as the Cartesian
// product of N + M + 1 cones:
//
//        C = C_0 x C_1 x .... x C_N x C_{N+1} x ... x C_{N+M}.
//
// The first cone C_0 is the nonnegative orthant of dimension ml.
// The next N cones are second order cones of dimension r[0], ..., r[N-1].
// The second order cone of dimension m is defined as
//
//        { (u0, u1) in R x R^{m-1} | u0 >= ||u1||_2 }.
//
// The next M cones are positive semidefinite cones of order t[0], ..., t[M-1] >= 0.
//
// The structure of C is specified by DimensionSet dims which holds following sets
//
//   dims.At("l")  l, the dimension of the nonnegative orthant (array of length 1)
//   dims.At("q")  r[0], ... r[N-1], list with the dimesions of the second-order cones
//   dims.At("s")  t[0], ... t[M-1], array with the dimensions of the positive
//                 semidefinite cones
//
// The default value for dims is l: []int{G.Rows()}, q: []int{}, s: []int{}.
//
// Arguments primalstart, dualstart are optional starting points for primal and
// dual problems. If non-nil then primalstart is a FloatMatrixSet having two entries.
//
//  primalstart.At("x")[0]  starting point for x
//  primalstart.At("s")[0]  starting point for s
//  dualstart.At("y")[0]    starting point for y
//  dualstart.At("z")[0]    starting point for z
//
// On exit Solution contains the result and information about the accurancy of the
// solution. if SolutionStatus is Optimal then Solution.Result contains solutions
// for the problems.
//
//   Result.At("x")[0]  solution for x
//   Result.At("y")[0]  solution for y
//   Result.At("s")[0]  solution for s
//   Result.At("z")[0]  solution for z
//
func ConeLp(c, G, h, A, b *matrix.FloatMatrix, dims *sets.DimensionSet, solopts *SolverOptions,
	primalstart, dualstart *sets.FloatMatrixSet) (sol *Solution, err error) {

	if c == nil || c.Cols() > 1 {
		err = errors.New("'c' must be matrix with 1 column")
		return
	}
	if c.Rows() < 1 {
		err = errors.New("No variables, 'c' must have at least one row")
		return

	}
	if h == nil || h.Cols() > 1 {
		err = errors.New("'h' must be matrix with 1 column")
		return
	}

	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}

	cdim := dims.Sum("l", "q") + dims.SumSquared("s")
	cdim_pckd := dims.Sum("l", "q") + dims.SumPacked("s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	if G == nil {
		G = matrix.FloatZeros(0, c.Rows())
	}
	if !G.SizeMatch(cdim, c.Rows()) {
		estr := fmt.Sprintf("'G' must be of size (%d,%d)", cdim, c.Rows())
		err = errors.New(estr)
		return
	}

	// Check A and set defaults if it is nil
	if A == nil {
		// zeros rows reduces Gemv to vector products
		A = matrix.FloatZeros(0, c.Rows())
	}
	if A.Cols() != c.Rows() {
		estr := fmt.Sprintf("'A' must have %d columns", c.Rows())
		err = errors.New(estr)
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}
	if b.Rows() != A.Rows() {
		estr := fmt.Sprintf("'b' must have length %d", A.Rows())
		err = errors.New(estr)
		return
	}

	if b.Rows() > c.Rows() || b.Rows()+cdim_pckd < c.Rows() {
		err = errors.New("Rank(A) < p or Rank([G; A]) < n")
		return
	}

	solvername := solopts.KKTSolverName
	if len(solvername) == 0 {
		if len(dims.At("q")) > 0 || len(dims.At("s")) > 0 {
			solvername = "qr"
		} else {
			solvername = "chol2"
		}
	}

	var factor kktFactor
	var kktsolver KKTConeSolver = nil
	if kktfunc, ok := lpsolvers[solvername]; ok {
		// kkt function returns us problem spesific factor function.
		factor, err = kktfunc(G, dims, A, 0)
		if err != nil {
			return nil, err
		}
		kktsolver = func(W *sets.FloatMatrixSet) (KKTFunc, error) {
			return factor(W, nil, nil)
		}
	} else {
		err = errors.New(fmt.Sprintf("solver '%s' not known", solvername))
		return
	}
	//return ConeLpCustom(c, &mG, h, &mA, b, dims, kktsolver, solopts, primalstart, dualstart)
	c_e := &matrixVar{c}
	G_e := &matrixVarG{G, dims}
	A_e := &matrixVarA{A}
	b_e := &matrixVar{b}
	return conelp_problem(c_e, G_e, h, A_e, b_e, dims, kktsolver, solopts, primalstart, dualstart)
}
Пример #15
0
// Solves a convex optimization problem with a linear objective
//
//       minimize    f0(x)
//       subject to  fk(x) <= 0, k = 1, ..., mnl
//                   G*x   <= h
//                   A*x    = b.
//
// using custom solver for KKT equations and constraint equations G and A.
//
func CpCustomMatrix(F ConvexProg, G MatrixG, h *matrix.FloatMatrix, A MatrixA,
	b *matrix.FloatMatrix, dims *sets.DimensionSet, kktsolver KKTCpSolver,
	solopts *SolverOptions) (sol *Solution, err error) {

	var mnl int
	var x0 *matrix.FloatMatrix

	mnl, x0, err = F.F0()
	if err != nil {
		return
	}

	if x0.Cols() != 1 {
		err = errors.New("'x0' must be matrix with one column")
		return
	}
	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() > 1 {
		err = errors.New("'h' must be matrix with 1 column")
		return
	}

	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}
	if err = checkConeLpDimensions(dims); err != nil {
		return
	}
	cdim := dims.Sum("l", "q") + dims.SumSquared("s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	var G_e MatrixVarG = nil
	if G == nil {
		G_e = &epMatrixG{matrix.FloatZeros(0, x0.Rows()), dims}
	} else {
		G_e = &epiMatrixG{G, dims}
	}

	var A_e MatrixVarA = nil
	if A == nil {
		A_e = &epMatrixA{matrix.FloatZeros(0, x0.Rows())}
	} else {
		A_e = &epiMatrixA{A}
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}

	if kktsolver == nil {
		err = errors.New("'kktsolver' must be non-nil function.")
		return
	}

	c_e := newEpigraph(x0, 1.0)
	blas.ScalFloat(c_e.m(), 0.0)
	b_e := matrixVar{b}

	return cp_problem(F, c_e, G_e, h, A_e, &b_e, dims, kktsolver, solopts, x0, mnl)

}
Пример #16
0
// Solves a convex optimization problem with a linear objective
//
//       minimize    f0(x)
//       subject to  fk(x) <= 0, k = 1, ..., mnl
//                   G*x   <= h
//                   A*x    = b.
//
// using custom solver for KKT equations.
//
func CpCustomKKT(F ConvexProg, G, h, A, b *matrix.FloatMatrix, dims *sets.DimensionSet,
	kktsolver KKTCpSolver, solopts *SolverOptions) (sol *Solution, err error) {

	var mnl int
	var x0 *matrix.FloatMatrix

	mnl, x0, err = F.F0()
	if err != nil {
		return
	}

	if x0.Cols() != 1 {
		err = errors.New("'x0' must be matrix with one column")
		return
	}
	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() > 1 {
		err = errors.New("'h' must be matrix with 1 column")
		return
	}

	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}
	if err = checkConeLpDimensions(dims); err != nil {
		return
	}
	cdim := dims.Sum("l", "q") + dims.SumSquared("s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	if G == nil {
		G = matrix.FloatZeros(0, x0.Rows())
	}
	if !G.SizeMatch(cdim, x0.Rows()) {
		estr := fmt.Sprintf("'G' must be of size (%d,%d)", cdim, x0.Rows())
		err = errors.New(estr)
		return
	}

	// Check A and set defaults if it is nil
	if A == nil {
		// zeros rows reduces Gemv to vector products
		A = matrix.FloatZeros(0, x0.Rows())
	}
	if A.Cols() != x0.Rows() {
		estr := fmt.Sprintf("'A' must have %d columns", x0.Rows())
		err = errors.New(estr)
		return
	}

	// Check b and set defaults if it is nil
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if b.Cols() != 1 {
		estr := fmt.Sprintf("'b' must be a matrix with 1 column")
		err = errors.New(estr)
		return
	}
	if b.Rows() != A.Rows() {
		estr := fmt.Sprintf("'b' must have length %d", A.Rows())
		err = errors.New(estr)
		return
	}

	if kktsolver == nil {
		err = errors.New("'kktsolver' must be non-nil function.")
		return
	}

	c_e := newEpigraph(x0, 1.0)
	blas.ScalFloat(x0, 0.0)
	G_e := epMatrixG{G, dims}
	A_e := epMatrixA{A}
	b_e := matrixVar{b}

	return cp_problem(F, c_e, &G_e, h, &A_e, &b_e, dims, kktsolver, solopts, x0, mnl)
}
Пример #17
0
// Solves a pair of primal and dual SDPs
//
//        minimize    c'*x
//        subject to  Gl*x + sl = hl
//                    mat(Gs[k]*x) + ss[k] = hs[k], k = 0, ..., N-1
//                    A*x = b
//                    sl >= 0,  ss[k] >= 0, k = 0, ..., N-1
//
//        maximize    -hl'*z - sum_k trace(hs[k]*zs[k]) - b'*y
//        subject to  Gl'*zl + sum_k Gs[k]'*vec(zs[k]) + A'*y + c = 0
//                    zl >= 0,  zs[k] >= 0, k = 0, ..., N-1.
//
// The inequalities sl >= 0 and zl >= 0 are elementwise vector
// inequalities.  The inequalities ss[k] >= 0, zs[k] >= 0 are matrix
// inequalities, i.e., the symmetric matrices ss[k] and zs[k] must be
// positive semidefinite.  mat(Gs[k]*x) is the symmetric matrix X with
// X[:] = Gs[k]*x.  For a symmetric matrix, zs[k], vec(zs[k]) is the
// vector zs[k][:].
//
func Sdp(c, Gl, hl, A, b *matrix.FloatMatrix, Ghs *sets.FloatMatrixSet, solopts *SolverOptions,
	primalstart, dualstart *sets.FloatMatrixSet) (sol *Solution, err error) {
	if c == nil {
		err = errors.New("'c' must a column matrix")
		return
	}
	n := c.Rows()
	if n < 1 {
		err = errors.New("Number of variables must be at least 1")
		return
	}
	if Gl == nil {
		Gl = matrix.FloatZeros(0, n)
	}
	if Gl.Cols() != n {
		err = errors.New(fmt.Sprintf("'G' must be matrix with %d columns", n))
		return
	}
	ml := Gl.Rows()
	if hl == nil {
		hl = matrix.FloatZeros(0, 1)
	}
	if !hl.SizeMatch(ml, 1) {
		err = errors.New(fmt.Sprintf("'hl' must be matrix of size (%d,1)", ml))
		return
	}
	Gsset := Ghs.At("Gs")
	ms := make([]int, 0)
	for i, Gs := range Gsset {
		if Gs.Cols() != n {
			err = errors.New(fmt.Sprintf("'Gs' must be list of matrices with %d columns", n))
			return
		}
		sz := int(math.Sqrt(float64(Gs.Rows())))
		if Gs.Rows() != sz*sz {
			err = errors.New(fmt.Sprintf("the squareroot of the number of rows of 'Gq[%d]' is not an integer", i))
			return
		}
		ms = append(ms, sz)
	}

	hsset := Ghs.At("hs")
	if len(Gsset) != len(hsset) {
		err = errors.New(fmt.Sprintf("'hs' must be a list of %d matrices", len(Gsset)))
		return
	}
	for i, hs := range hsset {
		if !hs.SizeMatch(ms[i], ms[i]) {
			s := fmt.Sprintf("hq[%d] has size (%d,%d). Expected size is (%d,%d)",
				i, hs.Rows(), hs.Cols(), ms[i], ms[i])
			err = errors.New(s)
			return
		}
	}
	if A == nil {
		A = matrix.FloatZeros(0, n)
	}
	if A.Cols() != n {
		err = errors.New(fmt.Sprintf("'A' must be matrix with %d columns", n))
		return
	}
	p := A.Rows()
	if b == nil {
		b = matrix.FloatZeros(0, 1)
	}
	if !b.SizeMatch(p, 1) {
		err = errors.New(fmt.Sprintf("'b' must be matrix of size (%d,1)", p))
		return
	}
	dims := sets.NewDimensionSet("l", "q", "s")
	dims.Set("l", []int{ml})
	dims.Set("s", ms)
	N := dims.Sum("l") + dims.SumSquared("s")

	// Map hs matrices to h vector
	h := matrix.FloatZeros(N, 1)
	h.SetIndexesFromArray(hl.FloatArray()[:ml], matrix.MakeIndexSet(0, ml, 1)...)
	ind := ml
	for k, hs := range hsset {
		h.SetIndexesFromArray(hs.FloatArray(), matrix.MakeIndexSet(ind, ind+ms[k]*ms[k], 1)...)
		ind += ms[k] * ms[k]
	}

	Gargs := make([]*matrix.FloatMatrix, 0)
	Gargs = append(Gargs, Gl)
	Gargs = append(Gargs, Gsset...)
	G, sizeg := matrix.FloatMatrixStacked(matrix.StackDown, Gargs...)

	var pstart, dstart *sets.FloatMatrixSet = nil, nil
	if primalstart != nil {
		pstart = sets.NewFloatSet("x", "s")
		pstart.Set("x", primalstart.At("x")[0])
		slset := primalstart.At("sl")
		margs := make([]*matrix.FloatMatrix, 0, len(slset)+1)
		margs = append(margs, primalstart.At("s")[0])
		margs = append(margs, slset...)
		sl, _ := matrix.FloatMatrixStacked(matrix.StackDown, margs...)
		pstart.Set("s", sl)
	}

	if dualstart != nil {
		dstart = sets.NewFloatSet("y", "z")
		dstart.Set("y", dualstart.At("y")[0])
		zlset := primalstart.At("zl")
		margs := make([]*matrix.FloatMatrix, 0, len(zlset)+1)
		margs = append(margs, dualstart.At("z")[0])
		margs = append(margs, zlset...)
		zl, _ := matrix.FloatMatrixStacked(matrix.StackDown, margs...)
		dstart.Set("z", zl)
	}

	//fmt.Printf("h=\n%v\n", h.ToString("%.3f"))
	//fmt.Printf("G=\n%v\n", G.ToString("%.3f"))

	sol, err = ConeLp(c, G, h, A, b, dims, solopts, pstart, dstart)
	// unpack sol.Result
	if err == nil {
		s := sol.Result.At("s")[0]
		sl := matrix.FloatVector(s.FloatArray()[:ml])
		sol.Result.Append("sl", sl)
		ind := ml
		for _, m := range ms {
			sk := matrix.FloatNew(m, m, s.FloatArray()[ind:ind+m*m])
			sol.Result.Append("ss", sk)
			ind += m * m
		}

		z := sol.Result.At("z")[0]
		zl := matrix.FloatVector(s.FloatArray()[:ml])
		sol.Result.Append("zl", zl)
		ind = ml
		for i, k := range sizeg[1:] {
			zk := matrix.FloatNew(ms[i], ms[i], z.FloatArray()[ind:ind+k])
			sol.Result.Append("zs", zk)
			ind += k
		}
	}
	sol.Result.Remove("s")
	sol.Result.Remove("z")

	return

}
Пример #18
0
func coneqp_solver(P MatrixVarP, q MatrixVariable, G MatrixVarG, h *matrix.FloatMatrix,
	A MatrixVarA, b MatrixVariable, dims *sets.DimensionSet, kktsolver KKTConeSolverVar,
	solopts *SolverOptions, initvals *sets.FloatMatrixSet) (sol *Solution, err error) {

	err = nil
	EXPON := 3
	STEP := 0.99

	sol = &Solution{Unknown,
		nil,
		0.0, 0.0, 0.0, 0.0, 0.0,
		0.0, 0.0, 0.0, 0.0, 0.0, 0}

	//var kktsolver func(*sets.FloatMatrixSet)(KKTFunc, error) = nil
	var refinement int
	var correction bool = true

	feasTolerance := FEASTOL
	absTolerance := ABSTOL
	relTolerance := RELTOL
	maxIter := MAXITERS
	if solopts.FeasTol > 0.0 {
		feasTolerance = solopts.FeasTol
	}
	if solopts.AbsTol > 0.0 {
		absTolerance = solopts.AbsTol
	}
	if solopts.RelTol > 0.0 {
		relTolerance = solopts.RelTol
	}
	if solopts.MaxIter > 0 {
		maxIter = solopts.MaxIter
	}
	if q == nil {
		err = errors.New("'q' must be non-nil MatrixVariable with one column")
		return
	}

	if h == nil {
		h = matrix.FloatZeros(0, 1)
	}
	if h.Cols() != 1 {
		err = errors.New("'h' must be non-nil matrix with one column")
		return
	}
	if dims == nil {
		dims = sets.NewDimensionSet("l", "q", "s")
		dims.Set("l", []int{h.Rows()})
	}

	err = checkConeQpDimensions(dims)
	if err != nil {
		return
	}

	cdim := dims.Sum("l", "q") + dims.SumSquared("s")
	//cdim_pckd := dims.Sum("l", "q") + dims.SumPacked("s")
	cdim_diag := dims.Sum("l", "q", "s")

	if h.Rows() != cdim {
		err = errors.New(fmt.Sprintf("'h' must be float matrix of size (%d,1)", cdim))
		return
	}

	// Data for kth 'q' constraint are found in rows indq[k]:indq[k+1] of G.
	indq := make([]int, 0)
	indq = append(indq, dims.At("l")[0])
	for _, k := range dims.At("q") {
		indq = append(indq, indq[len(indq)-1]+k)
	}

	// Data for kth 's' constraint are found in rows inds[k]:inds[k+1] of G.
	inds := make([]int, 0)
	inds = append(inds, indq[len(indq)-1])
	for _, k := range dims.At("s") {
		inds = append(inds, inds[len(inds)-1]+k*k)
	}

	if P == nil {
		err = errors.New("'P' must be non-nil MatrixVarP interface.")
		return
	}
	fP := func(u, v MatrixVariable, alpha, beta float64) error {
		return P.Pf(u, v, alpha, beta)
	}

	if G == nil {
		err = errors.New("'G' must be non-nil MatrixG interface.")
		return
	}
	fG := func(x, y MatrixVariable, alpha, beta float64, trans la.Option) error {
		return G.Gf(x, y, alpha, beta, trans)
	}

	// Check A and set defaults if it is nil
	fA := func(x, y MatrixVariable, alpha, beta float64, trans la.Option) error {
		return A.Af(x, y, alpha, beta, trans)
	}

	// Check b and set defaults if it is nil
	if b == nil {
		err = errors.New("'b' must be non-nil MatrixVariable interface.")
		return
	}

	// kktsolver(W) returns a routine for solving 3x3 block KKT system
	//
	//     [ 0   A'  G'*W^{-1} ] [ ux ]   [ bx ]
	//     [ A   0   0         ] [ uy ] = [ by ].
	//     [ G   0   -W'       ] [ uz ]   [ bz ]

	if kktsolver == nil {
		err = errors.New("nil kktsolver not allowed.")
		return
	}

	ws3 := matrix.FloatZeros(cdim, 1)
	wz3 := matrix.FloatZeros(cdim, 1)
	checkpnt.AddMatrixVar("ws3", ws3)
	checkpnt.AddMatrixVar("wz3", wz3)

	//
	res := func(ux, uy MatrixVariable, uz, us *matrix.FloatMatrix, vx, vy MatrixVariable, vz, vs *matrix.FloatMatrix, W *sets.FloatMatrixSet, lmbda *matrix.FloatMatrix) (err error) {
		// Evaluates residual in Newton equations:
		//
		//      [ vx ]    [ vx ]   [ 0     ]   [ P  A'  G' ]   [ ux        ]
		//      [ vy ] := [ vy ] - [ 0     ] - [ A  0   0  ] * [ uy        ]
		//      [ vz ]    [ vz ]   [ W'*us ]   [ G  0   0  ]   [ W^{-1}*uz ]
		//
		//      vs := vs - lmbda o (uz + us).

		// vx := vx - P*ux - A'*uy - G'*W^{-1}*uz
		minor := checkpnt.MinorTop()
		checkpnt.Check("00res", minor)
		fP(ux, vx, -1.0, 1.0)
		fA(uy, vx, -1.0, 1.0, la.OptTrans)
		blas.Copy(uz, wz3)
		scale(wz3, W, true, false)
		fG(&matrixVar{wz3}, vx, -1.0, 1.0, la.OptTrans)
		// vy := vy - A*ux
		fA(ux, vy, -1.0, 1.0, la.OptNoTrans)
		checkpnt.Check("50res", minor)

		// vz := vz - G*ux - W'*us
		fG(ux, &matrixVar{vz}, -1.0, 1.0, la.OptNoTrans)
		blas.Copy(us, ws3)
		scale(ws3, W, true, false)
		blas.AxpyFloat(ws3, vz, -1.0)

		// vs := vs - lmbda o (uz + us)
		blas.Copy(us, ws3)
		blas.AxpyFloat(uz, ws3, 1.0)
		sprod(ws3, lmbda, dims, 0, la.OptDiag)
		blas.AxpyFloat(ws3, vs, -1.0)
		checkpnt.Check("90res", minor)
		return
	}

	resx0 := math.Max(1.0, math.Sqrt(q.Dot(q)))
	resy0 := math.Max(1.0, math.Sqrt(b.Dot(b)))
	resz0 := math.Max(1.0, snrm2(h, dims, 0))
	//fmt.Printf("resx0: %.17f, resy0: %.17f, resz0: %.17f\n", resx0, resy0, resz0)

	var x, y, dx, dy, rx, ry MatrixVariable
	var z, s, ds, dz, rz *matrix.FloatMatrix
	var lmbda, lmbdasq, sigs, sigz *matrix.FloatMatrix
	var W *sets.FloatMatrixSet
	var f, f3 KKTFuncVar
	var resx, resy, resz, step, sigma, mu, eta float64
	var gap, pcost, dcost, relgap, pres, dres, f0 float64

	if cdim == 0 {
		// Solve
		//
		//     [ P  A' ] [ x ]   [ -q ]
		//     [       ] [   ] = [    ].
		//     [ A  0  ] [ y ]   [  b ]
		//
		Wtmp := sets.NewFloatSet("d", "di", "beta", "v", "r", "rti")
		Wtmp.Set("d", matrix.FloatZeros(0, 1))
		Wtmp.Set("di", matrix.FloatZeros(0, 1))
		f3, err = kktsolver(Wtmp)
		if err != nil {
			s := fmt.Sprintf("kkt error: %s", err)
			err = errors.New("2: Rank(A) < p or Rank(([P; A; G;]) < n : " + s)
			return
		}
		x = q.Copy()
		x.Scal(0.0)
		y = b.Copy()
		f3(x, y, matrix.FloatZeros(0, 1))

		// dres = || P*x + q + A'*y || / resx0
		rx = q.Copy()
		fP(x, rx, 1.0, 1.0)
		pcost = 0.5 * (x.Dot(rx) + x.Dot(q))
		fA(y, rx, 1.0, 1.0, la.OptTrans)
		dres = math.Sqrt(rx.Dot(rx) / resx0)

		ry = b.Copy()
		fA(x, ry, 1.0, -1.0, la.OptNoTrans)
		pres = math.Sqrt(ry.Dot(ry) / resy0)

		relgap = 0.0
		if pcost == 0.0 {
			relgap = math.NaN()
		}

		sol.Result = sets.NewFloatSet("x", "y", "s", "z")
		sol.Result.Set("x", x.Matrix())
		sol.Result.Set("y", y.Matrix())
		sol.Result.Set("s", matrix.FloatZeros(0, 1))
		sol.Result.Set("z", matrix.FloatZeros(0, 1))
		sol.Status = Optimal
		sol.Gap = 0.0
		sol.RelativeGap = relgap
		sol.PrimalObjective = pcost
		sol.DualObjective = pcost
		sol.PrimalInfeasibility = pres
		sol.DualInfeasibility = dres
		sol.PrimalSlack = 0.0
		sol.DualSlack = 0.0
		return
	}
	x = q.Copy()
	y = b.Copy()
	s = matrix.FloatZeros(cdim, 1)
	z = matrix.FloatZeros(cdim, 1)

	checkpnt.AddVerifiable("x", x)
	checkpnt.AddVerifiable("y", y)
	checkpnt.AddMatrixVar("s", s)
	checkpnt.AddMatrixVar("z", z)

	var ts, tz, nrms, nrmz float64

	if initvals == nil {
		// Factor
		//
		//     [ 0   A'  G' ]
		//     [ A   0   0  ].
		//     [ G   0  -I  ]
		//
		W = sets.NewFloatSet("d", "di", "v", "beta", "r", "rti")
		W.Set("d", matrix.FloatOnes(dims.At("l")[0], 1))
		W.Set("di", matrix.FloatOnes(dims.At("l")[0], 1))
		W.Set("beta", matrix.FloatOnes(len(dims.At("q")), 1))

		for _, n := range dims.At("q") {
			vm := matrix.FloatZeros(n, 1)
			vm.SetIndex(0, 1.0)
			W.Append("v", vm)
		}
		for _, n := range dims.At("s") {
			W.Append("r", matrix.FloatIdentity(n))
			W.Append("rti", matrix.FloatIdentity(n))
		}
		checkpnt.AddScaleVar(W)
		f, err = kktsolver(W)
		if err != nil {
			s := fmt.Sprintf("kkt error: %s", err)
			err = errors.New("3: Rank(A) < p or Rank([P; G; A]) < n : " + s)
			return
		}
		// Solve
		//
		//     [ P   A'  G' ]   [ x ]   [ -q ]
		//     [ A   0   0  ] * [ y ] = [  b ].
		//     [ G   0  -I  ]   [ z ]   [  h ]
		mCopy(q, x)
		x.Scal(-1.0)
		mCopy(b, y)
		blas.Copy(h, z)
		checkpnt.Check("00init", 1)
		err = f(x, y, z)
		if err != nil {
			s := fmt.Sprintf("kkt error: %s", err)
			err = errors.New("4: Rank(A) < p or Rank([P; G; A]) < n : " + s)
			return
		}
		blas.Copy(z, s)
		blas.ScalFloat(s, -1.0)
		checkpnt.Check("05init", 1)

		nrms = snrm2(s, dims, 0)
		ts, _ = maxStep(s, dims, 0, nil)
		//fmt.Printf("nrms = %.7f, ts = %.7f\n", nrms, ts)
		if ts >= -1e-8*math.Max(nrms, 1.0) {
			// a = 1.0 + ts
			a := 1.0 + ts
			is := make([]int, 0)
			// indexes s[:dims['l']]
			is = append(is, matrix.MakeIndexSet(0, dims.At("l")[0], 1)...)
			// indexes s[indq[:-1]]
			is = append(is, indq[:len(indq)-1]...)
			ind := dims.Sum("l", "q")
			// indexes s[ind:ind+m*m:m+1] (diagonal)
			for _, m := range dims.At("s") {
				is = append(is, matrix.MakeIndexSet(ind, ind+m*m, m+1)...)
				ind += m * m
			}
			for _, k := range is {
				s.SetIndex(k, a+s.GetIndex(k))
			}
		}

		nrmz = snrm2(z, dims, 0)
		tz, _ = maxStep(z, dims, 0, nil)
		//fmt.Printf("nrmz = %.7f, tz = %.7f\n", nrmz, tz)
		if tz >= -1e-8*math.Max(nrmz, 1.0) {
			a := 1.0 + tz
			is := make([]int, 0)
			is = append(is, matrix.MakeIndexSet(0, dims.At("l")[0], 1)...)
			is = append(is, indq[:len(indq)-1]...)
			ind := dims.Sum("l", "q")
			for _, m := range dims.At("s") {
				is = append(is, matrix.MakeIndexSet(ind, ind+m*m, m+1)...)
				ind += m * m
			}
			for _, k := range is {
				z.SetIndex(k, a+z.GetIndex(k))
			}
		}

	} else {
		ix := initvals.At("x")[0]
		if ix != nil {
			mCopy(&matrixVar{ix}, x)
		} else {
			x.Scal(0.0)
		}

		is := initvals.At("s")[0]
		if is != nil {
			blas.Copy(is, s)
		} else {
			iset := make([]int, 0)
			iset = append(iset, matrix.MakeIndexSet(0, dims.At("l")[0], 1)...)
			iset = append(iset, indq[:len(indq)-1]...)
			ind := dims.Sum("l", "q")
			for _, m := range dims.At("s") {
				iset = append(iset, matrix.MakeIndexSet(ind, ind+m*m, m+1)...)
				ind += m * m
			}
			for _, k := range iset {
				s.SetIndex(k, 1.0)
			}
		}

		iy := initvals.At("y")[0]
		if iy != nil {
			mCopy(&matrixVar{iy}, y)
		} else {
			y.Scal(0.0)
		}

		iz := initvals.At("z")[0]
		if iz != nil {
			blas.Copy(iz, z)
		} else {
			iset := make([]int, 0)
			iset = append(iset, matrix.MakeIndexSet(0, dims.At("l")[0], 1)...)
			iset = append(iset, indq[:len(indq)-1]...)
			ind := dims.Sum("l", "q")
			for _, m := range dims.At("s") {
				iset = append(iset, matrix.MakeIndexSet(ind, ind+m*m, m+1)...)
				ind += m * m
			}
			for _, k := range iset {
				z.SetIndex(k, 1.0)
			}
		}
	}

	rx = q.Copy()
	ry = b.Copy()
	rz = matrix.FloatZeros(cdim, 1)
	dx = x.Copy()
	dy = y.Copy()
	dz = matrix.FloatZeros(cdim, 1)
	ds = matrix.FloatZeros(cdim, 1)
	lmbda = matrix.FloatZeros(cdim_diag, 1)
	lmbdasq = matrix.FloatZeros(cdim_diag, 1)
	sigs = matrix.FloatZeros(dims.Sum("s"), 1)
	sigz = matrix.FloatZeros(dims.Sum("s"), 1)

	checkpnt.AddVerifiable("rx", rx)
	checkpnt.AddVerifiable("ry", ry)
	checkpnt.AddVerifiable("dx", dx)
	checkpnt.AddVerifiable("dy", dy)
	//checkpnt.AddMatrixVar("rs", rs)
	checkpnt.AddMatrixVar("rz", rz)
	checkpnt.AddMatrixVar("ds", ds)
	checkpnt.AddMatrixVar("dz", dz)
	checkpnt.AddMatrixVar("lmbda", lmbda)
	checkpnt.AddMatrixVar("lmbdasq", lmbdasq)

	//var resx, resy, resz, step, sigma, mu, eta float64
	//var gap, pcost, dcost, relgap, pres, dres, f0 float64
	checkpnt.AddFloatVar("resx", &resx)
	checkpnt.AddFloatVar("resy", &resy)
	checkpnt.AddFloatVar("resz", &resz)
	checkpnt.AddFloatVar("step", &step)
	checkpnt.AddFloatVar("gap", &gap)
	checkpnt.AddFloatVar("dcost", &dcost)
	checkpnt.AddFloatVar("pcost", &pcost)
	checkpnt.AddFloatVar("dres", &dres)
	checkpnt.AddFloatVar("pres", &pres)
	checkpnt.AddFloatVar("relgap", &relgap)
	checkpnt.AddFloatVar("sigma", &sigma)

	var WS fVarClosure

	gap = sdot(s, z, dims, 0)
	for iter := 0; iter < maxIter+1; iter++ {
		checkpnt.MajorNext()
		checkpnt.Check("loopstart", 10)

		// f0 = (1/2)*x'*P*x + q'*x + r and  rx = P*x + q + A'*y + G'*z.
		mCopy(q, rx)
		fP(x, rx, 1.0, 1.0)
		f0 = 0.5 * (x.Dot(rx) + x.Dot(q))
		fA(y, rx, 1.0, 1.0, la.OptTrans)
		fG(&matrixVar{z}, rx, 1.0, 1.0, la.OptTrans)
		resx = math.Sqrt(rx.Dot(rx))

		// ry = A*x - b
		mCopy(b, ry)
		fA(x, ry, 1.0, -1.0, la.OptNoTrans)
		resy = math.Sqrt(ry.Dot(ry))

		// rz = s + G*x - h
		blas.Copy(s, rz)
		blas.AxpyFloat(h, rz, -1.0)
		fG(x, &matrixVar{rz}, 1.0, 1.0, la.OptNoTrans)
		resz = snrm2(rz, dims, 0)
		//fmt.Printf("resx: %.17f, resy: %.17f, resz: %.17f\n", resx, resy, resz)

		// Statistics for stopping criteria.

		// pcost = (1/2)*x'*P*x + q'*x
		// dcost = (1/2)*x'*P*x + q'*x + y'*(A*x-b) + z'*(G*x-h) '
		//       = (1/2)*x'*P*x + q'*x + y'*(A*x-b) + z'*(G*x-h+s) - z'*s
		//       = (1/2)*x'*P*x + q'*x + y'*ry + z'*rz - gap
		pcost = f0
		dcost = f0 + y.Dot(ry) + sdot(z, rz, dims, 0) - gap
		if pcost < 0.0 {
			relgap = gap / -pcost
		} else if dcost > 0.0 {
			relgap = gap / dcost
		} else {
			relgap = math.NaN()
		}
		pres = math.Max(resy/resy0, resz/resz0)
		dres = resx / resx0

		if solopts.ShowProgress {
			if iter == 0 {
				// show headers of something
				fmt.Printf("% 10s% 12s% 10s% 8s% 7s\n",
					"pcost", "dcost", "gap", "pres", "dres")
			}
			// show something
			fmt.Printf("%2d: % 8.4e % 8.4e % 4.0e% 7.0e% 7.0e\n",
				iter, pcost, dcost, gap, pres, dres)
		}
		checkpnt.Check("stoptest", 100)

		if pres <= feasTolerance && dres <= feasTolerance &&
			(gap <= absTolerance || (!math.IsNaN(relgap) && relgap <= relTolerance)) ||
			iter == maxIter {

			ind := dims.Sum("l", "q")
			for _, m := range dims.At("s") {
				symm(s, m, ind)
				symm(z, m, ind)
				ind += m * m
			}
			ts, _ = maxStep(s, dims, 0, nil)
			tz, _ = maxStep(z, dims, 0, nil)
			if iter == maxIter {
				// terminated on max iterations.
				sol.Status = Unknown
				err = errors.New("Terminated (maximum iterations reached)")
				fmt.Printf("Terminated (maximum iterations reached)\n")
				return
			}
			// optimal solution found
			//fmt.Print("Optimal solution.\n")
			err = nil
			sol.Result = sets.NewFloatSet("x", "y", "s", "z")
			sol.Result.Set("x", x.Matrix())
			sol.Result.Set("y", y.Matrix())
			sol.Result.Set("s", s)
			sol.Result.Set("z", z)
			sol.Status = Optimal
			sol.Gap = gap
			sol.RelativeGap = relgap
			sol.PrimalObjective = pcost
			sol.DualObjective = dcost
			sol.PrimalInfeasibility = pres
			sol.DualInfeasibility = dres
			sol.PrimalSlack = -ts
			sol.DualSlack = -tz
			sol.PrimalResidualCert = math.NaN()
			sol.DualResidualCert = math.NaN()
			sol.Iterations = iter
			return
		}

		// Compute initial scaling W and scaled iterates:
		//
		//     W * z = W^{-T} * s = lambda.
		//
		// lmbdasq = lambda o lambda.
		if iter == 0 {
			W, err = computeScaling(s, z, lmbda, dims, 0)
			checkpnt.AddScaleVar(W)
		}
		ssqr(lmbdasq, lmbda, dims, 0)

		f3, err = kktsolver(W)
		if err != nil {
			if iter == 0 {
				s := fmt.Sprintf("kkt error: %s", err)
				err = errors.New("5: Rank(A) < p or Rank([P; A; G]) < n : " + s)
				return
			} else {
				ind := dims.Sum("l", "q")
				for _, m := range dims.At("s") {
					symm(s, m, ind)
					symm(z, m, ind)
					ind += m * m
				}
				ts, _ = maxStep(s, dims, 0, nil)
				tz, _ = maxStep(z, dims, 0, nil)
				// terminated (singular KKT matrix)
				fmt.Printf("Terminated (singular KKT matrix).\n")
				err = errors.New("Terminated (singular KKT matrix).")
				sol.Result = sets.NewFloatSet("x", "y", "s", "z")
				sol.Result.Set("x", x.Matrix())
				sol.Result.Set("y", y.Matrix())
				sol.Result.Set("s", s)
				sol.Result.Set("z", z)
				sol.Status = Unknown
				sol.RelativeGap = relgap
				sol.PrimalObjective = pcost
				sol.DualObjective = dcost
				sol.PrimalInfeasibility = pres
				sol.DualInfeasibility = dres
				sol.PrimalSlack = -ts
				sol.DualSlack = -tz
				sol.Iterations = iter
				return
			}
		}
		// f4_no_ir(x, y, z, s) solves
		//
		//     [ 0     ]   [ P  A'  G' ]   [ ux        ]   [ bx ]
		//     [ 0     ] + [ A  0   0  ] * [ uy        ] = [ by ]
		//     [ W'*us ]   [ G  0   0  ]   [ W^{-1}*uz ]   [ bz ]
		//
		//     lmbda o (uz + us) = bs.
		//
		// On entry, x, y, z, s contain bx, by, bz, bs.
		// On exit, they contain ux, uy, uz, us.

		f4_no_ir := func(x, y MatrixVariable, z, s *matrix.FloatMatrix) error {
			// Solve
			//
			//     [ P A' G'   ] [ ux        ]    [ bx                    ]
			//     [ A 0  0    ] [ uy        ] =  [ by                    ]
			//     [ G 0 -W'*W ] [ W^{-1}*uz ]    [ bz - W'*(lmbda o\ bs) ]
			//
			//     us = lmbda o\ bs - uz.
			//
			// On entry, x, y, z, s  contains bx, by, bz, bs.
			// On exit they contain x, y, z, s.

			minor := checkpnt.MinorTop()
			checkpnt.Check("f4_no_ir_start", minor)
			// s := lmbda o\ s
			//    = lmbda o\ bs
			sinv(s, lmbda, dims, 0)

			// z := z - W'*s
			//    = bz - W'*(lambda o\ bs)
			blas.Copy(s, ws3)
			scale(ws3, W, true, false)
			blas.AxpyFloat(ws3, z, -1.0)

			checkpnt.Check("f4_no_ir_f3", minor+50)
			err := f3(x, y, z)
			if err != nil {
				return err
			}
			checkpnt.Check("f4_no_ir_f3", minor+60)

			// s := s - z
			//    = lambda o\ bs - uz.
			blas.AxpyFloat(z, s, -1.0)
			checkpnt.Check("f4_no_ir_f3", minor+90)
			return nil
		}

		if iter == 0 {
			if refinement > 0 || solopts.Debug {
				WS.wx = q.Copy()
				WS.wy = y.Copy()
				WS.ws = matrix.FloatZeros(cdim, 1)
				WS.wz = matrix.FloatZeros(cdim, 1)
				checkpnt.AddVerifiable("wx", WS.wx)
				checkpnt.AddVerifiable("wy", WS.wy)
				checkpnt.AddMatrixVar("ws", WS.ws)
				checkpnt.AddMatrixVar("wz", WS.wz)
			}
			if refinement > 0 {
				WS.wx2 = q.Copy()
				WS.wy2 = y.Copy()
				WS.ws2 = matrix.FloatZeros(cdim, 1)
				WS.wz2 = matrix.FloatZeros(cdim, 1)
				checkpnt.AddVerifiable("wx2", WS.wx2)
				checkpnt.AddVerifiable("wy2", WS.wy2)
				checkpnt.AddMatrixVar("ws2", WS.ws2)
				checkpnt.AddMatrixVar("wz2", WS.wz2)
			}
		}

		f4 := func(x, y MatrixVariable, z, s *matrix.FloatMatrix) (err error) {
			minor := checkpnt.MinorTop()
			checkpnt.Check("f4start", minor)
			err = nil
			if refinement > 0 || solopts.Debug {
				mCopy(x, WS.wx)
				mCopy(y, WS.wy)
				blas.Copy(z, WS.wz)
				blas.Copy(s, WS.ws)
			}

			checkpnt.MinorPush(minor + 100)
			err = f4_no_ir(x, y, z, s)
			checkpnt.MinorPop()

			for i := 0; i < refinement; i++ {
				mCopy(WS.wx, WS.wx2)
				mCopy(WS.wy, WS.wy2)
				blas.Copy(WS.wz, WS.wz2)
				blas.Copy(WS.ws, WS.ws2)

				checkpnt.MinorPush(minor + (i+1)*300)
				res(x, y, z, s, WS.wx2, WS.wy2, WS.wz2, WS.ws2, W, lmbda)
				checkpnt.MinorPop()

				checkpnt.MinorPush(minor + (i+1)*500)
				f4_no_ir(WS.wx2, WS.wy2, WS.wz2, WS.ws2)
				checkpnt.MinorPop()

				WS.wx2.Axpy(x, 1.0)
				WS.wy2.Axpy(y, 1.0)
				blas.AxpyFloat(WS.wz2, z, 1.0)
				blas.AxpyFloat(WS.ws2, s, 1.0)
			}
			checkpnt.Check("f4end", minor+1500)
			return
		}

		//var mu, sigma, eta float64
		mu = gap / float64(dims.Sum("l", "s")+len(dims.At("q")))
		sigma, eta = 0.0, 0.0

		for i := 0; i < 2; i++ {
			// Solve
			//
			//     [ 0     ]   [ P  A' G' ]   [ dx        ]
			//     [ 0     ] + [ A  0  0  ] * [ dy        ] = -(1 - eta) * r
			//     [ W'*ds ]   [ G  0  0  ]   [ W^{-1}*dz ]
			//
			//     lmbda o (dz + ds) = -lmbda o lmbda + sigma*mu*e (i=0)
			//     lmbda o (dz + ds) = -lmbda o lmbda - dsa o dza
			//                         + sigma*mu*e (i=1) where dsa, dza
			//                         are the solution for i=0.

			minor_base := (i + 1) * 2000
			// ds = -lmbdasq + sigma * mu * e  (if i is 0)
			//    = -lmbdasq - dsa o dza + sigma * mu * e  (if i is 1),
			//    where ds, dz are solution for i is 0.
			blas.ScalFloat(ds, 0.0)
			if correction && i == 1 {
				blas.AxpyFloat(ws3, ds, -1.0)
			}
			blas.AxpyFloat(lmbdasq, ds, -1.0, &la.IOpt{"n", dims.Sum("l", "q")})
			ind := dims.At("l")[0]
			ds.Add(sigma*mu, matrix.MakeIndexSet(0, ind, 1)...)
			for _, m := range dims.At("q") {
				ds.SetIndex(ind, sigma*mu+ds.GetIndex(ind))
				ind += m
			}
			ind2 := ind
			for _, m := range dims.At("s") {
				blas.AxpyFloat(lmbdasq, ds, -1.0, &la.IOpt{"n", m}, &la.IOpt{"incy", m + 1},
					&la.IOpt{"offsetx", ind2}, &la.IOpt{"offsety", ind})
				ds.Add(sigma*mu, matrix.MakeIndexSet(ind, ind+m*m, m+1)...)
				ind += m * m
				ind2 += m
			}

			checkpnt.Check("00loop01", minor_base)

			// (dx, dy, dz) := -(1 - eta) * (rx, ry, rz)
			//blas.ScalFloat(dx, 0.0)
			//blas.AxpyFloat(rx, dx, -1.0+eta)
			dx.Scal(0.0)
			rx.Axpy(dx, -1.0+eta)
			dy.Scal(0.0)
			ry.Axpy(dy, -1.0+eta)
			blas.ScalFloat(dz, 0.0)
			blas.AxpyFloat(rz, dz, -1.0+eta)

			//fmt.Printf("== Calling f4 %d\n", i)
			//fmt.Printf("dx=\n%v\n", dx.ToString("%.17f"))
			//fmt.Printf("ds=\n%v\n", ds.ToString("%.17f"))
			//fmt.Printf("dz=\n%v\n", dz.ToString("%.17f"))
			//fmt.Printf("== Entering f4 %d\n", i)
			checkpnt.MinorPush(minor_base)
			err = f4(dx, dy, dz, ds)
			checkpnt.MinorPop()
			if err != nil {
				if iter == 0 {
					s := fmt.Sprintf("kkt error: %s", err)
					err = errors.New("6: Rank(A) < p or Rank([P; A; G]) < n : " + s)
					return
				} else {
					ind = dims.Sum("l", "q")
					for _, m := range dims.At("s") {
						symm(s, m, ind)
						symm(z, m, ind)
						ind += m * m
					}
					ts, _ = maxStep(s, dims, 0, nil)
					tz, _ = maxStep(z, dims, 0, nil)
					return
				}
			}

			dsdz := sdot(ds, dz, dims, 0)
			if correction && i == 0 {
				blas.Copy(ds, ws3)
				sprod(ws3, dz, dims, 0)
			}

			// Maximum step to boundary.
			//
			// If i is 1, also compute eigenvalue decomposition of the 's'
			// blocks in ds, dz.  The eigenvectors Qs, Qz are stored in
			// dsk, dzk.  The eigenvalues are stored in sigs, sigz.
			scale2(lmbda, ds, dims, 0, false)
			scale2(lmbda, dz, dims, 0, false)
			checkpnt.Check("maxstep", minor_base+1500)
			if i == 0 {
				ts, _ = maxStep(ds, dims, 0, nil)
				tz, _ = maxStep(dz, dims, 0, nil)
			} else {
				ts, _ = maxStep(ds, dims, 0, sigs)
				tz, _ = maxStep(dz, dims, 0, sigz)
			}
			t := maxvec([]float64{0.0, ts, tz})
			//fmt.Printf("== t=%.17f from %v\n", t, []float64{ts, tz})
			if t == 0.0 {
				step = 1.0
			} else {
				if i == 0 {
					step = math.Min(1.0, 1.0/t)
				} else {
					step = math.Min(1.0, STEP/t)
				}
			}
			if i == 0 {
				m := math.Max(0.0, 1.0-step+dsdz/gap*(step*step))
				sigma = math.Pow(math.Min(1.0, m), float64(EXPON))
				eta = 0.0
			}
			//fmt.Printf("== step=%.17f sigma=%.17f dsdz=%.17f\n", step, sigma, dsdz)

		}

		checkpnt.Check("updatexy", 8000)
		dx.Axpy(x, step)
		dy.Axpy(y, step)
		//fmt.Printf("x=\n%v\n", x.ConvertToString())
		//fmt.Printf("y=\n%v\n", y.ConvertToString())
		//fmt.Printf("ds=\n%v\n", ds.ConvertToString())
		//fmt.Printf("dz=\n%v\n", dz.ConvertToString())

		// We will now replace the 'l' and 'q' blocks of ds and dz with
		// the updated iterates in the current scaling.
		// We also replace the 's' blocks of ds and dz with the factors
		// Ls, Lz in a factorization Ls*Ls', Lz*Lz' of the updated variables
		// in the current scaling.

		// ds := e + step*ds for nonlinear, 'l' and 'q' blocks.
		// dz := e + step*dz for nonlinear, 'l' and 'q' blocks.
		blas.ScalFloat(ds, step, &la.IOpt{"n", dims.Sum("l", "q")})
		blas.ScalFloat(dz, step, &la.IOpt{"n", dims.Sum("l", "q")})
		ind := dims.At("l")[0]
		is := matrix.MakeIndexSet(0, ind, 1)
		ds.Add(1.0, is...)
		dz.Add(1.0, is...)
		for _, m := range dims.At("q") {
			ds.SetIndex(ind, 1.0+ds.GetIndex(ind))
			dz.SetIndex(ind, 1.0+dz.GetIndex(ind))
			ind += m
		}
		checkpnt.Check("updatedsdz", 8010)

		// ds := H(lambda)^{-1/2} * ds and dz := H(lambda)^{-1/2} * dz.
		//
		// This replaces the 'l' and 'q' components of ds and dz with the
		// updated variables in the current scaling.
		// The 's' components of ds and dz are replaced with
		//
		// diag(lmbda_k)^{1/2} * Qs * diag(lmbda_k)^{1/2}
		// diag(lmbda_k)^{1/2} * Qz * diag(lmbda_k)^{1/2}
		scale2(lmbda, ds, dims, 0, true)
		scale2(lmbda, dz, dims, 0, true)
		checkpnt.Check("scale2", 8030)

		// sigs := ( e + step*sigs ) ./ lambda for 's' blocks.
		// sigz := ( e + step*sigz ) ./ lambda for 's' blocks.
		blas.ScalFloat(sigs, step)
		blas.ScalFloat(sigz, step)
		sigs.Add(1.0)
		sigz.Add(1.0)
		sdimsum := dims.Sum("s")
		qdimsum := dims.Sum("l", "q")
		blas.TbsvFloat(lmbda, sigs, &la.IOpt{"n", sdimsum}, &la.IOpt{"k", 0},
			&la.IOpt{"lda", 1}, &la.IOpt{"offseta", qdimsum})
		blas.TbsvFloat(lmbda, sigz, &la.IOpt{"n", sdimsum}, &la.IOpt{"k", 0},
			&la.IOpt{"lda", 1}, &la.IOpt{"offseta", qdimsum})

		ind2 := qdimsum
		ind3 := 0
		sdims := dims.At("s")

		for k := 0; k < len(sdims); k++ {
			m := sdims[k]
			for i := 0; i < m; i++ {
				a := math.Sqrt(sigs.GetIndex(ind3 + i))
				blas.ScalFloat(ds, a, &la.IOpt{"offset", ind2 + m*i}, &la.IOpt{"n", m})
				a = math.Sqrt(sigz.GetIndex(ind3 + i))
				blas.ScalFloat(dz, a, &la.IOpt{"offset", ind2 + m*i}, &la.IOpt{"n", m})
			}
			ind2 += m * m
			ind3 += m
		}

		checkpnt.Check("updatescaling", 8050)
		err = updateScaling(W, lmbda, ds, dz)
		checkpnt.Check("afterscaling", 8060)

		// Unscale s, z, tau, kappa (unscaled variables are used only to
		// compute feasibility residuals).
		ind = dims.Sum("l", "q")
		ind2 = ind
		blas.Copy(lmbda, s, &la.IOpt{"n", ind})
		for _, m := range dims.At("s") {
			blas.ScalFloat(s, 0.0, &la.IOpt{"offset", ind2})
			blas.Copy(lmbda, s, &la.IOpt{"offsetx", ind}, &la.IOpt{"offsety", ind2},
				&la.IOpt{"n", m}, &la.IOpt{"incy", m + 1})
			ind += m
			ind2 += m * m
		}
		scale(s, W, true, false)

		ind = dims.Sum("l", "q")
		ind2 = ind
		blas.Copy(lmbda, z, &la.IOpt{"n", ind})
		for _, m := range dims.At("s") {
			blas.ScalFloat(z, 0.0, &la.IOpt{"offset", ind2})
			blas.Copy(lmbda, z, &la.IOpt{"offsetx", ind}, &la.IOpt{"offsety", ind2},
				&la.IOpt{"n", m}, &la.IOpt{"incy", m + 1})
			ind += m
			ind2 += m * m
		}
		scale(z, W, false, true)

		gap = blas.DotFloat(lmbda, lmbda)
		checkpnt.Check("eol", 8900)
		//fmt.Printf("== gap = %.17f\n", gap)
	}
	return
}