From 6b83ab75f32fc167062ae087c13d0e4a076cecb8 Mon Sep 17 00:00:00 2001
From: GiggleLiu <cacate0129@gmail.com>
Date: Thu, 12 Mar 2026 22:56:52 +0800
Subject: [PATCH 1/5] fix: address issue review comments for #126 and #117
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

PR #599 (KSat→SubsetSum): Fix imprecise Karp 1972 attribution — the
direct 3-SAT→SubsetSum digit encoding follows Sipser (2012, Thm 7.56)
and CLRS (2022, §34.5.5), not Karp's original reduction tree. Add bib
entries for both textbooks.

PR #570 (GraphPartitioning): Add proper @citations for Garey, Johnson
& Stockmeyer (1976) and Arora, Rao & Vazirani (2009) instead of
plain-text references. Add bib entries for both papers.

Regenerate problem_schemas.json and reduction_graph.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 docs/paper/reductions.typ                |   4 +-
 docs/paper/references.bib                |  38 +++++
 docs/src/reductions/problem_schemas.json |  11 ++
 docs/src/reductions/reduction_graph.json | 209 ++++++++++++-----------
 4 files changed, 160 insertions(+), 102 deletions(-)

diff --git a/docs/paper/reductions.typ b/docs/paper/reductions.typ
index b08ca70f0..747996668 100644
--- a/docs/paper/reductions.typ
+++ b/docs/paper/reductions.typ
@@ -385,7 +385,7 @@ caption: [The house graph with max cut $S = {v_0, v_3}$ (blue) vs $overline(S) =
   Given an undirected graph $G = (V, E)$ with $|V| = n$ (even), find a partition of $V$ into two disjoint sets $A$ and $B$ with $|A| = |B| = n slash 2$ that minimizes the number of edges crossing the partition:
   $ "cut"(A, B) = |{(u, v) in E : u in A, v in B}|. $
 ][
-Graph Partitioning is a core NP-hard problem arising in VLSI design, parallel computing, and scientific simulation, where balanced workload distribution with minimal communication is essential. Closely related to Max-Cut (which _maximizes_ rather than _minimizes_ the cut) and to the Ising Spin Glass model. NP-completeness was proved by Garey, Johnson and Stockmeyer (1976). Arora, Rao and Vazirani (2009) gave an $O(sqrt(log n))$-approximation algorithm. Standard partitioning tools include METIS, KaHIP, and Scotch.
+Graph Partitioning is a core NP-hard problem arising in VLSI design, parallel computing, and scientific simulation, where balanced workload distribution with minimal communication is essential. Closely related to Max-Cut (which _maximizes_ rather than _minimizes_ the cut) and to the Ising Spin Glass model. NP-completeness was proved by Garey, Johnson and Stockmeyer @garey1976. Arora, Rao and Vazirani @arora2009 gave an $O(sqrt(log n))$-approximation algorithm. Standard partitioning tools include METIS, KaHIP, and Scotch.
 
 *Example.* Consider the graph $G$ with $n = 6$ vertices and 9 edges: $(v_0, v_1)$, $(v_0, v_2)$, $(v_1, v_2)$, $(v_1, v_3)$, $(v_2, v_3)$, $(v_2, v_4)$, $(v_3, v_4)$, $(v_3, v_5)$, $(v_4, v_5)$. The optimal balanced partition is $A = {v_0, v_1, v_2}$, $B = {v_3, v_4, v_5}$, with cut value 3: the crossing edges are $(v_1, v_3)$, $(v_2, v_3)$, $(v_2, v_4)$. All other balanced partitions yield a cut of at least 3.
 
@@ -1198,7 +1198,7 @@ where $P$ is a penalty weight large enough that any constraint violation costs m
     Source config: #ksat_ss_sol.source_config #h(1em) Target config: #ksat_ss_sol.target_config
   ],
 )[
-  Classical Karp reduction @karp1972 using base-10 digit encoding. Each integer has $(n + m)$ digits, where the first $n$ positions correspond to variables and the last $m$ to clauses. For variable $x_i$, two integers $y_i, z_i$ encode positive and negative literal occurrences. For clause $C_j$, slack integers $g_j, h_j$ pad the clause digit to exactly 4. Since each clause has at most 3 literals and slacks add at most 2, no digit exceeds 5, so no carries occur.
+  Base-10 digit encoding reduction following Sipser @sipser2012[Thm 7.56] and CLRS @cormen2022[§34.5.5]. (Karp @karp1972 established SubsetSum NP-completeness via Exact Cover; this direct 3-SAT construction is a later textbook formulation.) Each integer has $(n + m)$ digits, where the first $n$ positions correspond to variables and the last $m$ to clauses. For variable $x_i$, two integers $y_i, z_i$ encode positive and negative literal occurrences. For clause $C_j$, slack integers $g_j, h_j$ pad the clause digit to exactly 4. Since each clause has at most 3 literals and slacks add at most 2, no digit exceeds 5, so no carries occur.
 ][
   _Construction._ Given a 3-CNF formula $phi$ with $n$ variables and $m$ clauses, create $2n + 2m$ integers in $(n+m)$-digit base-10 representation:
 
diff --git a/docs/paper/references.bib b/docs/paper/references.bib
index c3129a691..b69248331 100644
--- a/docs/paper/references.bib
+++ b/docs/paper/references.bib
@@ -387,3 +387,41 @@ @article{ibarra1975
   year    = {1975},
   doi     = {10.1145/321906.321909}
 }
+
+@book{sipser2012,
+  author    = {Michael Sipser},
+  title     = {Introduction to the Theory of Computation},
+  edition   = {3rd},
+  publisher = {Cengage Learning},
+  year      = {2012}
+}
+
+@book{cormen2022,
+  author    = {Thomas H. Cormen and Charles E. Leiserson and Ronald L. Rivest and Clifford Stein},
+  title     = {Introduction to Algorithms},
+  edition   = {4th},
+  publisher = {MIT Press},
+  year      = {2022}
+}
+
+@article{garey1976,
+  author  = {Michael R. Garey and David S. Johnson and Larry Stockmeyer},
+  title   = {Some Simplified NP-Complete Graph Problems},
+  journal = {Theoretical Computer Science},
+  volume  = {1},
+  number  = {3},
+  pages   = {237--267},
+  year    = {1976},
+  doi     = {10.1016/0304-3975(76)90059-1}
+}
+
+@article{arora2009,
+  author  = {Sanjeev Arora and Satish Rao and Umesh Vazirani},
+  title   = {Expander Flows, Geometric Embeddings and Graph Partitioning},
+  journal = {Journal of the ACM},
+  volume  = {56},
+  number  = {2},
+  pages   = {1--37},
+  year    = {2009},
+  doi     = {10.1145/1502793.1502794}
+}
diff --git a/docs/src/reductions/problem_schemas.json b/docs/src/reductions/problem_schemas.json
index ea93e5f67..4e60ebdcd 100644
--- a/docs/src/reductions/problem_schemas.json
+++ b/docs/src/reductions/problem_schemas.json
@@ -110,6 +110,17 @@
       }
     ]
   },
