import numpy as np
import scipy.sparse as sp
import herculesabqp
def make_sparse_ata_problem(m: int = 80, n: int = 40, density: float = 0.12, seed: int = 0):
rng = np.random.default_rng(seed)
a = sp.random(
m,
n,
density=density,
data_rvs=lambda k: rng.normal(size=k),
format="csr",
)
ridge = 1e-2
q = (a.T @ a + ridge * sp.eye(n, format="csr")).tocsr()
c = rng.normal(loc=-0.15, scale=0.2, size=n)
lb = np.zeros(n, dtype=float)
ub = np.ones(n, dtype=float)
return q, c, lb, ub
def solve_root_and_child():
q, c, lb, ub = make_sparse_ata_problem()
prepared = herculesabqp.PreparedSolver(
q,
c,
assume_symmetric=True,
scaling="hessian_diag",
lipschitz_method="auto",
)
root = prepared.solve(
lb,
ub,
max_iter=2_000,
tol=1e-7,
)
x_root = np.asarray(root["x"], dtype=float)
print("root objective:", root["objective"])
print("root iterations:", root["iterations"])
print("root rel_gap:", root["rel_gap"])
print("root kkt_inf:", root["kkt_inf"])
child_lb = lb.copy()
child_ub = ub.copy()
upper_active = np.flatnonzero(x_root >= 0.95)
branch_count = min(4, upper_active.size)
fixed = upper_active[:branch_count]
child_lb[fixed] = 1.0
child_ub[fixed] = 1.0
child = prepared.solve(
child_lb,
child_ub,
x0=x_root,
max_iter=500,
tol=1e-7,
)
x_child = np.asarray(child["x"], dtype=float)
print()
print("fixed indices:", fixed.tolist())
print("child objective:", child["objective"])
print("child iterations:", child["iterations"])
print("child rel_gap:", child["rel_gap"])
print("child kkt_inf:", child["kkt_inf"])
print("child fixed values:", x_child[fixed].tolist())
if __name__ == "__main__":
solve_root_and_child()