Skip to content

Commit 302d54d

Browse files
GiggleLiuisPANNclaude
authored
Fix #239: [Model] BalancedCompleteBipartiteSubgraph (#653)
* Add plan for #239: [Model] BalancedCompleteBipartiteSubgraph * Implement #239: [Model] BalancedCompleteBipartiteSubgraph * Fix review findings for #239 * chore: remove plan file after implementation * fix review feedback for balanced biclique model * Fix duplicate tests module in create.rs after merge Merge the PR's BalancedCompleteBipartiteSubgraph CLI tests into the existing tests module using empty_args() helper to avoid missing fields. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.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 369c489 commit 302d54d

13 files changed

Lines changed: 3125 additions & 33 deletions

File tree

docs/paper/reductions.typ

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"BMF": [Boolean Matrix Factorization],
9494
"PaintShop": [Paint Shop],
9595
"BicliqueCover": [Biclique Cover],
96+
"BalancedCompleteBipartiteSubgraph": [Balanced Complete Bipartite Subgraph],
9697
"BoundedComponentSpanningForest": [Bounded Component Spanning Forest],
9798
"BinPacking": [Bin Packing],
9899
"ClosestVectorProblem": [Closest Vector Problem],
@@ -1926,6 +1927,72 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS
19261927
]
19271928
}
19281929

1930+
#{
1931+
let x = load-model-example("BalancedCompleteBipartiteSubgraph")
1932+
let left-size = x.instance.graph.left_size
1933+
let right-size = x.instance.graph.right_size
1934+
let k = x.instance.k
1935+
let bip-edges = x.instance.graph.edges
1936+
let sol = x.optimal.at(0)
1937+
let left-selected = range(left-size).filter(i => sol.config.at(i) == 1)
1938+
let right-selected = range(right-size).filter(i => sol.config.at(left-size + i) == 1)
1939+
let selected-edges = bip-edges.filter(e =>
1940+
left-selected.contains(e.at(0)) and right-selected.contains(e.at(1))
1941+
)
1942+
[
1943+
#problem-def("BalancedCompleteBipartiteSubgraph")[
1944+
Given a bipartite graph $G = (A, B, E)$ and an integer $k$, determine whether there exist subsets $A' subset.eq A$ and $B' subset.eq B$ such that $|A'| = |B'| = k$ and every cross pair is present:
1945+
$A' times B' subset.eq E.$
1946+
][
1947+
Balanced Complete Bipartite Subgraph is a classical NP-complete bipartite containment problem from Garey and Johnson @garey1979. Unlike Biclique Cover, which asks for a collection of bicliques covering all edges, this problem asks for a _single_ balanced biclique of prescribed size. It arises naturally in biclustering, dense submatrix discovery, and pattern mining on bipartite data. Chen et al. give an exact $O^*(1.3803^n)$ algorithm for dense bipartite graphs, and the registry records that best-known bound in the catalog metadata. A straightforward baseline still enumerates all $k$-subsets of $A$ and $B$ and checks whether they induce a complete bipartite graph, taking $O(binom(|A|, k) dot binom(|B|, k) dot k^2) = O^*(2^(|A| + |B|))$ time.
1948+
1949+
*Example.* Consider the bipartite graph with $A = {ell_1, ell_2, ell_3, ell_4}$, $B = {r_1, r_2, r_3, r_4}$, and edges $E = {#bip-edges.map(e => $(ell_#(e.at(0) + 1), r_#(e.at(1) + 1))$).join(", ")}$. For $k = #k$, the selected sets $A' = {#left-selected.map(i => $ell_#(i + 1)$).join(", ")}$ and $B' = {#right-selected.map(i => $r_#(i + 1)$).join(", ")}$ form a balanced complete bipartite subgraph: all #selected-edges.len() required cross edges are present. Vertex $ell_4$ is excluded because $(ell_4, r_3) in.not E$, so any witness using $ell_4$ cannot realize $K_(#k,#k)$.
1950+
1951+
#figure(
1952+
canvas(length: 1cm, {
1953+
let lpos = range(left-size).map(i => (0, left-size - 1 - i))
1954+
let rpos = range(right-size).map(i => (2.6, right-size - 1 - i))
1955+
for (li, rj) in bip-edges {
1956+
let selected = selected-edges.any(e => e.at(0) == li and e.at(1) == rj)
1957+
g-edge(
1958+
lpos.at(li),
1959+
rpos.at(rj),
1960+
stroke: if selected { 2pt + graph-colors.at(0) } else { 1pt + luma(180) },
1961+
)
1962+
}
1963+
for (idx, pos) in lpos.enumerate() {
1964+
let selected = left-selected.contains(idx)
1965+
g-node(
1966+
pos,
1967+
name: "bcbs-l" + str(idx),
1968+
fill: if selected { graph-colors.at(0) } else { luma(240) },
1969+
label: if selected {
1970+
text(fill: white)[$ell_#(idx + 1)$]
1971+
} else {
1972+
[$ell_#(idx + 1)$]
1973+
},
1974+
)
1975+
}
1976+
for (idx, pos) in rpos.enumerate() {
1977+
let selected = right-selected.contains(idx)
1978+
g-node(
1979+
pos,
1980+
name: "bcbs-r" + str(idx),
1981+
fill: if selected { graph-colors.at(0) } else { luma(240) },
1982+
label: if selected {
1983+
text(fill: white)[$r_#(idx + 1)$]
1984+
} else {
1985+
[$r_#(idx + 1)$]
1986+
},
1987+
)
1988+
}
1989+
}),
1990+
caption: [Balanced complete bipartite subgraph with $k = #k$: the selected vertices $A' = {#left-selected.map(i => $ell_#(i + 1)$).join(", ")}$ and $B' = {#right-selected.map(i => $r_#(i + 1)$).join(", ")}$ are blue, and the 9 edges of the induced $K_(#k,#k)$ are highlighted. The missing edge $(ell_4, r_3)$ prevents including $ell_4$.],
1991+
) <fig:balanced-complete-bipartite-subgraph>
1992+
]
1993+
]
1994+
}
1995+
19291996
#{
19301997
let x = load-model-example("PartitionIntoTriangles")
19311998
let nv = graph-num-vertices(x.instance)

0 commit comments

Comments
 (0)