From Simplex to Reluplex: How We Learned to Verify Neural Networks

Technical notes on Katz et al. (2017) — with interactive figures

Reluplex is one of those papers where the core idea is deeply satisfying once you see it. But to see it, you need to understand what came before it. This post builds the intuition from the ground up: linear programming, the simplex method, why ReLU activation functions break everything, and how Reluplex fixes it.

Every concept has an interactive figure. Play with them.


1. The Setup: What Does “Verify a Neural Network” Mean?

A neural network is a function $f: \mathbb{R}^m \to \mathbb{R}^n$. Verification means proving that for all inputs $x$ in some region $\mathcal{X}$, the output $f(x)$ satisfies some property $\mathcal{P}$.

For example, in the ACAS Xu collision avoidance system:

  • Input region $\mathcal{X}$: “the intruder aircraft is directly ahead, within 1000 ft, closing fast”
  • Property $\mathcal{P}$: “the system does not output clear-of-conflict”

Verification asks: does $f(x) \in \mathcal{P}$ for every $x \in \mathcal{X}$? If yes, the property is proved. If not, the verifier returns a counterexample — a specific $x$ that violates it.

This is fundamentally different from testing, which checks finitely many points. Verification covers the entire continuous region.


2. Linear Programming and the Simplex Method

Before we can extend simplex, we need to understand it.

A linear program (LP) is a system of linear constraints over real-valued variables. For verification purposes, we only need the feasibility problem: does a solution exist?

Given variables $x_1, \ldots, x_n$ with bounds $l_i \leq x_i \leq u_i$ and linear equations (the tableau):

\[b_k = \sum_j c_{k,j} \, x_j\]

the simplex method finds an assignment $\alpha$ where every variable is within its bounds and every equation holds — or proves none exists.

The Key Data Structures

Simplex maintains:

  • Basic variables $B$: variables defined by the tableau equations (think of them as “dependent”)
  • Non-basic variables $N = X \setminus B$: the “free” variables
  • Tableau $T$: each basic variable expressed as a linear combination of non-basic variables
  • Assignment $\alpha$: current value for every variable
  • Bounds $l, u$: lower and upper bounds for each variable

The critical invariant: the assignment always satisfies the tableau equations, even when some variables are out of bounds. Simplex iteratively fixes out-of-bounds variables.

The Simplex Rules

The algorithm applies five rules:

Update — if a non-basic variable $x_j$ is out of bounds, directly adjust its value (and update all basic variables that depend on it through the tableau).

Pivot — if a basic variable $x_i$ is out of bounds, it can’t be directly adjusted (it’s defined by the equation). So swap it with a non-basic variable $x_j$ that has slack — room to move in the direction that helps $x_i$. After the pivot, $x_i$ becomes non-basic and can be updated.

Success — if all variables are within bounds, output SAT with the current assignment.

Failure — if a basic variable is out of bounds and no non-basic variable has slack, the system is infeasible: UNSAT.

The “slack” concept is important. A non-basic variable $x_j$ has positive slack for basic variable $x_i$ if adjusting $x_j$ can increase $x_i$’s value without violating $x_j$’s own bounds. Formally:

\[\text{slack}^+(x_i) = \{x_j \notin B \mid (T_{i,j} > 0 \wedge \alpha(x_j) < u(x_j)) \;\lor\; (T_{i,j} < 0 \wedge \alpha(x_j) > l(x_j))\}\]

The simplex method is efficient in practice — typically polynomial time — even though worst-case complexity is exponential. It moves along vertices of the feasible polytope, improving at each step.


3. Neural Networks as Constraint Systems

A neural network with ReLU activations can be encoded as a set of linear equations plus ReLU constraints.

For each neuron in hidden layer $i$, introduce two variables:

  • $v^b$ (backward-facing): the pre-activation value, defined by the linear combination from the previous layer
  • $v^f$ (forward-facing): the post-activation value

The linear relationships become tableau equations:

\[v^b_{i,j} = \sum_k w_{j,k} \, v^f_{i-1,k} + b_j\]

And each activation imposes:

\[\text{ReLU}(v^b, v^f) \iff v^f = \max(0, v^b)\]

The linear parts are standard LP. The problem is the ReLU constraints — they’re nonlinear and non-convex.


4. The Naive Approach (and Why It Fails)

The obvious strategy: for each ReLU, split into two cases (active or inactive). Each case makes the ReLU linear, so you get a pure LP that simplex can solve.

For $n$ ReLU nodes, this creates $2^n$ subproblems in the worst case.

ACAS Xu networks have 300 ReLU nodes. That’s $2^{300} \approx 10^{90}$ subproblems — more than the number of atoms in the observable universe.

In practice, SAT solvers and branch-and-bound methods can prune many of these, but experiments by Katz et al. (and others) showed that even with good heuristics, this approach stalls on networks beyond ~20 nodes.


5. The Reluplex Idea: Be Lazy About ReLUs

