Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Constraint Qualifications

For C1C^1 data near a feasible point, constraint qualifications connect the actual feasible set to its first-order model. We use row-oriented Jacobians and the canonical form gi(x)≤0g_i(\mathbf{x})\le0, hj(x)=0h_j(\mathbf{x})=0. The KKT reference owns active/strong/weak terminology and sensitivity; Local Optimality Conditions owns convex KKT sufficiency.

The definitions, full proof arguments, and diagnostics below supplement Lecture 20. Biegler (2010), Sections 4.3.1–4.3.2, pp. 74–79, supplies the core sequence; Nocedal and Wright (2006), Sections 12.2, 12.4 and 12.6, supplies the tangent-cone formulation and proof details.

On open D⊂RnD\subset\mathbb R^n, use f:D→Rf:D\to\mathbb R, g:D→Rr\mathbf g:D\to\mathbb R^r, h:D→Rm\mathbf h:D\to\mathbb R^m, and S={x∈D:g(x)≤0,h(x)=0}S=\{\mathbf x\in D:\mathbf g(\mathbf x)\le\mathbf0,\mathbf h(\mathbf x)=\mathbf0\}. Inequalities are componentwise.

Feasible sequences, unit directions, and the tangent cone

A feasible sequence approaching xˉ\bar{\mathbf{x}} has xk≠xˉ\mathbf{x}^k\ne\bar{\mathbf{x}}, xk→xˉ\mathbf{x}^k\to\bar{\mathbf{x}}, and feasible terms for all sufficiently large kk. If

xk−xˉ∥xk−xˉ∥⟶d,\frac{\mathbf{x}^k-\bar{\mathbf{x}}}{\|\mathbf{x}^k-\bar{\mathbf{x}}\|}\longrightarrow\mathbf{d},

then d\mathbf{d} is its unit limiting direction. A feasible sequence need not have a direction limit: it can alternate between two approach directions. The definition applies to sequences or subsequences for which the limit exists.

The tangent cone uses arbitrary positive scales:

TS(xˉ)={w:∃ zk∈S, tk>0, tk↓0, (zk−xˉ)/tk→w}.T_S(\bar{\mathbf{x}})=\left\{\mathbf{w}:\exists\,\mathbf{z}^k\in S,\ t_k>0,\ t_k\downarrow0,\ (\mathbf{z}^k-\bar{\mathbf{x}})/t_k\to\mathbf{w}\right\}.

It includes 0\mathbf0. Every nonzero tangent vector gives a unit limiting direction after normalization, and positive multiples of a unit limiting direction lie in TST_S. Thus unit limiting directions are TS∩{∥d∥=1}T_S\cap\{\|\mathbf{d}\|=1\}, rather than the entire cone. This distinction resolves the normalization shorthand in Biegler’s Lemma 4.13. See Nocedal and Wright, Definition 12.2, p. 316, and Lemma 12.2, pp. 323–325.

Feasible points and their shrinking chords

Here S={x2≥0.2x12}S=\{x_2\ge0.2x_1^2\}, x(t)=(t,0.6t2)\mathbf{x}(t)=(t,0.6t^2), t↓0t\downarrow0. Its normalized chord is (1,0.6t)T/1+0.36t2→(1,0)T(1,0.6t)^T/\sqrt{1+0.36t^2}\to(1,0)^T. The direction points from the limit toward nearby feasible points. A ball travelling toward the limit moves in the opposite direction; the ball is an analogy, not an assumption about an algorithm’s iterates.

First-order necessity along the actual feasible set

If ff is differentiable and x∗\mathbf{x}^* is a local minimum on SS, then

∇f(x∗)Tw≥0(w∈TS(x∗)).\nabla f(\mathbf{x}^*)^T\mathbf{w}\ge0\qquad(\mathbf{w}\in T_S(\mathbf{x}^*)).

Proof for a unit limiting direction. Put rk=∥xk−x∗∥>0r_k=\|\mathbf{x}^k-\mathbf{x}^*\|>0 and dk=(xk−x∗)/rk→d\mathbf{d}_k=(\mathbf{x}^k-\mathbf{x}^*)/r_k\to\mathbf{d}. Differentiability gives

f(xk)−f(x∗)rk=∇f(x∗)Tdk+o(1)⟶∇f(x∗)Td.\frac{f(\mathbf{x}^k)-f(\mathbf{x}^*)}{r_k}=\nabla f(\mathbf{x}^*)^T\mathbf{d}_k+o(1)\longrightarrow\nabla f(\mathbf{x}^*)^T\mathbf{d}.

Local minimality makes the left side nonnegative eventually. A negative limit would force arbitrarily nearby feasible points with a smaller objective, a contradiction. Multiplication by a nonnegative scalar extends the result to every tangent vector. Biegler, Theorem 4.8 and proof, pp. 74–75; Nocedal and Wright, Theorem 12.3, pp. 325–326.

Negative first-order term dominates the remainder

This is necessary, not sufficient. For min⁡x2\min x_2 subject to x2≥−x12x_2\ge-x_1^2, the origin has TS={d2≥0}T_S=\{d_2\ge0\} and ∇fTd=d2≥0\nabla f^T\mathbf{d}=d_2\ge0. Yet (t,−t2)(t,-t^2) is feasible and improves the objective for every nonzero tt. The loss appears at second order (Nocedal and Wright, Example (12.44), p. 326).

Linearization and constraint indices

