Bilevel KKT-emitter frontend¶
A bilevel program
\[\begin{split}
\begin{aligned}
\min_{x, y} \quad & F(x, y) \\
\text{s.t.} \quad & y \in \argmin_y \{\, f(x, y) \;:\; g(x, y) \le 0,\ h(x, y) = 0 \,\}
\end{aligned}
\end{split}\]
becomes an MPCC by replacing the lower-level \(\argmin\) with its KKT system:
\[\begin{split}
\begin{aligned}
& \nabla_y f(x, y) + \sum_i \lambda_i \nabla_y g_i(x, y) + \sum_k \mu_k \nabla_y h_k(x, y) = 0 \\
& h(x, y) = 0 \\
& \lambda \ge 0,\ -g(x, y) \ge 0,\ \lambda \perp -g(x, y).
\end{aligned}
\end{split}\]
pympcc.bilevel.from_lower_level does this rewrite automatically.
API¶
from pympcc.bilevel import from_lower_level
problem = from_lower_level(
n_x=2, n_y=2,
x0=np.zeros(2), y0=np.zeros(2),
f_upper=lambda x, y: ..., # JAX-traceable
f_lower=lambda x, y: ..., # JAX-traceable
n_g_lower=1,
g_lower=lambda x, y: ..., # (n_g_lower,)
n_h_lower=0,
h_lower=None,
derivatives="jax", # or "fd"
xl=None, xu=None, yl=None, yu=None,
lambda0=None, mu0=None,
)
result = pympcc.solve(problem, strategy="scholtes")
Variable layout¶
The emitted MPCC has
\[
z = [\, x_\text{upper}\ (n_x) \;\mid\; y_\text{lower}\ (n_y) \;\mid\; \lambda\ (n_{g,\text{lower}}) \;\mid\; \mu\ (n_{h,\text{lower}}) \,].
\]
The \(\lambda\) block is automatically lower-bounded at \(0\); \(\mu\) stays free.
When KKT emission is valid¶
KKT validity assumes lower-level convexity (or at least a stationary lower optimum). For non-convex lower-level problems the resulting MPCC characterises stationary points of the lower problem rather than its global \(\argmin\). If the lower level lacks inequality constraints there is no complementarity to emit — solve it as a regular NLP instead.