Clarabel.jl
Clarabel.jl copied to clipboard
indirect solve prototype
A small experiment to see how we could go about enabling indirect KKT solves. This PR so far does the following:
-
adds a registration mechanism for AbstractKKTSolver implementations. This uses a Dict object implemented similarly to the registration method for the direct LDL solvers. This requires a minor change to the Settings structure, which now defines a default
kkt_solver_method = :directldl
to get the standard solver behaviour. -
adds a new prototype implementation for a
IndirectKKTSolver
solver type, which can be selected via the optionkkt_solver_method = :indirect
. This is very basic and assumes internally that it will only be applied to a problem with a single NN cone constraint. It does not actually implement an indirect solve, but rather reduces the KKT system to a dense form to which an an actual indirect linear solver could be applied. -
makes some internal modifications to the rest of the code to support the indirect solve, mostly by passing
cones
around where they are required.
Note that if an indirect method is used then there is no reason that SparseMatrixCSC
format is required, since in that case the solver only needs to perform matrix multiplication. (Almost) everything is implemented internally in terms of AbstractMatrix{T}
, so the solver should work on any input type that implements enough of AbstractMatrix{T}
interface. See example below for further explanation.
This is WIP and should not be used in anger. It is currently unclear to me how this could be applied to general cone problems since it requires the inverse of the scaling block Hs, or at least multiplication by the inverse of that block. See internal comments in the kktsolver_indirect.jl
implementation for further explanation.
Example code:
using Clarabel, SparseArrays
# A small box constrained QP problem.
n = 4
P = sparse(I(n)).*1.
q = collect((1:n).*1.)
A = sparse([I(n);-I(n)].*1.)
b = ones(2*n)
cones = [Clarabel.NonnegativeConeT(2*n)]
# Solve the problem using standard direct method
settings = Clarabel.Settings(kkt_solver_method = :directldl)
solver = Clarabel.Solver(settings)
Clarabel.setup!(solver, P, q, A, b,cones)
result = Clarabel.solve!(solver)
# Solve the problem using an indirect method
settings = Clarabel.Settings(kkt_solver_method = :indirect)
solver = Clarabel.Solver(settings)
Clarabel.setup!(solver, P, q, A, b,cones)
result = Clarabel.solve!(solver)
# Since the :indirect method doesn't require direct
# assembly or factorization of the KKT matrix in sparse
# format, everything should also work for matrix data
# of other type, since (nearly) all of the solver is
# implemented in terms of AbstractMatrix{T}. The only
# exceptions are :
# - info printing provides a nonzero count, so make
# a blanket implementation for that function here
SparseArrays.nnz(A::AbstractMatrix) = prod(size(A))
# Now the solver should work with dense matrices
settings = Clarabel.Settings(
kkt_solver_method = :indirect,
)
denseP = Matrix(P)
denseA = Matrix(A)
solver = Clarabel.Solver(settings)
Clarabel.setup!(solver, denseP, q, denseA, b, cones)
result = Clarabel.solve!(solver)