Use separate index sets: E={1,…,m}\mathcal E=\{1,\ldots,m\} for equalities and AI(xˉ)={i:gi(xˉ)=0}\mathcal A_I(\bar{\mathbf{x}})=\{i:g_i(\bar{\mathbf{x}})=0\} for active inequalities. The combined row labels are tagged pairs (h,j)(h,j) and (g,i)(g,i); equality 1 and inequality 1 are distinct rows. Stack

JA=[JhJg,AI].\mathbf J_{\mathcal A}=\begin{bmatrix}\mathbf J_h\\J_{g,\mathcal A_I}\end{bmatrix}.

The linearized cone is

LS(xˉ)={d:Jhd=0, Jg,AId≤0}.L_S(\bar{\mathbf{x}})=\{\mathbf{d}:\mathbf J_h\mathbf{d}=\mathbf0,\ \mathbf J_{g,\mathcal A_I}\mathbf{d}\le\mathbf0\}.

Containment proof. For w∈TS\mathbf{w}\in T_S, write zk=xˉ+tkw+o(tk)\mathbf{z}^k=\bar{\mathbf{x}}+t_k\mathbf{w}+o(t_k). Expand an equality about the feasible point and divide by tk>0t_k>0: 0=hj(zk)/tk=∇hjTw+o(1)0=h_j(\mathbf{z}^k)/t_k=\nabla h_j^T\mathbf{w}+o(1). For an active inequality, 0≥gi(zk)/tk=∇giTw+o(1)0\ge g_i(\mathbf{z}^k)/t_k=\nabla g_i^T\mathbf{w}+o(1). Taking limits proves TS⊆LST_S\subseteq L_S. Inactive inequalities stay negative nearby by continuity and impose no first-order restriction. The remainder is o(tk)o(t_k), not o(tk2)o(t_k^2).

Linear constraints and curvature corrections

Linearized feasibility alone does not assert that xˉ+td\bar{\mathbf{x}}+t\mathbf{d} is feasible for a nonlinear constraint. A curved correction can be necessary.

Containment proof: expand, divide, and take limits

Affine constraints: exact first-order geometry

For Bx≤b\mathbf B\mathbf{x}\le\mathbf b, Cx=c\mathbf C\mathbf{x}=\mathbf c, take d\mathbf d with Cd=0\mathbf C\mathbf d=0 and Bid≤0\mathbf B_i\mathbf d\le0 for every active row. The straight path xˉ+td\bar{\mathbf{x}}+t\mathbf d satisfies the equalities and active inequalities exactly. Each inactive row has positive slack bi−Bixˉb_i-\mathbf B_i\bar{\mathbf{x}}; choose t>0t>0 small enough to preserve all finitely many slacks. Hence LS=TSL_S=T_S, even if the constraint rows are dependent.

At a local minimum, no d\mathbf d solves ∇fTd<0\nabla f^T\mathbf d<0, Cd=0\mathbf C\mathbf d=0, BAId≤0\mathbf B_{\mathcal A_I}\mathbf d\le0. The theorem of alternatives gives

∇f+BAITuAI+CTv=0,uAI≥0.\nabla f+\mathbf B_{\mathcal A_I}^T\mathbf u_{\mathcal A_I}+\mathbf C^T\mathbf v=0,\qquad\mathbf u_{\mathcal A_I}\ge0.

Set inactive multipliers to zero to obtain the complete KKT conditions. This is Biegler’s Theorem 4.11, pp. 75–76; Nocedal and Wright’s Lemma 12.7, pp. 338–339. Independence is not required for this affine-constraint argument. With a convex objective the existing convex KKT certificate proves global sufficiency; it does not require LICQ.

A cusp where KKT fails

min⁡xx1s.t.g1=x2−x13≤0,g2=−x13−x2≤0.\min_{\mathbf{x}}x_1\quad\text{s.t.}\quad g_1=x_2-x_1^3\le0,\qquad g_2=-x_1^3-x_2\le0.

Both constraints imply −x13≤x2≤x13-x_1^3\le x_2\le x_1^3, so x1≥0x_1\ge0; at x1=0x_1=0 they force x2=0x_2=0. The origin is the unique global solution. This is Biegler’s (4.44), Figure 4.8, p. 77.

import sys
from pathlib import Path
import numpy as np
import matplotlib.pyplot as plt

if "google.colab" in sys.modules:
    import urllib.request
    urllib.request.urlretrieve(
        "https://raw.githubusercontent.com/ndcbe/optimization/main/notebooks/helper.py",
        "helper.py",
    )
    import helper
    helper.easy_install()
else:
    sys.path.insert(0, str(Path("..").resolve()))
    import helper
plt.style.use("../../figures/dowling.mplstyle" if Path("../../figures/dowling.mplstyle").exists()
              else "https://raw.githubusercontent.com/ndcbe/optimization/main/figures/dowling.mplstyle")
x1_grid = np.linspace(-1.2, 1.2, 401)
cusp_data = {"x1": x1_grid.tolist(), "upper": (x1_grid**3).tolist(),
             "lower": (-x1_grid**3).tolist(), "gradients": [[0, 1], [0, -1]]}
helper.save_results("licq-cusp", cusp_data,
    notebook="notebooks/7-dev/Constraint-Qualifications.ipynb",
    source_cells=[("notebooks/7-dev/Constraint-Qualifications.ipynb", "results:cq-cusp-data")],
    description="Analytic cusp boundaries and active gradients; no optimization solve.", quiet=True)
results = cusp_data
HATCH_CYCLE = ["///", "\\\\"]
SHADE_ALPHA = 0.18
XLO, XHI = -1.2, 1.2
YLO, YHI = -1.35, 1.35

