pympcc.MPCCSolver¶
- class pympcc.MPCCSolver(problem, strategy='scholtes', backend='ipopt', ipopt_options=None, solver_options=None, callback=None, inner_callback=None, time_limit=None, verbose=False, presolve=False, diagnostics=False, autoscale=False, b_stat_max_biactive=10, tnlp_refine=False, tnlp_max_iter=500, **strategy_options)[source]¶
Bases:
objectSolver for Mathematical Programs with Complementarity Constraints (MPCC).
- Parameters:
problem (MPCCProblem) – The MPCC problem instance.
strategy ({'direct', 'scholtes', 'smoothing', 'lin_fukushima', 'augmented_lagrangian', 'slack'}) –
Reformulation strategy (default
'scholtes').'direct'— single NLP solve withG·H ≤ 0.'scholtes'— outer loop relaxingG·H ≤ εwithε → 0.'smoothing'— Fischer-Burmeister smoothingφ_ε(G,H) = 0.'lin_fukushima'— Scholtes +G+H ≥ εto preserve MPCC-MFCQ.'augmented_lagrangian'— PHR penalty; complementarity in objective only.'slack'— lifting strategy with slack variabless_G = G(x),s_H = H(x); the complementarity Jacobian rows have zero x-block, which is efficient whenn_comp ≪ n. Incompatible withbackend='filterSQP'.
backend ({'ipopt', 'filterSQP', 'scipy'}, optional) –
NLP backend solver (default
'ipopt').'ipopt'— uses IPOPT via cyipopt (default, fully supported).'filterSQP'— uses pyfiltersqp (L-BFGS SQP). Requires thepyfiltersqppackage to be installed. The'slack'strategy is incompatible with this backend.'scipy'— usesscipy.optimize.minimizewithmethod='trust-constr'. Requiresscipy>=1.10. No IPOPT installation required; suitable for small problems and IPOPT-free environments. Dual warm-starting is accepted but not forwarded (scipy does not support multiplier warm-starts); exact Hessians are not used.
ipopt_options (dict, optional) – Options passed to the IPOPT backend (e.g.
{"max_iter": 500, "tol": 1e-8}). Whenbackend='filterSQP'the common keys"tol"and"max_iter"are translated to filterSQP equivalents; IPOPT-specific keys are silently ignored. Merged with package defaults; user values take precedence.solver_options (dict, optional) – Options forwarded directly to
SQPSolver(e.g.{"tol_feas": 1e-7, "lbfgs_memory": 20}). Ignored whenbackend='ipopt'.**strategy_options – Extra keyword arguments forwarded to the strategy class (e.g.
epsilon_0,reductionfor Scholtes / smoothing). Passdual_warmstart=Falseto disable dual warm-starting between outer iterations (defaultTruefor all iterative strategies).callback (callable, optional) –
f(k: int, info: IterationInfo) -> Nonecalled after each outer iteration, wherekis the 0-based iteration index. Not called by the'direct'strategy (single solve, no outer loop).inner_callback (callable, optional) –
f(iter_count: int, info: dict) -> boolinvoked once per IPOPT inner iteration. ReturnFalseto stop the inner solve early.infomirrors IPOPT’sintermediatearguments. Ignored by the'filterSQP'and'scipy'backends.time_limit (float, optional) – Wall-clock budget in seconds for the outer iterative loop. When the budget is exhausted the loop terminates and the best feasible incumbent (smallest
comp_residualamong accepted iterates) is returned withresult.time_limit_hit = True. Does not interrupt an in-flight inner NLP solve — use IPOPT’smax_cpu_secsfor that. Ignored by the'direct'strategy.verbose (bool, optional) – If
Trueand no callback is provided, prints a formatted progress table to stdout after each outer iteration (defaultFalse).presolve (bool)
diagnostics (bool)
autoscale (bool)
b_stat_max_biactive (int)
tnlp_refine (bool)
tnlp_max_iter (int)
Examples
>>> solver = MPCCSolver(problem, strategy='scholtes', ... epsilon_0=0.5, reduction=0.1) >>> result = solver.solve()
Using the filterSQP backend:
result = pympcc.solve(problem, backend='filterSQP', solver_options={'lbfgs_memory': 20})
- __init__(problem, strategy='scholtes', backend='ipopt', ipopt_options=None, solver_options=None, callback=None, inner_callback=None, time_limit=None, verbose=False, presolve=False, diagnostics=False, autoscale=False, b_stat_max_biactive=10, tnlp_refine=False, tnlp_max_iter=500, **strategy_options)[source]¶
- Parameters:
problem (MPCCProblem | StructuredMPCC)
strategy (Literal['direct', 'scholtes', 'smoothing', 'lin_fukushima', 'augmented_lagrangian', 'slack', 'smooth_min', 'chen_chen_kanzow', 'kanzow_schwartz', 'chen_mangasarian', 'billups', 'veelken_ulbrich_pow', 'veelken_ulbrich_sin', 'ncp'])
backend (Literal['ipopt', 'filterSQP', 'scipy'])
ipopt_options (dict | None)
solver_options (dict | None)
callback (Callable[[int, IterationInfo], None] | None)
time_limit (float | None)
verbose (bool)
presolve (bool)
diagnostics (bool)
autoscale (bool)
b_stat_max_biactive (int)
tnlp_refine (bool)
tnlp_max_iter (int)
- Return type:
None
Methods
__init__(problem[, strategy, backend, ...])resolve(problem, *[, warm_x0, warm_dual])Re-solve a near-identical MPCC reusing the previous result's state.
solve()Run the solver and return an
MPCCResult.- solve()[source]¶
Run the solver and return an
MPCCResult.- Return type:
- resolve(problem, *, warm_x0=True, warm_dual=True)[source]¶
Re-solve a near-identical MPCC reusing the previous result’s state.
- Parameters:
problem (MPCCProblem or StructuredMPCC) – The new problem. Must share the structural signature (
n,n_comp,n_eq,n_ineq, every Jacobian sparsity pattern) of the problem this solver was constructed with; numeric values may differ freely.warm_x0 (bool) – When
True(default), seed the newproblem.x0with the previous result’sx*(clipped onto the new variable bounds). WhenFalse, use whateverx0the new problem carries.warm_dual (bool) – When
True(default), forward the previous solve’smult_g/mult_x_L/mult_x_Uto IPOPT and togglewarm_start_init_point=yeson the first inner solve.
- Returns:
result.warmstart_savings_itercarries the IPOPT iter delta vs the cold-baseline solve.- Return type:
Notes
When the structural signature changes, this method emits a
UserWarningand falls back to a cold-rebuild of the strategy. The cold-rebuild’s iter count becomes the new baseline.autoscaleis intentionally not re-applied on resolve: rescaling comp pairs would invalidate the warm dual. Reconstruct the solver if you need a fresh autoscale probe.Subsequent
solve()calls on the same instance also act as warm-restarts (the warm state persists);resolveis the intended entry point because it lets you swap the problem in.