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