# One scale for both gradient arrows. They are unit vectors of equal length in
# opposite directions; drawing them at equal length is the whole point.
SCALE = 0.62


def _arrow(ax, base, vec, label, *, color, offset, ha="left", scale=SCALE):
    """One gradient, drawn AND named. The name is the greyscale-safe identity."""
    tip = np.asarray(base) + scale * np.asarray(vec)
    ax.arrow(
        base[0],
        base[1],
        scale * vec[0],
        scale * vec[1],
        width=0.022,
        length_includes_head=True,
        color=color,
        zorder=6,
    )
    ax.annotate(
        label,
        xy=(tip[0] + offset[0], tip[1] + offset[1]),
        fontsize=13,
        ha=ha,
        va="center",
        zorder=7,
        bbox=dict(facecolor="white", edgecolor="none", pad=1.0),
    )



x1 = np.asarray(results["x1"])
upper = np.asarray(results["upper"])          # x2 = x1^3,  boundary of g1 <= 0
lower = np.asarray(results["lower"])       # x2 = -x1^3, boundary of g2 <= 0

fig, ax = plt.subplots(figsize=(5.2, 5.0))

# g1 <= 0 is everything BELOW x2 = x1^3.
ax.fill_between(
    x1,
    YLO,
    np.clip(upper, YLO, YHI),
    facecolor="0.55",
    alpha=SHADE_ALPHA,
    hatch=HATCH_CYCLE[0],
    edgecolor=plt.rcParams["hatch.color"],
    linewidth=0.0,
    zorder=0,
)
# g2 <= 0 is everything ABOVE x2 = -x1^3.
ax.fill_between(
    x1,
    np.clip(lower, YLO, YHI),
    YHI,
    facecolor="0.55",
    alpha=SHADE_ALPHA,
    hatch=HATCH_CYCLE[1],
    edgecolor=plt.rcParams["hatch.color"],
    linewidth=0.0,
    zorder=0,
)

ax.plot(x1, upper, color="#0072B2", linestyle="-", linewidth=2.5, zorder=3)
ax.plot(x1, lower, color="#E69F00", linestyle="--", linewidth=2.5, zorder=3)

ax.annotate(
    "$g_1(\\mathbf{x}) = x_2 - x_1^3 \\leq 0$",
    xy=(-1.15, -1.22),
    fontsize=12,
    bbox=dict(facecolor="white", edgecolor="none", pad=1.0),
    zorder=4,
)
ax.annotate(
    "$g_2(\\mathbf{x}) = -x_1^3 - x_2 \\leq 0$",
    xy=(-1.15, 1.10),
    fontsize=12,
    bbox=dict(facecolor="white", edgecolor="none", pad=1.0),
    zorder=4,
)

# The feasible set: the doubly hatched sliver, x1 >= 0, between the curves.
ax.annotate(
    "feasible set\n(both hatches)",
    xy=(0.55, 0.02),
    xytext=(0.86, -0.72),
    fontsize=12,
    ha="center",
    va="center",
    arrowprops=dict(arrowstyle="->", color="black", linewidth=1.2),
    bbox=dict(facecolor="white", edgecolor="none", pad=1.0),
    zorder=9,
)

# x* = (0,0): the cusp.
ax.plot([0.0], [0.0], marker="*", markersize=18, color="black", linestyle="none", zorder=8)
ax.annotate(
    "$\\mathbf{x}^*$",
    xy=(0.09, -0.17),
    fontsize=14,
    bbox=dict(facecolor="white", edgecolor="none", pad=1.0),
    zorder=8,
)

# The two active gradients at x*. grad g1 = [0,1]^T, grad g2 = [0,-1]^T:
# antiparallel, so the active Jacobian has rank 1 and LICQ fails.
_arrow(
    ax,
    (0.0, 0.0),
    (0.0, 1.0),
    "$\\nabla g_1(\\mathbf{x}^*)$\n$= (0,\\, 1)^{T}$",
    color="#0072B2",
    offset=(-0.10, -0.02),
    ha="right",
)
_arrow(
    ax,
    (0.0, 0.0),
    (0.0, -1.0),
    "$\\nabla g_2(\\mathbf{x}^*)$\n$= (0,\\, -1)^{T}$",
    color="#E69F00",
    offset=(-0.10, 0.02),
    ha="right",
)

ax.axhline(0.0, color="black", linewidth=0.8, zorder=1)
ax.axvline(0.0, color="black", linewidth=0.8, zorder=1)
ax.set_xlim(XLO, XHI)
ax.set_ylim(YLO, YHI)
ax.set_xlabel("$x_1$")
ax.set_ylabel("$x_2$")
ax.set_aspect("equal", adjustable="box")

fig.tight_layout()
helper.save_figure(fig, "licq-cusp", quiet=True)
<Figure size 520x500 with 1 Axes>

Explain the geometry. The overlap of both hatches is feasible. Why is the origin optimal even though the objective gradient is nonzero? The constraints restrict x1x_1 to be nonnegative and permit only x2=0x_2=0 when x1=0x_1=0.

Full KKT case analysis

With L=x1+u1(x2−x13)+u2(−x13−x2)L=x_1+u_1(x_2-x_1^3)+u_2(-x_1^3-x_2), stationarity is

∇xL=[1−3(u1+u2)x12u1−u2]=0.\nabla_x L=\begin{bmatrix}1-3(u_1+u_2)x_1^2\\u_1-u_2\end{bmatrix}=\mathbf0.

