Diagnostics¶
Pass diagnostics=True to pympcc.solve to populate the constraint qualification, B-stationarity, and SOSC fields on MPCCResult. Pass tnlp_refine=True to extract certified MPCC multipliers.
CQ, B-stationarity, SOSC¶
result = pympcc.solve(problem, strategy="scholtes", diagnostics=True)
print(result.cq) # "MPCC-LICQ"
print(result.b_stationary) # "B-stationary"
print(result.sosc) # True — strict local minimiser
print(result.sosc_min_eigenvalue) # > 0
SOSC checks positive definiteness of the reduced Lagrangian Hessian on the critical cone:
True— \(x^*\) is a certified strict local minimiser.False— saddle point, or only a local max in some direction.None— skipped (biactive pairs present, or solve did not converge); checkresult.sosc_skipped_reason.
TNLP-certified multipliers¶
result = pympcc.solve(
problem, strategy="scholtes",
diagnostics=True, tnlp_refine=True,
)
print(result.mult_comp_G_mpcc) # certified μ_G (≥ 0 at S-stationary points)
print(result.mult_comp_H_mpcc) # certified μ_H
print(result.stationarity) # "S-stationary" or "W-stationary"
TNLP refinement re-solves a tightened NLP with the active set fixed as equalities. This extracts MPCC-clean multipliers and certifies S- or W-stationarity. The FD-based SOSC check uses TNLP multipliers when available (most accurate path).
Multi-merit cross-check¶
After every solve, three independent MPCC merit functions are evaluated and reported on the result:
Fischer-Burmeister: \(\lvert G + H - \sqrt{G^2 + H^2} \rvert\)
min-map: \(\lvert \min(G, H) \rvert\)
inner-product: \(\lvert G \cdot H \rvert\)
print(result.merit_cross_check) # {"fb_max": ..., "minmap_max": ..., "ip_max": ..., "disagreement_ratio": ...}
A disagreement_ratio close to 1 means the merits agree (healthy convergence); large values flag scaling mismatch or near-degeneracy.
Active-Jacobian diagnostics¶
print(result.jac_row_norms) # {"max": ..., "min": ..., "near_zero": int}
print(result.jac_col_norms) # idem
print(result.degeneracy_report) # {"n_biactive": ..., "n_zero_rows": ..., "min_singular_value": ...}
Condition numbers¶
print(result.jac_condition) # κ(J_active)
print(result.hessian_condition_estimate) # diagonal-scaling estimate from MA57/MA27
Initial-point statistics¶
from pympcc import initial_point_statistics
stats = initial_point_statistics(problem)
# bound violations, complementarity violation at x0, constraint residuals