Python Quick Start
August 12, 2026 · View on GitHub
PDHCG provides a user-friendly Python interface for quadratic and quadratic conic problems using familiar NumPy and SciPy data structures.
Basic Usage
import numpy as np
import scipy.sparse as sp
from pdhcg import Model
# Example: minimize 0.5 * x'(Q + R^T D R)x + c'x
# subject to l <= A x <= u, lb <= x <= ub
# (D defaults to identity, i.e. 0.5 * x'(Q + R^T R)x + c'x.)
# 1. Define Standard QP terms
Q = sp.csc_matrix([[1.0, -1.0], [-1.0, 2.0]])
c = np.array([-2.0, -6.0])
# 2. Define Low-Rank Matrix R
# This adds 0.5 * ||Rx||^2 to the objective
R = sp.csc_matrix([[1.0, 0.0]])
# 3. (Optional) Middle matrix D for R^T D R; 1-D = diag, 2-D = dense, sparse OK.
# D = np.array([2.5])
# 4. Define Constraints
A = sp.csc_matrix([[1.0, 1.0], [-1.0, 2.0], [2.0, 1.0]])
l = np.array([-np.inf, -np.inf, -np.inf])
u = np.array([2.0, 2.0, 3.0])
lb = np.zeros(2)
ub = np.array([np.inf, np.inf])
# 5. Create QP model with Low-Rank term (R) and optional middle D
m = Model(objective_matrix=Q,
objective_matrix_low_rank=R,
# objective_matrix_low_rank_middle=D,
objective_vector=c,
constraint_matrix=A,
constraint_lower_bound=l,
constraint_upper_bound=u,
variable_lower_bound=lb,
variable_upper_bound=ub)
# 5. Set solver parameters (0=Silent, 1=Summary, 2=Detailed)
m.setParams(LogLevel=2)
# Solve
m.optimize()
# Print results
print(f"Status: {m.Status}")
print(f"Objective: {m.ObjVal:.4f}")
if m.X is not None:
print(f"Primal Solution: {m.X}")
Quick start with cone constraints
Conic constraints use a columnar ConeSpec, whose arrays can describe many
blocks without allocating one Python object per cone. See
model.md.
import numpy as np
import scipy.sparse as sp
from pdhcg import ConeSpec, ConeType, Model
# min z s.t. v = 3, w = 4, (v, w, z) in K_soc => z = sqrt(v^2 + w^2) = 5
A = sp.csr_matrix([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
model = Model(
objective_vector=np.array([0.0, 0.0, 1.0]),
constraint_matrix=A,
constraint_lower_bound=np.array([3.0, 4.0]),
constraint_upper_bound=np.array([3.0, 4.0]),
variable_cones=ConeSpec(
ConeType.SOC,
np.array([0], dtype=np.int32),
v_dims=1,
),
)
model.optimize()
print(model.Status, model.X)
CVXPY
Install the optional integration with pip install "pdhcg[cvxpy]", then
import the backend once in each process:
import cvxpy as cp
import pdhcg.cvxpy_backend # Registers solver="PDHCG".
x = cp.Variable()
problem = cp.Problem(cp.Minimize(x), [x >= 1])
value = problem.solve(solver="PDHCG", eps=1e-6)
print(problem.status, value, x.value)
The backend preserves CVXPY's primal and dual conventions. It supports quadratic objectives and Zero, NonNeg, SOC, PSD, ExpCone, and PowCone3D constraints. Mixed-integer models are not supported.
Model Creation
The Model class is the core interface for defining quadratic conic problems. The problem formulation is:
Required Parameters
objective_vector(): Linear coefficients of the objective function
Optional Parameters
objective_matrix(): Sparse quadratic coefficientsobjective_matrix_low_rank(): Low-rank quadratic factor of shapeobjective_matrix_low_rank_middle(, ): Middle matrix in . 1-D array → diagonal ; 2-D array → dense symmetric ; scipy sparse → sparse . May be indefinite. Defaults to identityconstraint_matrix(): Linear constraint matrixconstraint_lower_bound(): Constraint lower boundsconstraint_upper_bound(): Constraint upper boundsaffine_cone_matrix(): Matrix in the native affine-cone constraintaffine_cone_offset(): Affine-cone offset; defaults to zeroaffine_cones:ConeSpeccovering every row ofvariable_cones:ConeSpecdescribing cone blocks embedded invariable_lower_bound(): Variable lower bounds (default: )variable_upper_bound(): Variable upper bounds (default: )objective_constant: Constant term in objective
Setting Parameters
Solver parameters can be set individually or in batch:
# Set individual parameter
m.setParam("TimeLimit", 3600)
# Set multiple parameters
m.setParams(
TimeLimit=3600,
IterationLimit=100000,
LogLevel=1
)
# Or use the Params view
m.Params.TimeLimit = 3600
Warm Starting
Provide initial solutions to speed up convergence:
# Set warm start
m.setWarmStart(primal=x0, dual=y0)
# Clear warm start
m.clearWarmStart()
Accessing Results
After calling optimize(), results are available through properties:
m.optimize()
# Solution
print(m.X) # Primal solution
print(m.Pi) # Dual solution
# Objective
print(m.ObjVal) # Primal objective value
print(m.DualObj) # Dual objective value
print(m.Gap) # Objective gap
print(m.RelGap) # Relative gap
# Status
print(m.Status) # Solution status string
print(m.StatusCode) # Solution status code
print(m.IterCount) # Number of iterations
print(m.Runtime) # Runtime in seconds
# Residuals
print(m.RelPrimalResidual) # Relative primal residual
print(m.RelDualResidual) # Relative dual residual