You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Add plan for #294: [Model] UndirectedFlowLowerBounds
* Implement #294: [Model] UndirectedFlowLowerBounds
* chore: remove plan file after implementation
* Merge origin/main and fix formatting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix source==sink false positive and restore capacity overflow validation
- Add assert!(source != sink) to UndirectedFlowLowerBounds constructor
to prevent the circulation demand edge from becoming a self-loop
- Restore capacity domain-size check in UndirectedTwoCommodityIntegralFlow
create branch, which was removed when parse_capacities was generalized
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix duplicate test from merge conflict resolution
Restore test_create_longest_path_requires_edge_lengths with its
correct name — the merge conflict subagent had renamed it, creating
a duplicate of test_create_undirected_flow_lower_bounds_requires_lower_bounds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@@ -1134,6 +1135,68 @@ is feasible: each set induces a connected subgraph, the component weights are $2
1134
1135
]
1135
1136
]
1136
1137
}
1138
+
#{
1139
+
let x = load-model-example("UndirectedFlowLowerBounds")
1140
+
let s = x.instance.source
1141
+
let t = x.instance.sink
1142
+
let R = x.instance.requirement
1143
+
let orientation = x.optimal_config
1144
+
let edges = x.instance.graph.edges
1145
+
let lower = x.instance.lower_bounds
1146
+
let caps = x.instance.capacities
1147
+
let witness = (2, 1, 1, 1, 1, 2, 1)
1148
+
[
1149
+
#problem-def("UndirectedFlowLowerBounds")[
1150
+
Given an undirected graph $G = (V, E)$, specified vertices $s, t in V$, lower bounds $l: E -> ZZ_(>= 0)$, upper capacities $c: E -> ZZ^+$ with $l(e) <= c(e)$ for every edge, and a requirement $R in ZZ^+$, determine whether there exists a flow function $f: {(u, v), (v, u): {u, v} in E} -> ZZ_(>= 0)$ such that each edge carries flow in at most one direction, every edge value lies between its lower and upper bound, flow is conserved at every vertex in $V backslash {s, t}$, and the net flow into $t$ is at least $R$.
1151
+
][
1152
+
Undirected Flow with Lower Bounds appears as ND37 in Garey and Johnson's catalog @garey1979. Itai proved that even this single-commodity undirected feasibility problem is NP-complete, contrasting sharply with the directed lower-bounded case, which reduces to ordinary max-flow machinery @itai1978.
1153
+
1154
+
The implementation exposes one binary decision per edge rather than raw flow magnitudes. The configuration $(#orientation.map(str).join(", "))$ means "orient every edge exactly as listed in the stored edge order"; once an orientation is fixed, `evaluate()` checks the remaining lower-bounded directed circulation conditions internally. This keeps the explicit search space at $2^m$ for $m = |E|$, matching the registry complexity bound.
1155
+
1156
+
*Example.* The canonical fixture uses source $s = v_#s$, sink $t = v_#t$, requirement $R = #R$, edges ${#edges.map(((u, v)) => $(v_#u, v_#v)$).join(", ")}$, and lower/upper pairs ${#range(edges.len()).map(i => $(#lower.at(i), #caps.at(i))$).join(", ")}$ in that order. Under the all-zero orientation config, a feasible witness sends flows $(#witness.map(str).join(", "))$ along those edges respectively: $2$ on $(v_0, v_1)$, $1$ on $(v_0, v_2)$, $1$ on $(v_1, v_3)$, $1$ on $(v_2, v_3)$, $1$ on $(v_1, v_4)$, $2$ on $(v_3, v_5)$, and $1$ on $(v_4, v_5)$. Every lower bound is satisfied, each nonterminal vertex has equal inflow and outflow, and the sink receives $2 + 1 = 3 >= R$, so the instance evaluates to true. A separate rule issue tracks the natural reduction to ILP; this model PR only documents the standalone verifier.
caption: [Canonical YES instance for Undirected Flow with Lower Bounds. Blue edges follow the all-zero orientation config, and edge labels show one feasible witness flow.],
1196
+
) <fig:undirected-flow-lower-bounds>
1197
+
]
1198
+
]
1199
+
}
1137
1200
#{
1138
1201
let x = load-model-example("UndirectedTwoCommodityIntegralFlow")
pred create BiconnectivityAugmentation --graph 0-1,1-2,2-3 --potential-edges 0-2:3,0-3:4,1-3:2 --budget 5
330
332
pred create FVS --arcs \"0>1,1>2,2>0\" --weights 1,1,1
@@ -363,6 +365,9 @@ pub struct CreateArgs {
363
365
/// Edge capacities for multicommodity flow problems (e.g., 1,1,2)
364
366
#[arg(long)]
365
367
pubcapacities:Option<String>,
368
+
/// Edge lower bounds for lower-bounded flow problems (e.g., 1,1,0,0,1,0,1)
369
+
#[arg(long)]
370
+
publower_bounds:Option<String>,
366
371
/// Bundle capacities for IntegralFlowBundles (e.g., 1,1,1)
367
372
#[arg(long)]
368
373
pubbundle_capacities:Option<String>,
@@ -375,7 +380,7 @@ pub struct CreateArgs {
375
380
/// Sink vertex for path-based graph problems and MinimumCutIntoBoundedSets
376
381
#[arg(long)]
377
382
pubsink:Option<usize>,
378
-
/// Required total flow R for IntegralFlowBundles, IntegralFlowHomologousArcs, IntegralFlowWithMultipliers, and PathConstrainedNetworkFlow
383
+
/// Required total flow R for IntegralFlowBundles, IntegralFlowHomologousArcs, IntegralFlowWithMultipliers, PathConstrainedNetworkFlow, and UndirectedFlowLowerBounds
379
384
#[arg(long)]
380
385
pubrequirement:Option<u64>,
381
386
/// Required number of paths for LengthBoundedDisjointPaths
0 commit comments