The remaining conditions are g1,g2≤0g_1,g_2\le0, u1,u2≥0u_1,u_2\ge0, u1g1=u2g2=0u_1g_1=u_2g_2=0. At the origin the first stationarity component is 1 for every finite multiplier vector.

  1. Neither multiplier positive: u1=u2=0u_1=u_2=0 gives gradient (1,0)T(1,0)^T, so stationarity fails. Zero multipliers do not remove the constraints or make this feasible problem unbounded.

  2. Only u1>0u_1>0: the second stationarity row forces u1=0u_1=0, a contradiction.

  3. Only u2>0u_2>0: the second row forces u2=0u_2=0, again a contradiction.

  4. Both positive: the second row gives u1=u2=uu_1=u_2=u; the first gives x12=1/(6u)x_1^2=1/(6u). Complementarity requires both constraints active, which forces x1=x2=0x_1=x_2=0, contradicting the first row. The algebraic relation has both square-root signs; feasibility selects x1≥0x_1\ge0, but no finite feasible KKT point results.

An approximate stationarity path illustrates the difficulty: for t>0t>0, choose (x1,x2)=(t,0)(x_1,x_2)=(t,0), u1=u2=1/(6t2)u_1=u_2=1/(6t^2). Stationarity holds and the point is feasible, but both inequalities are slack and uigi=−t/6≠0u_i g_i=-t/6\ne0. As t↓0t\downarrow0, complementarity residuals vanish while multipliers diverge. This is not a family of exact KKT points. The original scan’s 3u3u denominator is replaced by the verified 6u6u relation.

Actual and linearized directions at the cusp

At the origin the active row Jacobian is

Jg=[010−1].\mathbf J_g=\begin{bmatrix}0&1\\0&-1\end{bmatrix}.

Its inequalities impose d2≤0d_2\le0 and −d2≤0-d_2\le0, hence LS={(d1,0):d1∈R}L_S=\{(d_1,0):d_1\in\mathbb R\}. In contrast, ∣x2∣≤x13|x_2|\le x_1^3 and x1≥0x_1\ge0 imply every normalized nonzero feasible chord tends to (1,0)T(1,0)^T: ∣x2∣/x1≤x12→0|x_2|/x_1\le x_1^2\to0. Therefore TS={(d1,0):d1≥0}T_S=\{(d_1,0):d_1\ge0\}.

The tangent ray and linearized line

Biegler calls (1,0)T(1,0)^T d1\mathbf d_1 and (−1,0)T(-1,0)^T d2\mathbf d_2. The left-pointing d2\mathbf d_2 has ∇fTd2=−1\nabla f^T\mathbf d_2=-1 but cannot be realized by a feasible sequence. Two handwritten sketches reverse these names; the algebra and geometry fix the labels. A constraint qualification eliminates this extra first-order direction.

LICQ and feasible curved corrections

LICQ holds at a feasible point when all equality gradients and all active inequality gradients are jointly independent: rank⁡JA=m+∣AI∣\operatorname{rank}\mathbf J_{\mathcal A}=m+|\mathcal A_I|. It is a property of the constraint representation at a point, not a requirement that the point already be optimal. Equalities, weakly active inequalities, and active bounds all count. If there are more active rows than variables, LICQ cannot hold. Biegler, Definition 4.12 at the foot of p. 77; Nocedal and Wright, Definition 12.4, p. 320.

The cusp has two antiparallel nonzero rows, rank 1 rather than 2, so LICQ fails. Nonzero individual gradients are not enough.

Independent and dependent active rows

Reverse inclusion under LICQ. Let cA(z)c_{\mathcal A}(\mathbf z) stack all equalities and active inequalities in the tagged row order, and let Z∈Rn×(n−m−∣AI∣)Z\in\mathbb R^{n\times(n-m-|\mathcal A_I|)} have basis columns for ker⁡JA\ker \mathbf J_{\mathcal A}. For any d∈LS\mathbf d\in L_S, consider

R(z,t)=[cA(z)−tJAdZT(z−xˉ−td)]=0.R(\mathbf z,t)=\begin{bmatrix}c_{\mathcal A}(\mathbf z)-tJ_{\mathcal A}\mathbf d\\Z^T(\mathbf z-\bar{\mathbf x}-t\mathbf d)\end{bmatrix}=\mathbf0.

At (xˉ,0)(\bar{\mathbf x},0) its derivative with respect to z\mathbf z is [JA;ZT][\mathbf J_{\mathcal A};\mathbf Z^T], a square nonsingular matrix: a vector in its null space belongs to ker⁡JA=range⁡Z\ker \mathbf J_{\mathcal A}=\operatorname{range}\mathbf Z and is orthogonal to that space, hence is zero. The C1 implicit function theorem requires a C1 residual map, a zero residual at the base point and an invertible derivative with respect to the unknowns; these follow from the stated neighborhood data, feasibility and the displayed null-space argument. It yields a C1C^1 path z(t)\mathbf z(t), and differentiation at zero gives z′(0)=d\mathbf z'(0)=\mathbf d. Thus z(t)=xˉ+td+o(t)\mathbf z(t)=\bar{\mathbf x}+t\mathbf d+o(t).

The construction gives exactly hj(z(t))=t∇hjTd=0h_j(\mathbf z(t))=t\nabla h_j^T\mathbf d=0 and gi(z(t))=t∇giTd≤0g_i(\mathbf z(t))=t\nabla g_i^T\mathbf d\le0 for active inequalities; continuity preserves the inactive inequalities for small positive tt. These exact identities come from solving R=0R=0, not merely truncating a Taylor expansion. Consequently LS=TSL_S=T_S. This adapts Nocedal and Wright, Lemma 12.2, pp. 323–325, to g≤0g\le0 and row Jacobians; Biegler, Lemma 4.13, p. 78, requires the errata’s hjh_j subscript.

