Quadratic Program (QP) Example in Julia
We will show how to solve the Basic QP example problem both natively in Clarabel.jl and also by solving with Clarabel.jl within either JuMP or Convex.jl.
Clarabel.jl native interface
using Clarabel, SparseArrays
P = sparse([3. 0.;0. 2.].*2)
q = [-1., -4.]
A = sparse([1. -2.; #<-- LHS of equality constraint
1. 0.; #<-- LHS of inequality constraint (upper bound)
0. 1.; #<-- LHS of inequality constraint (upper bound)
-1. 0.; #<-- LHS of inequality constraint (lower bound)
0. -1.; #<-- LHS of inequality constraint (lower bound)
])
b = [0.; #<-- RHS of equality constraint
ones(4)] #<-- RHS of inequality constraints
cones =
[Clarabel.ZeroConeT(1), #<--- for the equality constraint
Clarabel.NonnegativeConeT(4)] #<--- for the inequality constraints
settings = Clarabel.Settings()
solver = Clarabel.Solver()
Clarabel.setup!(solver, P, q, A, b, cones, settings)
result = Clarabel.solve!(solver)
-------------------------------------------------------------
Clarabel.jl v0.8.1 - Clever Acronym
(c) Paul Goulart
University of Oxford, 2022
-------------------------------------------------------------
problem:
variables = 2
constraints = 5
nnz(P) = 2
nnz(A) = 6
cones (total) = 2
: Zero = 1, numel = 1
: Nonnegative = 1, numel = 4
settings:
linear algebra: direct / qdldl, precision: Float64
max iter = 200, time limit = Inf, max step = 0.990
tol_feas = 1.0e-08, tol_gap_abs = 1.0e-08, tol_gap_rel = 1.0e-08,
static reg : on, ϵ1 = 1.0e-08, ϵ2 = 4.9e-32
dynamic reg: on, ϵ = 1.0e-13, δ = 2.0e-07
iter refine: on, reltol = 1.0e-13, abstol = 1.0e-12,
max iter = 10, stop ratio = 5.0
equilibrate: on, min_scale = 1.0e-04, max_scale = 1.0e+04
max iter = 10
iter pcost dcost gap pres dres k/t μ step
---------------------------------------------------------------------------------------------
0 -3.2878e-01 -1.8973e+01 1.86e+01 9.76e-17 9.02e-17 1.00e+00 1.77e+00 ------
1 -5.7453e-01 -1.8040e+00 1.23e+00 4.81e-17 3.23e-17 6.08e-02 1.15e-01 9.44e-01
2 -6.4203e-01 -7.5345e-01 1.11e-01 1.63e-17 3.25e-17 5.21e-03 8.97e-03 9.90e-01
3 -6.4286e-01 -6.4541e-01 2.55e-03 1.08e-16 3.26e-17 1.19e-04 2.00e-04 9.90e-01
4 -6.4286e-01 -6.4288e-01 2.63e-05 4.89e-17 7.99e-18 1.23e-06 2.06e-06 9.90e-01
5 -6.4286e-01 -6.4286e-01 2.63e-07 8.82e-15 1.81e-14 1.23e-08 2.06e-08 9.90e-01
6 -6.4286e-01 -6.4286e-01 2.63e-09 2.30e-16 4.02e-16 1.23e-10 2.06e-10 9.90e-01
---------------------------------------------------------------------------------------------
Terminated with status = solved
solve time = 603μs
>>> Clarabel - Results
Status: SOLVED
Iterations: 6
Objective: -0.6429
Solve time: 603μs
result.x
2-element Vector{Float64}:
0.4285714281988429
0.2142857140994215
Using JuMP
We can solve the same problem a little more easily by using Clarabel.jl as the backend solver within JuMP. Here is the same problem again:
using Clarabel, JuMP
model = JuMP.Model(Clarabel.Optimizer)
set_optimizer_attribute(model, "verbose", true)
@variable(model, x[1:2])
@constraint(model, x[1] == 2x[2])
@constraint(model, -1 .<= x .<= 1)
@objective(model, Min, 3x[1]^2 + 2x[2]^2 - x[1] - 4x[2])
optimize!(model)
-------------------------------------------------------------
Clarabel.jl v0.8.1 - Clever Acronym
(c) Paul Goulart
University of Oxford, 2022
-------------------------------------------------------------
problem:
variables = 2
constraints = 5
nnz(P) = 2
nnz(A) = 6
cones (total) = 2
: Zero = 1, numel = 1
: Nonnegative = 1, numel = 4
settings:
linear algebra: direct / qdldl, precision: Float64
max iter = 200, time limit = Inf, max step = 0.990
tol_feas = 1.0e-08, tol_gap_abs = 1.0e-08, tol_gap_rel = 1.0e-08,
static reg : on, ϵ1 = 1.0e-08, ϵ2 = 4.9e-32
dynamic reg: on, ϵ = 1.0e-13, δ = 2.0e-07
iter refine: on, reltol = 1.0e-13, abstol = 1.0e-12,
max iter = 10, stop ratio = 5.0
equilibrate: on, min_scale = 1.0e-04, max_scale = 1.0e+04
max iter = 10
iter pcost dcost gap pres dres k/t μ step
---------------------------------------------------------------------------------------------
0 -3.2878e-01 -1.8973e+01 1.86e+01 9.48e-17 1.50e-16 1.00e+00 1.77e+00 ------
1 -5.7453e-01 -1.8040e+00 1.23e+00 4.89e-17 6.32e-17 6.08e-02 1.15e-01 9.44e-01
2 -6.4203e-01 -7.5345e-01 1.11e-01 5.91e-17 3.34e-17 5.21e-03 8.97e-03 9.90e-01
3 -6.4286e-01 -6.4541e-01 2.55e-03 1.14e-16 0.00e+00 1.19e-04 2.00e-04 9.90e-01
4 -6.4286e-01 -6.4288e-01 2.63e-05 4.71e-17 3.20e-17 1.23e-06 2.06e-06 9.90e-01
5 -6.4286e-01 -6.4286e-01 2.63e-07 8.82e-15 1.81e-14 1.23e-08 2.06e-08 9.90e-01
6 -6.4286e-01 -6.4286e-01 2.63e-09 1.96e-16 3.17e-16 1.23e-10 2.06e-10 9.90e-01
---------------------------------------------------------------------------------------------
Terminated with status = solved
solve time = 576μs
Here is the solution
JuMP.value.(x)
2-element Vector{Float64}:
0.4285714281988431
0.21428571409942154
and the solver termination status again
JuMP.termination_status(model)
OPTIMAL::TerminationStatusCode = 1
Using Convex.jl
We can likewise solve the same problem a using Clarabel.jl as the backend solver within Convex.jl. Here is the same problem one more time:
using Clarabel, Convex
x = Variable(2)
problem = minimize(3square(x[1]) + 2square(x[2]) - x[1] - 4x[2])
problem.constraints = [x[1] == 2x[2]]
problem.constraints += [x >= -1; x <= 1]
solve!(problem, Clarabel.Optimizer; silent_solver = false)
Problem statistics
problem is DCP : true
number of variables : 1 (2 scalar elements)
number of constraints : 3 (5 scalar elements)
number of coefficients : 12
number of atoms : 23
Solution summary
termination status : OPTIMAL
primal status : FEASIBLE_POINT
dual status : FEASIBLE_POINT
objective value : -0.6429
Expression graph
minimize
└─ + (convex; real)
├─ * (convex; positive)
│ ├─ [3;;]
│ └─ qol_elem (convex; positive)
│ ├─ …
│ └─ …
├─ * (convex; positive)
│ ├─ [2;;]
│ └─ qol_elem (convex; positive)
│ ├─ …
│ └─ …
├─ Convex.NegateAtom (affine; real)
│ └─ index (affine; real)
│ └─ …
⋮
subject to
├─ == constraint (affine)
│ └─ + (affine; real)
│ ├─ index (affine; real)
│ │ └─ …
│ └─ Convex.NegateAtom (affine; real)
│ └─ …
├─ ≥ constraint (affine)
│ └─ + (affine; real)
│ ├─ 2-element real variable (id: 348…882)
│ └─ Convex.NegateAtom (constant; positive)
│ └─ …
└─ ≤ constraint (affine)
└─ + (affine; real)
├─ 2-element real variable (id: 348…882)
└─ Convex.NegateAtom (constant; negative)
└─ …
Here is our solution
evaluate(x)
2-element Vector{Float64}:
0.4285731865024157
0.21428659325133423
and the solver termination status again
problem.status
OPTIMAL::TerminationStatusCode = 1
Note that in the Clarabel.jl output that follows the call to solve! using Convex.jl, the problem posed to the solver has been converted to a second-order cone program with a linear objective. You can see this because now nnz(P) == 0
(there is no quadratic term in the objective) and the solver reports two second order cone constraints.
Although the solution will be the same, the required number of iterations and solve time are slightly higher. When solving problems with quadratic objectives in Clarabel.jl, it is generally preferable to use either the native Clarabel.jl interface or JuMP, both of which handle quadratic terms in the objective directly.
This page was generated using Literate.jl.