Skip to content

Commit 43f37f8

Browse files
zazabapGiggleLiuisPANNclaude
authored
Fix #230: Add BiconnectivityAugmentation model (#640)
* Add plan for #230: BiconnectivityAugmentation model * Implement #230: Add BiconnectivityAugmentation model * Refine #230: add canonical example coverage * Fix review feedback for #230 * chore: remove plan file after implementation --------- Co-authored-by: GiggleLiu <cacate0129@gmail.com> Co-authored-by: Xiwei Pan <xiwei.pan@connect.hkust-gz.edu.cn> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent dfcc313 commit 43f37f8

12 files changed

Lines changed: 1052 additions & 33 deletions

File tree

docs/paper/reductions.typ

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"MinimumVertexCover": [Minimum Vertex Cover],
6767
"MaxCut": [Max-Cut],
6868
"GraphPartitioning": [Graph Partitioning],
69+
"BiconnectivityAugmentation": [Biconnectivity Augmentation],
6970
"HamiltonianPath": [Hamiltonian Path],
7071
"UndirectedTwoCommodityIntegralFlow": [Undirected Two-Commodity Integral Flow],
7172
"LengthBoundedDisjointPaths": [Length-Bounded Disjoint Paths],
@@ -537,6 +538,52 @@ Graph Partitioning is a core NP-hard problem arising in VLSI design, parallel co
537538
caption: [Graph with $n = 6$ vertices partitioned into $A = {v_0, v_1, v_2}$ (blue) and $B = {v_3, v_4, v_5}$ (red). The 3 crossing edges $(v_1, v_3)$, $(v_2, v_3)$, $(v_2, v_4)$ are shown in bold red; internal edges are gray.],
538539
) <fig:graph-partitioning>
539540
]
541+
#problem-def("BiconnectivityAugmentation")[
542+
Given an undirected graph $G = (V, E)$, a set $F$ of candidate edges on $V$ with $F inter E = emptyset$, weights $w: F -> RR$, and a budget $B in RR$, find $F' subset.eq F$ such that $sum_(e in F') w(e) <= B$ and the augmented graph $G' = (V, E union F')$ is biconnected, meaning $G'$ is connected and deleting any single vertex leaves it connected.
543+
][
544+
Biconnectivity augmentation is a classical network-design problem: add backup links so the graph survives any single vertex failure. The weighted candidate-edge formulation modeled here captures communication, transportation, and infrastructure planning settings where only a prescribed set of new links is feasible and each carries a cost. In this library, the exact baseline is brute-force enumeration over the $m = |F|$ candidate edges, yielding $O^*(2^m)$ time and matching the exported complexity metadata for the model.
545+
546+
*Example.* Consider the path graph $v_0 - v_1 - v_2 - v_3 - v_4 - v_5$ with candidate edges $(v_0, v_2)$, $(v_0, v_3)$, $(v_0, v_4)$, $(v_1, v_3)$, $(v_1, v_4)$, $(v_1, v_5)$, $(v_2, v_4)$, $(v_2, v_5)$, $(v_3, v_5)$ carrying weights $(1, 2, 3, 1, 2, 3, 1, 2, 1)$ and budget $B = 4$. Selecting $F' = {(v_0, v_2), (v_1, v_3), (v_2, v_4), (v_3, v_5)}$ uses total weight $1 + 1 + 1 + 1 = 4$ and eliminates every articulation point: after deleting any single vertex, the remaining graph is still connected. Reducing the budget to $B = 3$ makes the instance infeasible, because one of the path endpoints remains attached through a single articulation vertex.
547+
548+
#figure(
549+
canvas(length: 1cm, {
550+
import draw: *
551+
// 6 vertices in a horizontal line
552+
let verts = range(6).map(k => (k * 1.5, 0))
553+
let path-edges = ((0,1),(1,2),(2,3),(3,4),(4,5))
554+
// Candidate edges: (u, v, weight, selected?)
555+
let candidates = (
556+
(0, 2, 1, true), (0, 3, 2, false), (0, 4, 3, false),
557+
(1, 3, 1, true), (1, 4, 2, false), (1, 5, 3, false),
558+
(2, 4, 1, true), (2, 5, 2, false), (3, 5, 1, true),
559+
)
560+
let blue = graph-colors.at(0)
561+
let green = graph-colors.at(2)
562+
let gray = luma(180)
563+
// Draw path edges (existing graph)
564+
for (u, v) in path-edges {
565+
g-edge(verts.at(u), verts.at(v), stroke: 2pt + black)
566+
}
567+
// Draw candidate edges as arcs above the path
568+
for (u, v, w, sel) in candidates {
569+
let mid-x = (verts.at(u).at(0) + verts.at(v).at(0)) / 2
570+
let span = v - u
571+
let height = span * 0.4
572+
let ctrl = (mid-x, height)
573+
bezier(verts.at(u), verts.at(v), ctrl,
574+
stroke: if sel { 2.5pt + green } else { (dash: "dashed", paint: gray, thickness: 0.8pt) })
575+
// Weight label
576+
content((mid-x, height + 0.25),
577+
text(7pt, fill: if sel { green.darken(30%) } else { gray })[#w])
578+
}
579+
// Draw nodes
580+
for (k, pos) in verts.enumerate() {
581+
g-node(pos, name: "v" + str(k), label: [$v_#k$])
582+
}
583+
}),
584+
caption: [Biconnectivity Augmentation on a 6-vertex path with $B = 4$. Existing edges are black; green arcs show the selected augmentation $F'$ (total weight 4); dashed gray arcs are unselected candidates. The resulting graph $G' = (V, E union F')$ is biconnected.],
585+
) <fig:biconnectivity-augmentation>
586+
]
540587

541588
#problem-def("BoundedComponentSpanningForest")[
542589
Given an undirected graph $G = (V, E)$ with vertex weights $w: V -> ZZ_(gt.eq 0)$, a positive integer $K <= |V|$, and a positive bound $B$, determine whether there exists a partition of $V$ into $t$ non-empty sets $V_1, dots, V_t$ with $1 <= t <= K$ such that each induced subgraph $G[V_i]$ is connected and each part satisfies $sum_(v in V_i) w(v) <= B$.

problemreductions-cli/src/cli.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ Flags by problem type:
236236
X3C (ExactCoverBy3Sets) --universe, --sets (3 elements each)
237237
SetBasis --universe, --sets, --k
238238
BicliqueCover --left, --right, --biedges, --k
239+
BiconnectivityAugmentation --graph, --potential-edges, --budget [--num-vertices]
239240
BMF --matrix (0/1), --rank
240241
SteinerTree --graph, --edge-weights, --terminals
241242
CVP --basis, --target-vec [--bounds]
@@ -271,6 +272,7 @@ Examples:
271272
pred create MIS/KingsSubgraph --positions \"0,0;1,0;1,1;0,1\"
272273
pred create MIS/UnitDiskGraph --positions \"0,0;1,0;0.5,0.8\" --radius 1.5
273274
pred create MIS --random --num-vertices 10 --edge-prob 0.3
275+
pred create BiconnectivityAugmentation --graph 0-1,1-2,2-3 --potential-edges 0-2:3,0-3:4,1-3:2 --budget 5
274276
pred create FVS --arcs \"0>1,1>2,2>0\" --weights 1,1,1
275277
pred create UndirectedTwoCommodityIntegralFlow --graph 0-2,1-2,2-3 --capacities 1,1,2 --source-1 0 --sink-1 3 --source-2 1 --sink-2 3 --requirement-1 1 --requirement-2 1
276278
pred create X3C --universe 9 --sets \"0,1,2;0,2,4;3,4,5;3,5,7;6,7,8;1,4,6;2,5,8\"
@@ -438,6 +440,12 @@ pub struct CreateArgs {
438440
/// Directed arcs for directed graph problems (e.g., 0>1,1>2,2>0)
439441
#[arg(long)]
440442
pub arcs: Option<String>,
443+
/// Weighted potential augmentation edges (e.g., 0-2:3,1-3:5)
444+
#[arg(long)]
445+
pub potential_edges: Option<String>,
446+
/// Total budget for selected potential edges
447+
#[arg(long)]
448+
pub budget: Option<String>,
441449
/// Deadlines for MinimumTardinessSequencing (comma-separated, e.g., "5,5,5,3,3")
442450
#[arg(long)]
443451
pub deadlines: Option<String>,
@@ -573,3 +581,46 @@ pub fn print_subcommand_help_hint(error_msg: &str) {
573581
}
574582
}
575583
}
584+
585+
#[cfg(test)]
586+
mod tests {
587+
use super::*;
588+
589+
#[test]
590+
fn test_create_parses_biconnectivity_augmentation_flags() {
591+
let cli = Cli::parse_from([
592+
"pred",
593+
"create",
594+
"BiconnectivityAugmentation",
595+
"--graph",
596+
"0-1,1-2",
597+
"--potential-edges",
598+
"0-2:3,1-3:5",
599+
"--budget",
600+
"7",
601+
]);
602+
603+
let Commands::Create(args) = cli.command else {
604+
panic!("expected create command");
605+
};
606+
607+
assert_eq!(args.problem, "BiconnectivityAugmentation");
608+
assert_eq!(args.graph.as_deref(), Some("0-1,1-2"));
609+
assert_eq!(args.potential_edges.as_deref(), Some("0-2:3,1-3:5"));
610+
assert_eq!(args.budget.as_deref(), Some("7"));
611+
}
612+
613+
#[test]
614+
fn test_create_help_mentions_biconnectivity_augmentation_flags() {
615+
let cmd = Cli::command();
616+
let create = cmd.find_subcommand("create").expect("create subcommand");
617+
let help = create
618+
.get_after_help()
619+
.expect("create after_help")
620+
.to_string();
621+
622+
assert!(help.contains("BiconnectivityAugmentation"));
623+
assert!(help.contains("--potential-edges"));
624+
assert!(help.contains("--budget"));
625+
}
626+
}

0 commit comments

Comments
 (0)