For the circle equality h=(x1−1)2+x22−1=0h=(x_1-1)^2+x_2^2-1=0 at (0,0)(0,0), d=(0,1)T\mathbf d=(0,1)^T is tangent. The straight step (0,t)(0,t) has h=t2>0h=t^2>0. The corrected path (1−1−t2,t)(1-\sqrt{1-t^2},t) is feasible and differs from the straight step by (t2/2+O(t4),0)(t^2/2+O(t^4),0). LICQ promises a nearby feasible path, not feasibility of the straight step.

From no feasible descent to KKT

At a C1C^1 local minimum with LICQ, TS=LST_S=L_S, so no direction satisfies

∇fTd<0,Jhd=0,Jg,AId≤0.\nabla f^T\mathbf d<0,\qquad \mathbf J_h\mathbf d=0,\qquad \mathbf J_{g,\mathcal A_I}\mathbf d\le0.

The finite-dimensional linear alternative says that absence of a direction satisfying that system is equivalent to existence of a nonnegative active inequality multiplier and unrestricted equality multiplier balancing the objective gradient. Thus it gives uAI≥0\mathbf u_{\mathcal A_I}\ge0, unrestricted v\mathbf v, with ∇f+Jg,AITuAI+JhTv=0\nabla f+\mathbf J_{g,\mathcal A_I}^T\mathbf u_{\mathcal A_I}+\mathbf J_h^T\mathbf v=0. Inactive multipliers are zero, yielding dual feasibility and complementarity. Feasibility is already a hypothesis. This proves KKT necessity (Biegler, Theorem 4.14, p. 78; Nocedal and Wright, Theorem 12.1, p. 321, and proof pp. 323–329).

Normals balance the objective gradient

Conversely, a KKT vector implies ∇fTd=−uAITJg,AId≥0\nabla f^T\mathbf d=-\mathbf u_{\mathcal A_I}^TJ_{g,\mathcal A_I}\mathbf d\ge0 for every d∈LS\mathbf d\in L_S. This algebra needs no CQ. It is still a first-order necessary test, not general sufficiency. The separate convex certificate is at the Local Optimality reference.

Multiplier uniqueness and its limits

At a fixed KKT point, stack active multipliers in the same order as JA\mathbf J_{\mathcal A}, with equality components unrestricted and inequality components nonnegative. If λa\boldsymbol\lambda^a and λb\boldsymbol\lambda^b both satisfy stationarity, then

JAT(λa−λb)=0.\mathbf J_{\mathcal A}^T(\boldsymbol\lambda^a-\boldsymbol\lambda^b)=0.

Full row rank makes JAT\mathbf J_{\mathcal A}^T injective, so the difference is zero. Equivalently, multiply by JA\mathbf J_{\mathcal A}: the row Gram matrix JAJAT\mathbf J_{\mathcal A}\mathbf J_{\mathcal A}^T is positive definite. This is the row-oriented version of Biegler’s Theorem 4.15 proof, p. 79; his column-oriented Gram matrix has the factors in the opposite order.

Injectivity or a null direction in multiplier space

Failure of LICQ does not force multiple KKT multipliers. For min⁡0\min0 subject to −x≤0-x\le0, −2x≤0-2x\le0, at x=0x=0 stationarity and nonnegativity require u1+2u2=0u_1+2u_2=0, hence (u1,u2)=(0,0)(u_1,u_2)=(0,0) uniquely despite dependent rows. Without LICQ the unconstrained linear stationarity system has a null direction, but the multiplier sign restrictions may remove all nonzero displacements.

For redundant equalities the situation differs: if JhTν=0\mathbf J_h^T\boldsymbol\nu=0, equality multipliers can move freely as v+tν\mathbf v+t\boldsymbol\nu without sign restrictions. The active equality KKT matrix has null vector (0,ν)T(\mathbf0,\boldsymbol\nu)^T, whatever the Hessian.

Uniqueness alone does not establish a differentiable solution branch or a shadow price. The sensitivity reference states the branch, sign, and second-order conditions and gives examples of nonsmooth values.

MFCQ, geometry, and bounded multipliers

MFCQ holds when Jh\mathbf J_h has full row rank and ∃d∈Rn: Jhd=0\exists\mathbf d\in\mathbb R^n:\ \mathbf J_h\mathbf d=\mathbf0 and ∇gi(xˉ)Td<0\nabla g_i(\bar{\mathbf x})^T\mathbf d<0 for every i∈AIi\in\mathcal A_I. With no active inequalities the strict condition is vacuous; equality independence still matters. This tests a feasible point, not just a solution. Biegler, Definition 4.16, p. 79; Nocedal and Wright, Definition 12.6, p. 339.

LICQ implies MFCQ: full row rank allows solving JAd=(0,−1)T\mathbf J_{\mathcal A}\mathbf d=(\mathbf0,-\mathbf1)^T. The equality part is zero and every active inequality decreases strictly.

Strictly weaker: take h=x2=0h=x_2=0, g1=−x1≤0g_1=-x_1\le0, g2=−2x1≤0g_2=-2x_1\le0 at the origin. The three active rows have rank 2, so LICQ fails; d=(1,0)T\mathbf d=(1,0)^T satisfies MFCQ. For f=x1f=x_1, stationarity gives v=0v=0, u1+2u2=1u_1+2u_2=1, u1,u2≥0u_1,u_2\ge0. The multiplier set is the closed line segment from (1,0)(1,0) to (0,1/2)(0,1/2): bounded, nonunique.

