# 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.5.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 =  942μs
>>> Clarabel - Results
Status: SOLVED
Iterations: 6
Objective: -0.6429
Solve time:  942μs

result.x
2-element Vector{Float64}:
0.428571428198843
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.5.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 =  925μ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)
-------------------------------------------------------------
Clarabel.jl v0.5.1  -  Clever Acronym
(c) Paul Goulart
University of Oxford, 2022
-------------------------------------------------------------

problem:
variables     = 5
constraints   = 14
nnz(P)        = 0
nnz(A)        = 17
cones (total) = 4
: Zero        = 1,  numel = 2
: Nonnegative = 1,  numel = 6
: SecondOrder = 2,  numel = (3,3)

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   4.4163e-18  -1.4716e+01  1.47e+01  6.17e-01  3.25e-01  1.00e+00  3.37e+00   ------
1  -1.0868e+00  -3.6775e+00  2.38e+00  1.44e-01  6.44e-02  4.78e-01  7.87e-01  9.90e-01
2  -7.0595e-01  -8.7396e-01  1.68e-01  8.52e-03  3.91e-03  2.62e-02  5.45e-02  9.41e-01
3  -6.4512e-01  -6.5074e-01  5.62e-03  2.82e-04  1.30e-04  8.81e-04  1.84e-03  9.66e-01
4  -6.4311e-01  -6.4380e-01  6.85e-04  3.44e-05  1.59e-05  1.09e-04  2.24e-04  8.86e-01
5  -6.4289e-01  -6.4301e-01  1.15e-04  5.79e-06  2.67e-06  1.86e-05  3.78e-05  8.43e-01
6  -6.4286e-01  -6.4287e-01  1.14e-05  5.75e-07  2.66e-07  1.89e-06  3.76e-06  9.13e-01
7  -6.4286e-01  -6.4286e-01  2.84e-07  1.44e-08  6.63e-09  4.79e-08  9.38e-08  9.77e-01
8  -6.4286e-01  -6.4286e-01  1.46e-08  2.52e-09  3.40e-10  2.46e-09  4.81e-09  9.49e-01
9  -6.4286e-01  -6.4286e-01  2.53e-09  4.34e-10  5.91e-11  4.30e-10  8.36e-10  8.37e-01
---------------------------------------------------------------------------------------------
Terminated with status = solved
solve time = 36.4ms

Here is our solution

evaluate(x)
2-element Vector{Float64}:
0.42857345927489715
0.21428672963748968

and the solver termination status again

problem.status
OPTIMAL::TerminationStatusCode = 1
Warning

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.