A counterexample to Goemans' cost conjecture #
Jason Hickey directed Claude's formal verification of Dmitry Rybin's counterexample,
discovered with GPT-5.6 Pro. Upstream also acknowledges Katherine Schlitz.
Adapted from jyh/dinitz-verify, commit ffba3523f0edd14be3460d039f22a6b98c02fd9e.
The splittable flow costs 58; every unsplittable routing satisfying the additive maximum-demand capacity bound costs at least 60, and this lower bound is attained. Generic coefficient transfer gives refutations over all linearly ordered commutative rings.
1. The counterexample instance #
Equations
- GoemansFlow.instReprVertex.repr GoemansFlow.Vertex.s prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Vertex.s")).group prec✝
- GoemansFlow.instReprVertex.repr GoemansFlow.Vertex.u prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Vertex.u")).group prec✝
- GoemansFlow.instReprVertex.repr GoemansFlow.Vertex.v prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Vertex.v")).group prec✝
- GoemansFlow.instReprVertex.repr GoemansFlow.Vertex.w prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Vertex.w")).group prec✝
- GoemansFlow.instReprVertex.repr GoemansFlow.Vertex.t1 prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Vertex.t1")).group prec✝
- GoemansFlow.instReprVertex.repr GoemansFlow.Vertex.t2 prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Vertex.t2")).group prec✝
- GoemansFlow.instReprVertex.repr GoemansFlow.Vertex.t3 prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Vertex.t3")).group prec✝
Instances For
Equations
- GoemansFlow.instReprVertex = { reprPrec := GoemansFlow.instReprVertex.repr }
Equations
- One or more equations did not get rendered due to their size.
Equations
- GoemansFlow.instReprArc = { reprPrec := GoemansFlow.instReprArc.repr }
Equations
- GoemansFlow.instReprArc.repr GoemansFlow.Arc.st1 prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Arc.st1")).group prec✝
- GoemansFlow.instReprArc.repr GoemansFlow.Arc.st2 prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Arc.st2")).group prec✝
- GoemansFlow.instReprArc.repr GoemansFlow.Arc.su prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Arc.su")).group prec✝
- GoemansFlow.instReprArc.repr GoemansFlow.Arc.ut3 prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Arc.ut3")).group prec✝
- GoemansFlow.instReprArc.repr GoemansFlow.Arc.uv prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Arc.uv")).group prec✝
- GoemansFlow.instReprArc.repr GoemansFlow.Arc.vt1 prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Arc.vt1")).group prec✝
- GoemansFlow.instReprArc.repr GoemansFlow.Arc.vw prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Arc.vw")).group prec✝
- GoemansFlow.instReprArc.repr GoemansFlow.Arc.wt2 prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Arc.wt2")).group prec✝
- GoemansFlow.instReprArc.repr GoemansFlow.Arc.wt3 prec✝ = Repr.addAppParen (Std.Format.nest (if prec✝ ≥ 1024 then 1 else 2) (Std.Format.text "GoemansFlow.Arc.wt3")).group prec✝
Instances For
Equations
- One or more equations did not get rendered due to their size.
Tail vertex of each arc in the counterexample.
Equations
- GoemansFlow.tail GoemansFlow.Arc.st1 = GoemansFlow.Vertex.s
- GoemansFlow.tail GoemansFlow.Arc.st2 = GoemansFlow.Vertex.s
- GoemansFlow.tail GoemansFlow.Arc.su = GoemansFlow.Vertex.s
- GoemansFlow.tail GoemansFlow.Arc.ut3 = GoemansFlow.Vertex.u
- GoemansFlow.tail GoemansFlow.Arc.uv = GoemansFlow.Vertex.u
- GoemansFlow.tail GoemansFlow.Arc.vt1 = GoemansFlow.Vertex.v
- GoemansFlow.tail GoemansFlow.Arc.vw = GoemansFlow.Vertex.v
- GoemansFlow.tail GoemansFlow.Arc.wt2 = GoemansFlow.Vertex.w
- GoemansFlow.tail GoemansFlow.Arc.wt3 = GoemansFlow.Vertex.w
Instances For
Head vertex of each arc in the counterexample.
Equations
- GoemansFlow.head GoemansFlow.Arc.st1 = GoemansFlow.Vertex.t1
- GoemansFlow.head GoemansFlow.Arc.st2 = GoemansFlow.Vertex.t2
- GoemansFlow.head GoemansFlow.Arc.su = GoemansFlow.Vertex.u
- GoemansFlow.head GoemansFlow.Arc.ut3 = GoemansFlow.Vertex.t3
- GoemansFlow.head GoemansFlow.Arc.uv = GoemansFlow.Vertex.v
- GoemansFlow.head GoemansFlow.Arc.vt1 = GoemansFlow.Vertex.t1
- GoemansFlow.head GoemansFlow.Arc.vw = GoemansFlow.Vertex.w
- GoemansFlow.head GoemansFlow.Arc.wt2 = GoemansFlow.Vertex.t2
- GoemansFlow.head GoemansFlow.Arc.wt3 = GoemansFlow.Vertex.t3
Instances For
The fractional (splittable) flow x.
Equations
- GoemansFlow.fractionalFlow GoemansFlow.Arc.st1 = 10
- GoemansFlow.fractionalFlow GoemansFlow.Arc.st2 = 6
- GoemansFlow.fractionalFlow GoemansFlow.Arc.su = 24
- GoemansFlow.fractionalFlow GoemansFlow.Arc.ut3 = 10
- GoemansFlow.fractionalFlow GoemansFlow.Arc.uv = 14
- GoemansFlow.fractionalFlow GoemansFlow.Arc.vt1 = 5
- GoemansFlow.fractionalFlow GoemansFlow.Arc.vw = 9
- GoemansFlow.fractionalFlow GoemansFlow.Arc.wt2 = 4
- GoemansFlow.fractionalFlow GoemansFlow.Arc.wt3 = 5
Instances For
The cost vector c.
Equations
- GoemansFlow.arcCost GoemansFlow.Arc.st1 = 2
- GoemansFlow.arcCost GoemansFlow.Arc.st2 = 3
- GoemansFlow.arcCost GoemansFlow.Arc.su = 0
- GoemansFlow.arcCost GoemansFlow.Arc.ut3 = 2
- GoemansFlow.arcCost GoemansFlow.Arc.uv = 0
- GoemansFlow.arcCost GoemansFlow.Arc.vt1 = 0
- GoemansFlow.arcCost GoemansFlow.Arc.vw = 0
- GoemansFlow.arcCost GoemansFlow.Arc.wt2 = 0
- GoemansFlow.arcCost GoemansFlow.Arc.wt3 = 0
Instances For
Terminal of commodity i.
Equations
Instances For
d_max, the largest demand.
Equations
Instances For
The instance is a simple digraph: no two arcs share both endpoints.
Flow conservation at every vertex other than the source: inflow − outflow = demand
absorbed there (which is 0 at non-terminals).
2. Loads and costs #
A routing: one walk from s to t_i per commodity i.
Equations
- GoemansFlow.IsRouting p = ∀ (i : Fin 3), GoemansFlow.IsWalk GoemansFlow.tail GoemansFlow.head GoemansFlow.Vertex.s (p i) (GoemansFlow.terminal i)
Instances For
Capacity-good: every arc load stays within x(a) + d_max.
Equations
Instances For
Cost of a routing.
Equations
Instances For
The cost of the fractional flow.
3. Path completeness: the digraph has exactly six s-t_i walks #
All nine arcs, in the order used for walk enumeration.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Arcs leaving x.
Equations
- GoemansFlow.outOf x = List.filter (fun (e : GoemansFlow.Arc) => decide (GoemansFlow.tail e = x)) GoemansFlow.allArcs
Instances For
A topological rank certifying acyclicity.
Equations
Instances For
The explicit enumeration of all walks of length ≤ 4 out of the source.
The two s-t1 paths.
Instances For
The zero-cost path to the first terminal.
Equations
Instances For
The two s-t2 paths.
Instances For
The zero-cost path to the second terminal.
Equations
Instances For
The two s-t3 paths.
Instances For
The zero-cost path to the third terminal.
Equations
Instances For
The positive-cost path for commodity i.
Equations
Instances For
The zero-cost path for commodity i.
Equations
Instances For
Path completeness. For each commodity i, the arc-lists forming a walk from the
source s to the terminal t_i are exactly the two listed paths. This is derived from
the arc list — via the enumeration walksFrom together with the topological rank bounding
every walk by 4 arcs — and not assumed.
Conversely, all six really are walks.
The vertex sequence visited by a walk.
Equations
Instances For
Each of the six s-t_i walks is a simple path (no repeated vertex), so restricting Conjecture 1.3 to simple paths would not help.
4. Layer A: the eight-case check and the cost lower bound #
The load written as a function of the three chosen paths.
Equations
- GoemansFlow.loadThree q0 q1 q2 a = List.count a q0 • GoemansFlow.demand 0 + List.count a q1 • GoemansFlow.demand 1 + List.count a q2 • GoemansFlow.demand 2
Instances For
Routing cost expressed in terms of the three chosen paths.
Equations
- GoemansFlow.routingCostThree q0 q1 q2 = ∑ a : GoemansFlow.Arc, GoemansFlow.arcCost a * GoemansFlow.loadThree q0 q1 q2 a
Instances For
The eight-case kernel check. Over the eight combinations of path choices, every capacity-good one costs at least 60.
Layer A (main). Every unsplittable routing of the three demands along arbitrary
walks out of s whose arc loads stay within x(a) + d_max costs at least 60 — strictly
more than the fractional cost 58.
Non-vacuity and tightness #
Route every commodity on its "expensive" path.
Instances For
Positive control. The instance does satisfy the conclusion of DGG Theorem 1.2
(the capacity clause (i) on its own): an unsplittable routing with
flow_P(a) ≤ x(a) + d_max for every arc a exists. So the refutation isolates
clause (ii), the cost clause — it is not an artifact of an unsatisfiable capacity
requirement.
Route every commodity on its zero-cost path.
Instances For
Positive control for the other clause. Clause (ii) of Conjecture 1.3 -- the cost
clause -- is also satisfiable on its own here: the all-Z routing costs 0 ≤ 58 = c^T x.
So neither clause is individually unsatisfiable at this instance; only their conjunction
fails, which is what makes the instance a counterexample to Conjecture 1.3 rather than to
either half of it.
No conflict with the primary source's planar theorems. Planarity is not formalized here.
The instance satisfies the numerical conclusion of the planar result in
arXiv:2308.02651. Theorem 1.8 of that paper grants a two-sided violation of 2·d_max
together with the cost bound, and its conclusion is satisfied here: the all-Z routing
keeps every arc load within 2·d_max = 30 of x on both sides and costs 0 ≤ 58. The
counterexample therefore refutes the d_max grade only, exactly as Conjecture 1.3 states
it.
60 is exactly the optimum: it is a lower bound and it is attained.
5. Layer B: the conjecture, and its refutation #
Goemans' cost conjecture (Dinitz–Garg–Goemans / SSUF), Conjecture 1.3 of
arXiv:2308.02651, stated over a linearly ordered commutative ring R.
Read: for every finite digraph (W, E) with arc endpoints tail, head, every source
src, every finite family of commodities K with distinct terminals term k ≠ src and
positive demands d k, every dmax equal to the maximum demand, every nonnegative cost
vector c and every nonnegative feasible single-source flow x routing the demands,
there is an unsplittable routing P (one walk per commodity) with
flow_P(a) ≤ x(a) + dmaxfor every arca, andc^T flow_P ≤ c^T x.
This form ranges over arbitrary directed graphs and omits capacities. The refutation
of GoemansCostConjectureFull also supplies a simple, loopless, acyclic instance with
explicit capacities, avoiding dependence on these differences from the source.
Equations
- One or more equations did not get rendered due to their size.
Instances For
The Full form is the weaker Prop. It is GoemansCostConjecture with four hypotheses
added (simple, loopless, acyclic, x ≤ u), so the bare conjecture implies it. Hence
¬ GoemansCostConjectureFull is the stronger statement, and it implies
¬ GoemansCostConjecture.
If the conjecture held over R, it would hold over ℤ (an integral instance is an
R-instance, and the conclusion pulls back along the order embedding ℤ ↪ R).
The same transfer for the literature-faithful form: if the Full conjecture held over
R, it would hold over ℤ. The four extra hypotheses (simple, loopless, acyclic,
x ≤ u) transfer verbatim -- the first three do not mention the ring at all, and x ≤ u
pushes forward along the order embedding ℤ ↪ R.
Layer B (main), literature-faithful form, over ℤ. The counterexample instance
discharges every hypothesis of GoemansCostConjectureFull: it is simple (arcs_simple),
loopless (no_self_loops), acyclic (⟨rank, rank_arc⟩), and takes u := x (the worst
case the primary source identifies), so x ≤ u holds by reflexivity.
Layer B (main), literature-faithful form, general coefficient ring. Goemans' cost conjecture -- capacities restored, digraph simple, loopless and acyclic -- is false over every linearly ordered commutative ring.
The literature-faithful form over ℚ, the setting of Conjecture 1.3.
THE HEADLINE. Goemans' cost conjecture for single-source unsplittable flow
(Conjecture 1.3 of arXiv:2308.02651, the cost version of the Dinitz–Garg–Goemans theorem)
is false over ℚ, in the form that keeps every piece of the literature's data: arc
capacities u with x ≤ u, and a simple, loopless, acyclic digraph.
dgg_cost_conjecture_false below is the same refutation for the bare form
GoemansCostConjecture and is kept as the searchable alias.
The headline over the reals.
Layer B, bare form. Goemans' cost conjecture is false over ℤ.
Layer B, bare form, general coefficient ring. Goemans' cost conjecture is false
over every linearly ordered commutative ring — in particular over ℚ, the setting of
Conjecture 1.3 of arXiv:2308.02651, and over ℝ.
The bare form over ℚ; the searchable alias of the headline
goemans_cost_conjecture_false. (It also follows from the headline without re-running the
instance, via GoemansCostConjectureFull_of_GoemansCostConjecture — see
dgg_cost_conjecture_false_of_headline — since the Full form is the weaker Prop.)
The same over the reals.
The headline implies the bare-form refutation, with no second appeal to the instance: the Full form is the weaker Prop, so refuting it refutes the bare one.