A common inward direction and the multiplier segment

At the cusp, MFCQ would require d2<0d_2<0 and −d2<0-d_2<0, which is impossible. No finite KKT multiplier exists there.

Why MFCQ bounds a nonempty KKT multiplier set. If a sequence of KKT multipliers were unbounded, omit its identically zero inactive components, normalize it by its diverging norm, and take a convergent subsequence on the compact unit sphere in Rm+∣AI∣\mathbb R^{m+|\mathcal A_I|}. Dividing stationarity by that norm gives

Jg,AITu^+JhTv^=0,u^≥0,∥(u^,v^)∥=1.\mathbf J_{g,\mathcal A_I}^T\widehat{\mathbf u}+\mathbf J_h^T\widehat{\mathbf v}=\mathbf0,\quad\widehat{\mathbf u}\ge0,\quad\|(\widehat{\mathbf u},\widehat{\mathbf v})\|=1.

Dot with the MFCQ direction. Each active inequality derivative is strictly negative, so a zero sum forces u^=0\widehat{\mathbf u}=\mathbf0. Equality independence then forces v^=0\widehat{\mathbf v}=\mathbf0, contradicting unit norm. The fixed-point KKT multiplier set is closed, so it is compact if nonempty. MFCQ also ensures KKT existence at a C1C^1 local minimum.

Conversely, failure of MFCQ yields a nonzero homogeneous multiplier (u^≥0,v^)(\widehat{\mathbf u}\ge\mathbf0,\widehat{\mathbf v}) with Jg,AITu^+JhTv^=0\mathbf J_{g,\mathcal A_I}^T\widehat{\mathbf u}+\mathbf J_h^T\widehat{\mathbf v}=\mathbf0: equality dependence gives one immediately; otherwise the strict-direction theorem of alternatives gives one. Add its nonnegative ray to any existing KKT vector to obtain an unbounded multiplier set. Thus at a fixed KKT point with a nonempty multiplier set, MFCQ is equivalent to boundedness. The nonempty condition matters: min⁡x\min x subject to x2≤0x^2\le0 has sole feasible point 0, fails MFCQ, and has no KKT vector; the empty set is bounded in the set-theoretic sense. See Nocedal and Wright, p. 339, with this scope made explicit.

Normalized multipliers would give a forbidden recession directionA hypothetical multiplier sequence normalizes to the compact unit sphere, shown in two dimensions

What each qualification guarantees

For C1C^1 data at a local minimum:

ConditionGeometryKKT multipliers
LICQTS=LST_S=L_S; all active rows independentExist and are unique
MFCQTS=LST_S=L_S; common strict inward direction with equality tangencyExist; nonempty compact set, possibly nonunique
All active constraints affineTS=LST_S=L_S without independenceExist, possibly unbounded
Abadie’s CQThe statement TS=LST_S=L_S itselfExistence by the same alternative argument; no general uniqueness or boundedness

These are sufficient hypotheses; their failure is not proof that KKT fails. Example: min⁡x2\min x^2 subject to x2≤0x^2\le0 has a KKT vector at zero although LICQ and MFCQ fail. Its multiplier set is [0,∞)[0,\infty).

MFCQ gives TS=LST_S=L_S: for any d∈LS\mathbf d\in L_S, add δw\delta\mathbf w with a strict MFCQ direction w\mathbf w. All active inequalities then decrease strictly. Full row rank of Jh\mathbf J_h gives, by the implicit function theorem, an equality-feasible path xˉ+t(d+δw)+o(t)\bar{\mathbf x}+t(\mathbf d+\delta\mathbf w)+o(t); strict inequality derivatives make it feasible for small t>0t>0. Thus d+δw∈TS\mathbf d+\delta\mathbf w\in T_S. Let δ↓0\delta\downarrow0 and use closedness of the tangent cone to get d∈TS\mathbf d\in T_S.

Peterson (1973), SIAM Review 15, pp. 639–654, DOI, Table 1 pp. 643–644 and Figure 4 p. 645, maps a broader CQ hierarchy. Table 1 puts MFCQ on p. 643 and LICQ on the continuation p. 644. His principal formulation uses inequalities and a general set XX; do not encode equalities as two opposite inequalities when translating MFCQ. His arrows point toward weaker conditions. The equality-aware definitions here follow the textbooks.

Example revisited: solve with Pyomo

The following original experiment intentionally approaches the degenerate cusp with Ipopt. Keep its iterates and reported termination distinct from an exact KKT certificate: there is no finite multiplier vector at the true solution. Solver versions and tolerances can change the numerical output.

import pyomo.environ as pyo
from pyomo.environ import (
    ConcreteModel,
    Var,
    Objective,
    Constraint,
    SolverFactory,
    Suffix,
    minimize,
    value,
)

## Create concrete Pyomo model
m = ConcreteModel()

## Set up to extract dual variables after model solve.
m.dual = Suffix(direction=Suffix.IMPORT)

## Declare variables with initial values
m.x1 = Var(initialize=1)
m.x2 = Var(initialize=1)

## Declare objective
m.OBJ = Objective(expr=m.x1, sense=minimize)

m.g1 = Constraint(expr=m.x2 <= m.x1**3)

m.g2 = Constraint(expr=-m.x1**3 <= m.x2)

## Specify IPOPT as solver
solver = SolverFactory("ipopt")

## Solve the model
results = solver.solve(m, tee=True)
assert pyo.check_optimal_termination(results), (
    f"Solve failed: status={results.solver.status}, "
    f"termination={results.solver.termination_condition}"
)