This is the key insight. Instead of pre-committing to each ReLU’s state, let ReLU constraints be temporarily violated — just like simplex lets bound constraints be temporarily violated.

Reluplex extends the simplex configuration with a set $R \subset X \times X$ of ReLU pairs. Each pair $(v^b, v^f)$ represents a ReLU constraint $v^f = \max(0, v^b)$.

The algorithm maintains the invariant that the tableau equations always hold, but both bound violations and ReLU violations are allowed during the search. The solver iteratively fixes whichever violation it picks, using new rules on top of standard simplex.

The Reluplex Rules

Update$_b$ — if the backward variable $v^b$ is non-basic, adjust it to satisfy $v^f = \max(0, v^b)$:

\[\alpha(v^b) \leftarrow \alpha(v^f) \quad \text{(if } \alpha(v^f) \geq 0\text{)}\]

Update$_f$ — if the forward variable $v^f$ is non-basic, adjust it:

\[\alpha(v^f) \leftarrow \max(0, \alpha(v^b))\]

PivotForRelu — if a ReLU variable is basic (can’t be directly updated), pivot it to make it non-basic first, then apply Update$_b$ or Update$_f$.

ReluSplit — if a ReLU pair can’t be fixed by updates (the solver keeps oscillating), split: guess that $v^b \leq 0$ (inactive) or $v^b \geq 0$ (active) by adding a bound. This branches the search tree.

ReluSuccess — if all variables are within bounds AND all ReLU constraints are satisfied, output SAT.

The strategy: try Update first, split only as a last resort. In practice, most ReLUs can be resolved by a few update-pivot cycles without ever splitting.


6. The Search Tree: When Laziness Isn’t Enough

Sometimes Update$_b$ and Update$_f$ keep fixing one ReLU only to break another. The solver oscillates. When this happens beyond a threshold, Reluplex applies ReluSplit: pick a ReLU with $l(v^b) < 0 < u(v^b)$ and branch:

  • Left branch: set $u(v^b) := 0$ (force inactive)
  • Right branch: set $l(v^b) := 0$ (force active)

Each branch is now a simpler subproblem (one fewer ambiguous ReLU). The solver explores them like a SAT solver explores a search tree, with backtracking.


7. Why It Works: Practical Observations

On the ACAS Xu networks (45 networks, 8 layers, 300 ReLUs each), Katz et al. observed:

Most ReLUs resolve without splitting. During the search, many ReLUs become fixed — their bounds narrow until they’re provably active or provably inactive. The solver derives tighter bounds by propagating constraints through the tableau.

Bound tightening is critical. Before attempting to fix a ReLU violation, the solver can derive tighter bounds on $v^b$ by analyzing the tableau. If the derived bounds show $l(v^b) \geq 0$, the ReLU is provably active — no split needed. If $u(v^b) \leq 0$, it’s provably inactive.

Conflict analysis helps. When a branch leads to UNSAT, the solver performs conflict analysis (like modern SAT solvers) to learn which variable assignments caused the contradiction, and prunes other branches that would lead to the same conflict.

The result: networks with 300 ReLUs were verified in minutes to hours, when the naive approach would take longer than the age of the universe.


8. Formal Correctness

Reluplex is sound: if it returns SAT with assignment $\alpha$, then $\alpha$ satisfies all linear constraints and all ReLU constraints. If it returns UNSAT, no such assignment exists.

Reluplex is complete: for any conjunction of linear atoms and ReLU constraints, the algorithm will terminate with either SAT or UNSAT (given the splitting strategy that forces termination after a bounded number of update attempts per ReLU).

The proof follows the structure of SMT soundness proofs: the splitting-on-demand framework guarantees that derivation trees are finite and exhaustive.


9. From Reluplex to Marabou (and Beyond)

Reluplex was the proof of concept. Its successor, Marabou (Katz et al., 2019), adds:

  • Support for more activation functions beyond ReLU (sigmoid, max-pool)
  • Divide-and-conquer parallelization of the search tree
  • Tighter bound propagation using linear relaxations
  • Integration with the annual VNN-COMP verification competition

The field has since exploded. Methods like CROWN, $\alpha$-CROWN, $\beta$-CROWN use linear relaxations for faster incomplete verification, and IBP (which we covered in the previous post) trades exactness for GPU-speed scalable certification.

But they all stand on the foundation Reluplex laid: the insight that ReLU constraints can be handled lazily within an extended simplex framework, making neural network verification practical for the first time.


References

  1. G. Katz, C. Barrett, D. Dill, K. Julian, M. Kochenderfer. “Reluplex: An Efficient SMT Solver for Verifying Deep Neural Networks.” CAV 2017. arXiv:1702.01135

  2. G. Katz et al. “The Marabou Framework for Verification and Analysis of Deep Neural Networks.” CAV 2019. GitHub

  3. S. Gowal et al. “On the Effectiveness of Interval Bound Propagation for Training Verifiably Robust Models.” 2018. arXiv:1810.12715