Preprocessing
ConicIP includes a preprocessing wrapper that removes redundant constraints before solving. This can prevent numerical issues caused by rank-deficient constraint matrices.
When to Use Preprocessing
Use preprocess_conicIP instead of conicIP when:
- The equality constraint matrix
Gmay have redundant rows (i.e.,rank(G) < size(G, 1)) - The combined matrix
[Q A' G']may be rank-deficient - You receive
:Erroror:Abandonedstatus from the solver due to singular KKT systems
Usage
preprocess_conicIP has the same signature as conicIP and passes all keyword arguments through:
sol = preprocess_conicIP(Q, c, A, b, cone_dims, G, d; verbose=false)What It Does
The preprocessor performs three steps:
Singleton fixing: an equality row with a single nonzero,
gᵢⱼ yⱼ = dᵢ, fixesyⱼ = dᵢ/gᵢⱼ. The row and the column are removed and the right-hand sides and objective adjusted; the fixed value and the row's dual multiplier are restored on the way out. Two singletons on the same column are dropped when their fixed values agree to tolerance; conflicting values are screened for a Farkas certificate.Equality constraint reduction (
rank_check): usesimcolsto identify and remove linearly dependent rows fromGandd, ensuringrank(G) = size(G, 1).Dual constraint check (
rank_check): checks that the combined system[Q A' G']has full row rank and, if not, opts into the solver's static KKT regularization rather than altering the problem.
Steps 2 and 3 are the expensive ones (two sparse QR factorizations) and exist for KKT solvers that need a full-rank G. rank_check = :auto (default) runs them only when such a solver will be used — dense QR for small and semidefinite problems, or an explicit solver other than kktsolver_ldl or its cached callable — since the LDLᵀ solver regularizes the equality block itself. :always and :never override.
After preprocessing, the reduced problem is passed to conicIP. Postsolve recomputes feasibility against the original data and revalidates certificates. A reduced optimum that fails the original optTol is returned as :Error, with the restored point available for inspection.
The imcols Function
imcols identifies independent columns (rows) in a linear system Ax = b. It returns the indices of a maximal linearly independent subset and checks consistency of the system.
using ConicIP, SparseArrays
A = sparse([1.0 2.0 3.0;
2.0 4.0 6.0; # redundant (2× row 1)
0.0 1.0 1.0])
b = [1.0; 2.0; 1.0]
# imcols returns indices of independent rows
idx = ConicIP.imcols(A', b)Example
using ConicIP, SparseArrays, LinearAlgebra, Random
Random.seed!(42)
n = 5
Q = sparse(1.0I, n, n)
c = randn(n)
A = sparse(1.0I, n, n)
b = zeros(n)
cone_dims = [("R", n)]
# Redundant equality constraints: row 3 = row 1 + row 2
G = [1.0 1.0 0.0 0.0 0.0;
0.0 0.0 1.0 1.0 0.0;
1.0 1.0 1.0 1.0 0.0] # redundant!
d = [1.0; 1.0; 2.0]
# preprocess_conicIP handles the redundancy automatically
sol = preprocess_conicIP(Q, c, A, b, cone_dims, G, d; verbose=false)
sol.status:Optimalround.(sol.y, digits=4)5-element Vector{Float64}:
1.0
0.0
0.4297
0.5703
0.0