## Return the solution
print("x1 = ", value(m.x1))
print("x2 = ", value(m.x2))
print("\n")

## Inspect dual variables
m.dual.display()
Ipopt 3.13.2: 

******************************************************************************
This program contains Ipopt, a library for large-scale nonlinear optimization.
 Ipopt is released as open source code under the Eclipse Public License (EPL).
         For more information visit http://projects.coin-or.org/Ipopt

This version of Ipopt was compiled from source code available at
    https://github.com/IDAES/Ipopt as part of the Institute for the Design of
    Advanced Energy Systems Process Systems Engineering Framework (IDAES PSE
    Framework) Copyright (c) 2018-2019. See https://github.com/IDAES/idaes-pse.

This version of Ipopt was compiled using HSL, a collection of Fortran codes
    for large-scale scientific computation.  All technical papers, sales and
    publicity material resulting from use of the HSL codes within IPOPT must
    contain the following acknowledgement:
        HSL, a collection of Fortran codes for large-scale scientific
        computation. See http://www.hsl.rl.ac.uk.
******************************************************************************

This is Ipopt version 3.13.2, running with linear solver ma27.

Number of nonzeros in equality constraint Jacobian...:        0
Number of nonzeros in inequality constraint Jacobian.:        4
Number of nonzeros in Lagrangian Hessian.............:        1

Total number of variables............................:        2
                     variables with only lower bounds:        0
                variables with lower and upper bounds:        0
                     variables with only upper bounds:        0
Total number of equality constraints.................:        0
Total number of inequality constraints...............:        2
        inequality constraints with only lower bounds:        0
   inequality constraints with lower and upper bounds:        0
        inequality constraints with only upper bounds:        2

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  1.0000000e+00 0.00e+00 7.89e-01  -1.0 0.00e+00    -  0.00e+00 0.00e+00   0
   1  9.7574511e-01 0.00e+00 1.04e-02  -1.0 2.54e-01    -  1.00e+00 1.00e+00f  1
   2  6.6105230e-01 0.00e+00 2.39e-01  -1.7 4.64e+00    -  1.00e+00 3.73e-01f  1
   3  4.6924687e-01 0.00e+00 2.74e-01  -1.7 1.92e-01    -  1.00e+00 1.00e+00h  1
   4  3.2820073e-01 0.00e+00 3.14e-01  -1.7 1.62e-01    -  1.00e+00 8.72e-01h  1
   5  2.6957767e-01 0.00e+00 1.60e-01  -1.7 5.86e-02    -  1.00e+00 1.00e+00f  1
   6  1.8935274e-01 0.00e+00 2.24e+00  -2.5 2.21e-01    -  1.00e+00 3.63e-01f  1
   7  1.3091124e-01 0.00e+00 3.19e-01  -2.5 5.84e-02    -  1.00e+00 1.00e+00h  1
   8  9.6126564e-02 0.00e+00 2.03e+00  -2.5 4.69e-02    -  1.00e+00 7.41e-01h  1
   9  7.1009142e-02 0.00e+00 2.58e-01  -2.5 2.51e-02    -  1.00e+00 1.00e+00f  1
iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
  10  5.1777995e-02 0.00e+00 1.21e+01  -2.5 3.18e-02    -  1.00e+00 6.04e-01h  1
  11  4.0824512e-02 0.00e+00 1.97e-01  -2.5 1.10e-02    -  1.00e+00 1.00e+00f  1
  12  3.4583313e-02 0.00e+00 5.91e+01  -2.5 1.80e-02    -  1.00e+00 3.47e-01h  2
  13  2.6914569e-02 0.00e+00 1.79e-01  -2.5 7.67e-03    -  1.00e+00 1.00e+00h  1
  14  2.0308733e-02 0.00e+00 2.01e-01  -2.5 6.61e-03    -  1.00e+00 1.00e+00h  1
  15  1.9046691e-02 0.00e+00 3.31e-02  -2.5 1.26e-03    -  1.00e+00 1.00e+00h  1
  16  1.2746908e-02 0.00e+00 5.71e+02  -3.8 1.83e-02    -  1.00e+00 3.44e-01f  1
  17  8.7118644e-03 0.00e+00 3.19e-01  -3.8 4.04e-03    -  1.00e+00 1.00e+00f  1
  18  7.5197334e-03 0.00e+00 1.09e+03  -3.8 3.10e-03    -  1.00e+00 3.85e-01f  2
  19  5.1147446e-03 0.00e+00 3.19e-01  -3.8 2.40e-03    -  1.00e+00 1.00e+00f  1
iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
  20  3.3178215e-03 0.00e+00 3.78e-01  -3.8 1.80e-03    -  1.00e+00 1.00e+00f  1
  21  2.2893616e-03 0.00e+00 3.40e-01  -3.8 1.03e-03    -  1.00e+00 1.00e+00f  1
  22  1.8283227e-03 0.00e+00 8.34e+04  -3.8 4.48e-03    -  1.00e+00 1.03e-01f  2
  23  4.5313818e-04 0.00e+00 8.82e-01  -3.8 1.38e-03    -  1.00e+00 1.00e+00f  1
  24  3.0653152e-04 0.00e+00 3.16e+05  -5.7 1.47e-04   4.0 2.32e-01 1.00e+00h  1
  25 -5.5285928e-04 0.00e+00 1.00e+00  -5.7 8.59e-04    -  1.00e+00 1.00e+00f  1
  26 -1.1223885e-02 1.40e-06 1.36e+04  -5.7 7.96e-01    -  1.00e+00 1.34e-02f  1
  27 -1.1107786e-02 1.36e-06 1.16e+03  -5.7 3.72e-03    -  1.00e+00 3.12e-02h  6
  28 -7.4290268e-03 4.00e-07 4.64e-01  -5.7 3.68e-03    -  1.00e+00 1.00e+00h  1
  29 -5.8687786e-03 1.92e-07 8.66e+02  -5.7 2.41e-03    -  1.00e+00 6.47e-01h  1
iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
  30 -5.8542172e-03 1.91e-07 3.64e+03  -5.7 1.86e-03    -  1.00e+00 7.81e-03f  8
  31 -3.9974633e-03 5.39e-08 3.37e-01  -5.7 1.86e-03    -  1.00e+00 1.00e+00h  1
  32 -2.9534118e-03 1.58e-08 5.23e+02  -5.7 1.12e-03    -  1.00e+00 9.29e-01h  1
  33 -2.9344353e-03 1.53e-08 1.06e+04  -5.7 6.07e-04    -  1.00e+00 3.12e-02f  6
  34 -2.3405157e-03 2.82e-09 1.76e-01  -5.7 5.94e-04    -  1.00e+00 1.00e+00h  1
  35 -2.1660008e-03 1.62e-10 3.83e-02  -5.7 1.75e-04    -  1.00e+00 1.00e+00h  1
  36 -2.1508378e-03 0.00e+00 6.75e-04  -5.7 1.52e-05    -  1.00e+00 1.00e+00h  1
  37 -2.1544258e-03 0.00e+00 6.10e-06  -8.6 3.59e-06    -  1.00e+00 1.00e+00f  1
  38 -2.1544329e-03 0.00e+00 7.78e-12  -9.0 7.05e-09    -  1.00e+00 1.00e+00h  1

Number of Iterations....: 38

                                   (scaled)                 (unscaled)
Objective...............:  -2.1544328718688505e-03   -2.1544328718688505e-03
Dual infeasibility......:   7.7819972688075723e-12    7.7819972688075723e-12
Constraint violation....:   0.0000000000000000e+00    0.0000000000000000e+00
Complementarity.........:   9.0909382315597638e-10    9.0909382315597638e-10
Overall NLP error.......:   2.5317795697139416e-12    9.0909382315597638e-10


Number of objective function evaluations             = 64
Number of objective gradient evaluations             = 39
Number of equality constraint evaluations            = 0
Number of inequality constraint evaluations          = 64
Number of equality constraint Jacobian evaluations   = 0
Number of inequality constraint Jacobian evaluations = 39
Number of Lagrangian Hessian evaluations             = 38
Total CPU secs in IPOPT (w/o function evaluations)   =      0.002
Total CPU secs in NLP function evaluations           =      0.000

EXIT: Optimal Solution Found.
x1 =  -0.0021544328718688505
x2 =  4.26637029618013e-25


dual : Direction=IMPORT, Datatype=FLOAT
    Key : Value
     g1 : -35907.30543965533
     g2 : -35907.30543965533

Discussion. Inspect the iteration count, final primal residuals, point, and imported duals. Why is the point only approximately zero? Compare the growth of multiplier magnitudes with 1/(6t2)1/(6t^2), rather than treating the solver’s output as a finite limiting KKT vector.

The raw Pyomo dual suffix uses the solver interface’s constraint orientation. It is not automatically the nonnegative uiu_i of the canonical gi≤0g_i\le0 form. For this pair of upper/lower constraints, check the mapping against stationarity before interpreting the signs; the worked suffix checks illustrate this procedure. A large negative imported value does not by itself violate canonical dual feasibility.

For diagnosing larger models, continue to NLP Diagnostics with Degeneracy Hunter: full row-dependence theory, QR/MILP workflow, scaling and case-study context accompany the executable diagnostic example.

Check the original model, rather than only the termination banner

The current default run reports an optimal termination at a slightly negative x1x_1. Exact cusp feasibility requires x1≥0x_1\ge0. Re-evaluate the original inequalities and multiplier products below. Both imported suffixes convert as ui=−m.dual[m.gi]u_i=-\texttt{m.dual[m.gi]} for this model; the stationarity residual checks that mapping.

Ipopt’s options reference describes bound relaxation and its limits. In an inequality formulation with slack variables, the internal feasibility and complementarity report can differ from evaluation of the original inequality. The numerical output here establishes that difference directly: small primal violation multiplied by a very large multiplier need not produce a small original-model complementarity residual. Keep the original experiment unchanged; an optimal solver status is not a proof of exact feasibility or KKT satisfaction at the cusp.

x = np.array([value(m.x1), value(m.x2)])
g = np.array([x[1] - x[0]**3, -x[0]**3 - x[1]])
u = -np.array([m.dual[m.g1], m.dual[m.g2]])
stationarity = np.array([1 - 3 * (u[0] + u[1]) * x[0]**2, u[0] - u[1]])
print(f"Original-model primal violation: {max(0.0, float(g.max())):.6e}")
print(f"Canonical multipliers: {u[0]:.6e}, {u[1]:.6e}")
print(f"Stationarity infinity norm: {np.linalg.norm(stationarity, np.inf):.6e}")
print(f"Original complementarity infinity norm: {np.linalg.norm(u * g, np.inf):.6e}")
assert np.all(u >= 0) and np.linalg.norm(stationarity, np.inf) < 1e-6
Original-model primal violation: 9.999975e-09
Canonical multipliers: 3.590731e+04, 3.590731e+04
Stationarity infinity norm: 7.782219e-12
Original complementarity infinity norm: 3.590721e-04