+  {
+    "name": "GraphPartitioning",
+    "description": "Find minimum cut balanced bisection of a graph",
+    "fields": [
+      {
+        "name": "graph",
+        "type_name": "G",
+        "description": "The undirected graph G=(V,E)"
+      }
+    ]
+  },
   {
     "name": "ILP",
     "description": "Optimize linear objective subject to linear constraints",
diff --git a/docs/src/reductions/reduction_graph.json b/docs/src/reductions/reduction_graph.json
index dcef7eae0..ce418d783 100644
--- a/docs/src/reductions/reduction_graph.json
+++ b/docs/src/reductions/reduction_graph.json
@@ -64,6 +64,15 @@
       "doc_path": "models/misc/struct.Factoring.html",
       "complexity": "exp((m + n)^(1/3) * log(m + n)^(2/3))"
     },
+    {
+      "name": "GraphPartitioning",
+      "variant": {
+        "graph": "SimpleGraph"
+      },
+      "category": "graph",
+      "doc_path": "models/graph/struct.GraphPartitioning.html",
+      "complexity": "2^num_vertices"
+    },
     {
       "name": "ILP",
       "variant": {
@@ -396,7 +405,7 @@
   "edges": [
     {
       "source": 4,
-      "target": 8,
+      "target": 9,
       "overhead": [
         {
           "field": "num_vars",
@@ -411,7 +420,7 @@
     },
     {
       "source": 4,
-      "target": 40,
+      "target": 41,
       "overhead": [
         {
           "field": "num_spins",
@@ -441,7 +450,7 @@
     },
     {
       "source": 7,
-      "target": 9,
+      "target": 10,
       "overhead": [
         {
           "field": "num_vars",
@@ -455,8 +464,8 @@
       "doc_path": "rules/factoring_ilp/index.html"
     },
     {
-      "source": 8,
-      "target": 9,
+      "source": 9,
+      "target": 10,
       "overhead": [
         {
           "field": "num_vars",
@@ -470,8 +479,8 @@
       "doc_path": "rules/ilp_bool_ilp_i32/index.html"
     },
     {
-      "source": 8,
-      "target": 37,
+      "source": 9,
+      "target": 38,
       "overhead": [
         {
           "field": "num_vars",
@@ -481,8 +490,8 @@
       "doc_path": "rules/ilp_qubo/index.html"
     },
     {
-      "source": 11,
-      "target": 14,
+      "source": 12,
+      "target": 15,
       "overhead": [
         {
           "field": "num_vertices",
@@ -496,8 +505,8 @@
       "doc_path": "rules/kcoloring_casts/index.html"
     },
     {
-      "source": 14,
-      "target": 8,
+      "source": 15,
+      "target": 9,
       "overhead": [
         {
           "field": "num_vars",
@@ -511,8 +520,8 @@
       "doc_path": "rules/coloring_ilp/index.html"
     },
     {
-      "source": 14,
-      "target": 37,
+      "source": 15,
+      "target": 38,
       "overhead": [
         {
           "field": "num_vars",
@@ -522,8 +531,8 @@
       "doc_path": "rules/coloring_qubo/index.html"
     },
     {
-      "source": 15,
-      "target": 17,
+      "source": 16,
+      "target": 18,
       "overhead": [
         {
           "field": "num_vars",
@@ -537,8 +546,8 @@
       "doc_path": "rules/ksatisfiability_casts/index.html"
     },
     {
-      "source": 15,
-      "target": 37,
+      "source": 16,
+      "target": 38,
       "overhead": [
         {
           "field": "num_vars",
@@ -548,8 +557,8 @@
       "doc_path": "rules/ksatisfiability_qubo/index.html"
     },
     {
-      "source": 16,
-      "target": 17,
+      "source": 17,
+      "target": 18,
       "overhead": [
         {
           "field": "num_vars",
@@ -563,8 +572,8 @@
       "doc_path": "rules/ksatisfiability_casts/index.html"
     },
     {
-      "source": 16,
-      "target": 37,
+      "source": 17,
+      "target": 38,
       "overhead": [
         {
           "field": "num_vars",
@@ -574,8 +583,8 @@
       "doc_path": "rules/ksatisfiability_qubo/index.html"
     },
     {
-      "source": 16,
-      "target": 41,
+      "source": 17,
+      "target": 42,
       "overhead": [
         {
           "field": "num_elements",
@@ -585,8 +594,8 @@
       "doc_path": "rules/ksatisfiability_subsetsum/index.html"
     },
     {
-      "source": 17,
-      "target": 38,
+      "source": 18,
+      "target": 39,
       "overhead": [
         {
           "field": "num_clauses",
@@ -604,8 +613,8 @@
       "doc_path": "rules/sat_ksat/index.html"
     },
     {
-      "source": 19,
-      "target": 40,
+      "source": 20,
+      "target": 41,
       "overhead": [
         {
           "field": "num_spins",
@@ -619,8 +628,8 @@
       "doc_path": "rules/spinglass_maxcut/index.html"
     },
     {
-      "source": 21,
-      "target": 8,
+      "source": 22,
+      "target": 9,
       "overhead": [
         {
           "field": "num_vars",
@@ -634,8 +643,8 @@
       "doc_path": "rules/maximumclique_ilp/index.html"
     },
     {
-      "source": 22,
-      "target": 23,
+      "source": 23,
+      "target": 24,
       "overhead": [
         {
           "field": "num_vertices",
@@ -649,8 +658,8 @@
       "doc_path": "rules/maximumindependentset_casts/index.html"
     },
     {
-      "source": 22,
-      "target": 27,
+      "source": 23,
+      "target": 28,
       "overhead": [
         {
           "field": "num_vertices",
@@ -664,8 +673,8 @@
       "doc_path": "rules/maximumindependentset_casts/index.html"
     },
     {
-      "source": 23,
-      "target": 28,
+      "source": 24,
+      "target": 29,
       "overhead": [
         {
           "field": "num_vertices",
@@ -679,8 +688,8 @@
       "doc_path": "rules/maximumindependentset_casts/index.html"
     },
     {
-      "source": 24,
-      "target": 22,
+      "source": 25,
+      "target": 23,
       "overhead": [
         {
           "field": "num_vertices",
@@ -694,8 +703,8 @@
       "doc_path": "rules/maximumindependentset_gridgraph/index.html"
     },
     {
-      "source": 24,
-      "target": 25,
+      "source": 25,
+      "target": 26,
       "overhead": [
         {
           "field": "num_vertices",
@@ -709,8 +718,8 @@
       "doc_path": "rules/maximumindependentset_casts/index.html"
     },
     {
-      "source": 24,
-      "target": 26,
+      "source": 25,
+      "target": 27,
       "overhead": [
         {
           "field": "num_vertices",
@@ -724,8 +733,8 @@
       "doc_path": "rules/maximumindependentset_triangular/index.html"
     },
     {
-      "source": 24,
-      "target": 30,
+      "source": 25,
+      "target": 31,
       "overhead": [
         {
           "field": "num_sets",
@@ -739,8 +748,8 @@
       "doc_path": "rules/maximumindependentset_maximumsetpacking/index.html"
     },
     {
-      "source": 25,
-      "target": 32,
+      "source": 26,
+      "target": 33,
       "overhead": [
         {
           "field": "num_sets",
@@ -754,8 +763,8 @@
       "doc_path": "rules/maximumindependentset_maximumsetpacking/index.html"
     },
     {
-      "source": 25,
-      "target": 35,
+      "source": 26,
+      "target": 36,
       "overhead": [
         {
           "field": "num_vertices",
@@ -769,8 +778,8 @@
       "doc_path": "rules/minimumvertexcover_maximumindependentset/index.html"
     },
     {
-      "source": 26,
-      "target": 28,
+      "source": 27,
+      "target": 29,
       "overhead": [
         {
           "field": "num_vertices",
@@ -784,8 +793,8 @@
       "doc_path": "rules/maximumindependentset_casts/index.html"
     },
     {
-      "source": 27,
-      "target": 24,
+      "source": 28,
+      "target": 25,
       "overhead": [
         {
           "field": "num_vertices",
@@ -799,8 +808,8 @@
       "doc_path": "rules/maximumindependentset_casts/index.html"
     },
     {
-      "source": 27,
-      "target": 28,
+      "source": 28,
+      "target": 29,
       "overhead": [
         {
           "field": "num_vertices",
@@ -814,8 +823,8 @@
       "doc_path": "rules/maximumindependentset_casts/index.html"
     },
     {
-      "source": 28,
-      "target": 25,
+      "source": 29,
+      "target": 26,
       "overhead": [
         {
           "field": "num_vertices",
@@ -829,8 +838,8 @@
       "doc_path": "rules/maximumindependentset_casts/index.html"
     },
     {
-      "source": 29,
-      "target": 8,
+      "source": 30,
+      "target": 9,
       "overhead": [
         {
           "field": "num_vars",
@@ -844,8 +853,8 @@
       "doc_path": "rules/maximummatching_ilp/index.html"
     },
     {
-      "source": 29,
-      "target": 32,
+      "source": 30,
+      "target": 33,
       "overhead": [
         {
           "field": "num_sets",
@@ -859,8 +868,8 @@
       "doc_path": "rules/maximummatching_maximumsetpacking/index.html"
     },
     {
-      "source": 30,
-      "target": 24,
+      "source": 31,
+      "target": 25,
       "overhead": [
         {
           "field": "num_vertices",
@@ -874,8 +883,8 @@
       "doc_path": "rules/maximumindependentset_maximumsetpacking/index.html"
     },
     {
-      "source": 30,
-      "target": 32,
+      "source": 31,
+      "target": 33,
       "overhead": [
         {
           "field": "num_sets",
@@ -889,8 +898,8 @@
       "doc_path": "rules/maximumsetpacking_casts/index.html"
     },
     {
-      "source": 31,
-      "target": 37,
+      "source": 32,
+      "target": 38,
       "overhead": [
         {
           "field": "num_vars",
@@ -900,8 +909,8 @@
       "doc_path": "rules/maximumsetpacking_qubo/index.html"
     },
     {
-      "source": 32,
-      "target": 8,
+      "source": 33,
+      "target": 9,
       "overhead": [
         {
           "field": "num_vars",
@@ -915,8 +924,8 @@
       "doc_path": "rules/maximumsetpacking_ilp/index.html"
     },
     {
-      "source": 32,
-      "target": 25,
+      "source": 33,
+      "target": 26,
       "overhead": [
         {
           "field": "num_vertices",
@@ -930,8 +939,8 @@
       "doc_path": "rules/maximumindependentset_maximumsetpacking/index.html"
     },
     {
-      "source": 32,
-      "target": 31,
+      "source": 33,
+      "target": 32,
       "overhead": [
         {
           "field": "num_sets",
@@ -945,8 +954,8 @@
       "doc_path": "rules/maximumsetpacking_casts/index.html"
     },
     {
-      "source": 33,
-      "target": 8,
+      "source": 34,
+      "target": 9,
       "overhead": [
         {
           "field": "num_vars",
@@ -960,8 +969,8 @@
       "doc_path": "rules/minimumdominatingset_ilp/index.html"
     },
     {
-      "source": 34,
-      "target": 8,
+      "source": 35,
+      "target": 9,
       "overhead": [
         {
           "field": "num_vars",
@@ -975,8 +984,8 @@
       "doc_path": "rules/minimumsetcovering_ilp/index.html"
     },
     {
-      "source": 35,
-      "target": 25,
+      "source": 36,
+      "target": 26,
       "overhead": [
         {
           "field": "num_vertices",
@@ -990,8 +999,8 @@
       "doc_path": "rules/minimumvertexcover_maximumindependentset/index.html"
     },
     {
-      "source": 35,
-      "target": 34,
+      "source": 36,
+      "target": 35,
       "overhead": [
         {
           "field": "num_sets",
@@ -1005,8 +1014,8 @@
       "doc_path": "rules/minimumvertexcover_minimumsetcovering/index.html"
     },
     {
-      "source": 37,
-      "target": 8,
+      "source": 38,
+      "target": 9,
       "overhead": [
         {
           "field": "num_vars",
@@ -1020,8 +1029,8 @@
       "doc_path": "rules/qubo_ilp/index.html"
     },
     {
-      "source": 37,
-      "target": 39,
+      "source": 38,
+      "target": 40,
       "overhead": [
         {
           "field": "num_spins",
@@ -1031,7 +1040,7 @@
       "doc_path": "rules/spinglass_qubo/index.html"
     },
     {
-      "source": 38,
+      "source": 39,
       "target": 4,
       "overhead": [
         {
@@ -1046,8 +1055,8 @@
       "doc_path": "rules/sat_circuitsat/index.html"
     },
     {
-      "source": 38,
-      "target": 11,
+      "source": 39,
+      "target": 12,
       "overhead": [
         {
           "field": "num_vertices",
@@ -1061,8 +1070,8 @@
       "doc_path": "rules/sat_coloring/index.html"
     },
     {
-      "source": 38,
-      "target": 16,
+      "source": 39,
+      "target": 17,
       "overhead": [
         {
           "field": "num_clauses",
@@ -1076,8 +1085,8 @@
       "doc_path": "rules/sat_ksat/index.html"
     },
     {
-      "source": 38,
-      "target": 24,
+      "source": 39,
+      "target": 25,
       "overhead": [
         {
           "field": "num_vertices",
@@ -1091,8 +1100,8 @@
       "doc_path": "rules/sat_maximumindependentset/index.html"
     },
     {
-      "source": 38,
-      "target": 33,
+      "source": 39,
+      "target": 34,
       "overhead": [
         {
           "field": "num_vertices",
@@ -1106,8 +1115,8 @@
       "doc_path": "rules/sat_minimumdominatingset/index.html"
     },
     {
-      "source": 39,
-      "target": 37,
+      "source": 40,
+      "target": 38,
       "overhead": [
         {
           "field": "num_vars",
@@ -1117,8 +1126,8 @@
       "doc_path": "rules/spinglass_qubo/index.html"
     },
     {
-      "source": 40,
-      "target": 19,
+      "source": 41,
+      "target": 20,
       "overhead": [
         {
           "field": "num_vertices",
@@ -1132,8 +1141,8 @@
       "doc_path": "rules/spinglass_maxcut/index.html"
     },
     {
-      "source": 40,
-      "target": 39,
+      "source": 41,
+      "target": 40,
       "overhead": [
         {
           "field": "num_spins",
@@ -1147,8 +1156,8 @@
       "doc_path": "rules/spinglass_casts/index.html"
     },
     {
-      "source": 42,
-      "target": 8,
+      "source": 43,
+      "target": 9,
       "overhead": [
         {
           "field": "num_vars",

From 98b9cfdb20e2726919dffdf7d6da16acaf751246 Mon Sep 17 00:00:00 2001
From: GiggleLiu <cacate0129@gmail.com>
Date: Thu, 12 Mar 2026 23:01:18 +0800
Subject: [PATCH 2/5] fix: add FPT complexity citation for GraphPartitioning
 (#117)

Address review comment: explicitly state that brute-force O*(2^n) is
the best known unconditional exact algorithm, and cite Cygan et al.
(STOC 2014 / SICOMP 2019) for the FPT result parameterized by
bisection width.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 docs/paper/reductions.typ |  2 +-
 docs/paper/references.bib | 12 ++++++++++++
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/docs/paper/reductions.typ b/docs/paper/reductions.typ
index 747996668..a30d1b73b 100644
--- a/docs/paper/reductions.typ
+++ b/docs/paper/reductions.typ
@@ -385,7 +385,7 @@ caption: [The house graph with max cut $S = {v_0, v_3}$ (blue) vs $overline(S) =
   Given an undirected graph $G = (V, E)$ with $|V| = n$ (even), find a partition of $V$ into two disjoint sets $A$ and $B$ with $|A| = |B| = n slash 2$ that minimizes the number of edges crossing the partition:
   $ "cut"(A, B) = |{(u, v) in E : u in A, v in B}|. $
 ][
-Graph Partitioning is a core NP-hard problem arising in VLSI design, parallel computing, and scientific simulation, where balanced workload distribution with minimal communication is essential. Closely related to Max-Cut (which _maximizes_ rather than _minimizes_ the cut) and to the Ising Spin Glass model. NP-completeness was proved by Garey, Johnson and Stockmeyer @garey1976. Arora, Rao and Vazirani @arora2009 gave an $O(sqrt(log n))$-approximation algorithm. Standard partitioning tools include METIS, KaHIP, and Scotch.
+Graph Partitioning is a core NP-hard problem arising in VLSI design, parallel computing, and scientific simulation, where balanced workload distribution with minimal communication is essential. Closely related to Max-Cut (which _maximizes_ rather than _minimizes_ the cut) and to the Ising Spin Glass model. NP-completeness was proved by Garey, Johnson and Stockmeyer @garey1976. Arora, Rao and Vazirani @arora2009 gave an $O(sqrt(log n))$-approximation algorithm. The best known unconditional exact algorithm is brute-force enumeration of all $binom(n, n slash 2) = O^*(2^n)$ balanced partitions; no faster worst-case algorithm is known. Cygan et al. @cygan2014 showed that Minimum Bisection is fixed-parameter tractable in $O(2^(O(k^3)) dot n^3 log^3 n)$ time parameterized by bisection width $k$. Standard partitioning tools include METIS, KaHIP, and Scotch.
 
 *Example.* Consider the graph $G$ with $n = 6$ vertices and 9 edges: $(v_0, v_1)$, $(v_0, v_2)$, $(v_1, v_2)$, $(v_1, v_3)$, $(v_2, v_3)$, $(v_2, v_4)$, $(v_3, v_4)$, $(v_3, v_5)$, $(v_4, v_5)$. The optimal balanced partition is $A = {v_0, v_1, v_2}$, $B = {v_3, v_4, v_5}$, with cut value 3: the crossing edges are $(v_1, v_3)$, $(v_2, v_3)$, $(v_2, v_4)$. All other balanced partitions yield a cut of at least 3.
 
diff --git a/docs/paper/references.bib b/docs/paper/references.bib
index b69248331..a68de5c4b 100644
--- a/docs/paper/references.bib
+++ b/docs/paper/references.bib
@@ -425,3 +425,15 @@ @article{arora2009
   year    = {2009},
   doi     = {10.1145/1502793.1502794}
 }
+
+@article{cygan2014,
+  author  = {Marek Cygan and Daniel Lokshtanov and Marcin Pilipczuk and Micha{\l} Pilipczuk and Saket Saurabh},
+  title   = {Minimum Bisection Is Fixed Parameter Tractable},
+  journal = {SIAM Journal on Computing},
+  volume  = {48},
+  number  = {2},
+  pages   = {417--450},
+  year    = {2019},
+  note    = {Conference version: STOC 2014},
+  doi     = {10.1137/140990255}
+}

From 6676a1b7f18baa56abf729f90164cf75843ae42c Mon Sep 17 00:00:00 2001
From: GiggleLiu <cacate0129@gmail.com>
Date: Thu, 12 Mar 2026 23:08:32 +0800
Subject: [PATCH 3/5] fix: use sort_by_key per clippy unnecessary_sort_by lint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 examples/detect_isolated_problems.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/detect_isolated_problems.rs b/examples/detect_isolated_problems.rs
index e2a359c79..209b61b17 100644
--- a/examples/detect_isolated_problems.rs
+++ b/examples/detect_isolated_problems.rs
@@ -53,7 +53,7 @@ fn main() {
     }
 
     // Sort components by size (largest first)
-    components.sort_by(|a, b| b.len().cmp(&a.len()));
+    components.sort_by_key(|b| std::cmp::Reverse(b.len()));
 
     // Identify isolated types (no edges at all)
     let isolated: Vec<&str> = types

From c660d53b1ec3641f52ee87cf38dcf8298703bc92 Mon Sep 17 00:00:00 2001
From: GiggleLiu <cacate0129@gmail.com>
Date: Thu, 12 Mar 2026 23:10:40 +0800
Subject: [PATCH 4/5] feat: add merge-with-main conflict resolution step to
 review-pipeline

Add Step 1a between checkout and Copilot fixes to merge origin/main
into the PR branch. Resolves simple conflicts automatically; aborts
and reports for complex conflicts needing manual resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 .claude/skills/review-pipeline/SKILL.md | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/.claude/skills/review-pipeline/SKILL.md b/.claude/skills/review-pipeline/SKILL.md
index f9c5bf81f..c61d183dc 100644
--- a/.claude/skills/review-pipeline/SKILL.md
+++ b/.claude/skills/review-pipeline/SKILL.md
@@ -82,6 +82,22 @@ cd "$WORKTREE_DIR"
 
 All subsequent steps run inside the worktree.
 
+### 1a. Resolve Conflicts with Main
+
+Check if the branch has merge conflicts with main:
+
+```bash
+git fetch origin main
+git merge origin/main --no-edit
+```
+
+- If the merge succeeds cleanly: push the merge commit and continue.
+- If there are conflicts:
+  1. Inspect the conflicting files with `git diff --name-only --diff-filter=U`.
+  2. Resolve conflicts (prefer the PR branch for new code, main for regenerated artifacts like JSON).
+  3. Stage resolved files, commit, and push.
+- If conflicts are too complex to resolve automatically (e.g., overlapping logic changes in the same function): abort the merge (`git merge --abort`), leave the PR in review-agentic, and report: `PR #N has complex merge conflicts with main — needs manual resolution.` Then STOP processing this PR.
+
 ### 2. Fix Copilot Review Comments
 
 Copilot review is guaranteed to exist (verified in Step 0). Fetch the comments:
@@ -210,3 +226,4 @@ Completed: 2/2 | All moved to In Review
 | Not checking out the right branch | Use `gh pr view` to get the exact branch name |
 | Worktree left behind on failure | Always clean up with `git worktree remove` in Step 5 |
 | Working in main checkout | All work happens in `.worktrees/` — never modify the main checkout |
+| Skipping merge with main | Always merge origin/main in Step 1a to catch conflicts before fixing comments |

From 16c5b18d7ae9d37c3d26b89dd15f601e1aedf0b1 Mon Sep 17 00:00:00 2001
From: GiggleLiu <cacate0129@gmail.com>
Date: Thu, 12 Mar 2026 23:13:06 +0800
Subject: [PATCH 5/5] update pipeline skills: eligibility-first sorting,
 merge-with-main

project-pipeline: Reorder Steps 0c/0d so eligibility check (source and
target models exist) runs before scoring. Only eligible issues get scored.

review-pipeline: Add Step 1a to merge origin/main into the PR branch
before fixing Copilot comments, catching conflicts early.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 .claude/skills/project-pipeline/SKILL.md | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/.claude/skills/project-pipeline/SKILL.md b/.claude/skills/project-pipeline/SKILL.md
index 73ff0b02d..eee7baa4b 100644
--- a/.claude/skills/project-pipeline/SKILL.md
+++ b/.claude/skills/project-pipeline/SKILL.md
@@ -48,9 +48,19 @@ Filter items where `status == "Ready"`. Partition into `[Model]` and `[Rule]` bu
 1. **Existing problems:** Call `list_problems` (MCP tool) to get all problems currently in the reduction graph.
 2. **Pending rules:** From the full project board JSON, collect all `[Rule]` issues that are in "Ready" or "In Progress" status. Parse their source/target problem names (e.g., `[Rule] BinPacking to ILP` → source=BinPacking, target=ILP).
 
-#### 0c. Score Each Issue
+#### 0c. Check Eligibility
 
-Score each Ready issue on three criteria. For `[Model]` issues, extract the problem name. For `[Rule]` issues, extract both source and target problem names.
+**Rule issues require both source and target models to exist.** For each `[Rule]` issue, parse the source and target problem names (e.g., `[Rule] BinPacking to ILP` → source=BinPacking, target=ILP). Check that both appear in the `list_problems` output (existing models) OR in a `[Model]` issue in the current Ready/In Progress columns.
+
+- If both models exist → **eligible**
+- If a missing model has a `[Model]` issue in Ready → eligible only in `--all` mode (the Model will be processed first); in single-issue mode, **skip this Rule** and mark it `[blocked]`
+- If a missing model has no `[Model]` issue at all → **ineligible**, mark it `[blocked]` with reason
+
+All `[Model]` issues are always eligible (no dependency check needed).
+
+#### 0d. Score Eligible Issues
+
+Score only **eligible** issues on three criteria. For `[Model]` issues, extract the problem name. For `[Rule]` issues, extract both source and target problem names.
 
 | Criterion | Weight | How to Assess |
 |-----------|--------|---------------|
@@ -64,14 +74,6 @@ Score each Ready issue on three criteria. For `[Model]` issues, extract the prob
 
 **Important for C2:** A problem that is merely a weighted/unweighted variant or a graph-subtype specialization of an existing problem scores **0** on C2, not 2. The goal is to add genuinely new problem types that expand the graph's reach.
 
-#### 0d. Apply Hard Constraints
-
-**Rule issues require both source and target models to exist.** For each `[Rule]` issue, check that both its source and target problem names appear in the `list_problems` output (existing models) OR in a `[Model]` issue in the current Ready/In Progress columns.
-
-- If both models exist → eligible
-- If a missing model has a `[Model]` issue in Ready → eligible only in `--all` mode (the Model will be processed first); in single-issue mode, **skip this Rule** and mark it `[blocked]`
-- If a missing model has no `[Model]` issue at all → **ineligible**, mark it `[blocked]` with reason
-
 #### 0e. Print Ranked List
 
 Print all Ready issues with their scores for visibility (no confirmation needed). Blocked rules appear at the bottom with their reason:
