Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions docs/paper/reductions.typ
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"MinimumFeedbackArcSet": [Minimum Feedback Arc Set],
"MinimumFeedbackVertexSet": [Minimum Feedback Vertex Set],
"ShortestCommonSupersequence": [Shortest Common Supersequence],
"MinMaxMulticenter": [Min-Max Multicenter],
"MinimumSumMulticenter": [Minimum Sum Multicenter],
"SteinerTree": [Steiner Tree],
"SubgraphIsomorphism": [Subgraph Isomorphism],
Expand Down Expand Up @@ -1003,6 +1004,50 @@ NP-completeness was established by Garey, Johnson, and Stockmeyer @gareyJohnsonS
]
}

#{
let x = load-model-example("MinMaxMulticenter")
let nv = graph-num-vertices(x.instance)
let edges = x.instance.graph.inner.edges.map(e => (e.at(0), e.at(1)))
let K = x.instance.k
let B = x.instance.bound
let desired-config = (0, 1, 0, 0, 1, 0)
let sol = x.optimal.find(o => o.config == desired-config)
let centers = sol.config.enumerate().filter(((i, v)) => v == 1).map(((i, _)) => i)
[
#problem-def("MinMaxMulticenter")[
Given a graph $G = (V, E)$ with vertex weights $w: V -> ZZ_(>= 0)$, edge lengths $l: E -> ZZ_(>= 0)$, a positive integer $K <= |V|$, and a rational bound $B > 0$, does there exist $S subset.eq V$ with $|S| = K$ such that $max_(v in V) w(v) dot d(v, S) <= B$, where $d(v, S) = min_(s in S) d(v, s)$ is the shortest weighted-path distance from $v$ to the nearest vertex in $S$?
][
Also known as the _vertex p-center problem_ (Garey & Johnson A2 ND50). The goal is to place $K$ facilities so that the worst-case weighted distance from any demand point to its nearest facility is at most $B$. NP-complete even with unit weights and unit edge lengths (Kariv and Hakimi, 1979).

Closely related to Dominating Set: on unweighted unit-length graphs, a $K$-center with radius $B = 1$ is exactly a dominating set of size $K$. The best known exact algorithm runs in $O^*(1.4969^n)$ via binary search over distance thresholds combined with dominating set computation @vanrooij2011. An optimal 2-approximation exists (Hochbaum and Shmoys, 1985); no $(2 - epsilon)$-approximation is possible unless $P = "NP"$ (Hsu and Nemhauser, 1979).

Variables: $n = |V|$ binary variables, one per vertex. $x_v = 1$ if vertex $v$ is selected as a center. A configuration is satisfying when exactly $K$ centers are selected and $max_(v in V) w(v) dot d(v, S) <= B$.

*Example.* Consider the graph $G$ on #nv vertices with unit weights $w(v) = 1$, unit edge lengths, edges ${#edges.map(((u, v)) => $(#u, #v)$).join(", ")}$, $K = #K$, and $B = #B$. Placing centers at $S = {#centers.map(i => $v_#i$).join(", ")}$ gives maximum distance $max_v d(v, S) = 1 <= B$, so this is a feasible solution. In fact, #x.optimal.len() distinct center placements satisfy the bound.

#figure({
let blue = graph-colors.at(0)
let gray = luma(200)
canvas(length: 1cm, {
import draw: *
let verts = ((-1.5, 0.8), (0, 1.5), (1.5, 0.8), (1.5, -0.8), (0, -1.5), (-1.5, -0.8))
for (u, v) in edges {
g-edge(verts.at(u), verts.at(v), stroke: 1pt + gray)
}
for (k, pos) in verts.enumerate() {
let is-center = centers.any(c => c == k)
g-node(pos, name: "v" + str(k),
fill: if is-center { blue } else { white },
label: if is-center { text(fill: white)[$v_#k$] } else { [$v_#k$] })
}
})
},
caption: [Min-Max Multicenter with $K = #K$, $B = #B$ on a #{nv}-vertex graph. Centers #centers.map(i => $v_#i$).join(" and ") (blue) ensure every vertex is within distance $B$ of some center.],
) <fig:min-max-multicenter>
]
]
}

== Set Problems

#{
Expand Down
4 changes: 3 additions & 1 deletion docs/src/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ pred create QUBO --matrix "1,0.5;0.5,2" -o qubo.json
pred create KColoring --k 3 --graph 0-1,1-2,2-0 -o kcol.json
pred create SpinGlass --graph 0-1,1-2 -o sg.json
pred create MaxCut --graph 0-1,1-2,2-0 -o maxcut.json
pred create MinMaxMulticenter --graph 0-1,1-2,2-3 --weights 1,1,1,1 --edge-weights 1,1,1 --k 2 --bound 1 -o pcenter.json
pred create SteinerTree --graph 0-1,0-3,1-2,1-3,2-3,2-4,3-4 --edge-weights 2,5,2,1,5,6,1 --terminals 0,2,4 -o steiner.json
pred create Factoring --target 15 --bits-m 4 --bits-n 4 -o factoring.json
pred create Factoring --target 21 --bits-m 3 --bits-n 3 -o factoring2.json
Expand Down Expand Up @@ -393,6 +394,7 @@ Stdin is supported with `-`:
```bash
pred create MIS --graph 0-1,1-2,2-3 | pred solve -
pred create MIS --graph 0-1,1-2,2-3 | pred solve - --solver brute-force
pred create MinMaxMulticenter --graph 0-1,1-2,2-3 --weights 1,1,1,1 --edge-weights 1,1,1 --k 2 --bound 1 | pred solve - --solver brute-force
```

When the problem is not ILP, the solver automatically reduces it to ILP, solves, and maps the solution back. The auto-reduction is shown in the output:
Expand All @@ -418,7 +420,7 @@ Source evaluation: Valid(2)
```

> **Note:** The ILP solver requires a reduction path from the target problem to ILP.
> Some problems (e.g., QUBO, SpinGlass, MaxCut, CircuitSAT) do not have this path yet.
> Some problems (e.g., QUBO, SpinGlass, MaxCut, CircuitSAT, MinMaxMulticenter) do not have this path yet.
> Use `--solver brute-force` for these, or reduce to a problem that supports ILP first.

## Shell Completions
Expand Down
31 changes: 31 additions & 0 deletions docs/src/reductions/problem_schemas.json
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,37 @@
}
]
},
{
"name": "MinMaxMulticenter",
"description": "Determine if K centers can be placed so max weighted distance is at most B (vertex p-center)",
"fields": [
{
"name": "graph",
"type_name": "G",
"description": "The underlying graph G=(V,E)"
},
{
"name": "vertex_weights",
"type_name": "Vec<W>",
"description": "Vertex weights w: V -> R"
},
{
"name": "edge_lengths",
"type_name": "Vec<W>",
"description": "Edge lengths l: E -> R"
},
{
"name": "k",
"type_name": "usize",
"description": "Number of centers to place"
},
{
"name": "bound",
"type_name": "W::Sum",
"description": "Upper bound B on maximum weighted distance"
}
]
},
{
"name": "MinimumDominatingSet",
"description": "Find minimum weight dominating set in a graph",
Expand Down
76 changes: 43 additions & 33 deletions docs/src/reductions/reduction_graph.json
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,16 @@
"doc_path": "models/set/struct.MaximumSetPacking.html",
"complexity": "2^num_sets"
},
{
"name": "MinMaxMulticenter",
"variant": {
"graph": "SimpleGraph",
"weight": "i32"
},
"category": "graph",
"doc_path": "models/graph/struct.MinMaxMulticenter.html",
"complexity": "1.4969^num_vertices"
},
{
"name": "MinimumDominatingSet",
"variant": {
Expand Down Expand Up @@ -569,7 +579,7 @@
},
{
"source": 4,
"target": 54,
"target": 55,
"overhead": [
{
"field": "num_spins",
Expand Down Expand Up @@ -629,7 +639,7 @@
},
{
"source": 12,
"target": 49,
"target": 50,
"overhead": [
{
"field": "num_vars",
Expand Down Expand Up @@ -670,7 +680,7 @@
},
{
"source": 19,
"target": 49,
"target": 50,
"overhead": [
{
"field": "num_vars",
Expand All @@ -696,7 +706,7 @@
},
{
"source": 20,
"target": 49,
"target": 50,
"overhead": [
{
"field": "num_vars",
Expand All @@ -722,7 +732,7 @@
},
{
"source": 21,
"target": 49,
"target": 50,
"overhead": [
{
"field": "num_vars",
Expand All @@ -733,7 +743,7 @@
},
{
"source": 21,
"target": 58,
"target": 59,
"overhead": [
{
"field": "num_elements",
Expand All @@ -744,7 +754,7 @@
},
{
"source": 22,
"target": 51,
"target": 52,
"overhead": [
{
"field": "num_clauses",
Expand All @@ -763,7 +773,7 @@
},
{
"source": 23,
"target": 49,
"target": 50,
"overhead": [
{
"field": "num_vars",
Expand All @@ -789,7 +799,7 @@
},
{
"source": 25,
"target": 54,
"target": 55,
"overhead": [
{
"field": "num_spins",
Expand Down Expand Up @@ -969,7 +979,7 @@
},
{
"source": 31,
"target": 45,
"target": 46,
"overhead": [
{
"field": "num_vertices",
Expand Down Expand Up @@ -1104,7 +1114,7 @@
},
{
"source": 37,
"target": 49,
"target": 50,
"overhead": [
{
"field": "num_vars",
Expand Down Expand Up @@ -1159,7 +1169,7 @@
"doc_path": "rules/maximumsetpacking_casts/index.html"
},
{
"source": 39,
"source": 40,
"target": 12,
"overhead": [
{
Expand All @@ -1174,7 +1184,7 @@
"doc_path": "rules/minimumdominatingset_ilp/index.html"
},
{
"source": 42,
"source": 43,
"target": 12,
"overhead": [
{
Expand All @@ -1189,7 +1199,7 @@
"doc_path": "rules/minimumsetcovering_ilp/index.html"
},
{
"source": 45,
"source": 46,
"target": 31,
"overhead": [
{
Expand All @@ -1204,8 +1214,8 @@
"doc_path": "rules/minimumvertexcover_maximumindependentset/index.html"
},
{
"source": 45,
"target": 42,
"source": 46,
"target": 43,
"overhead": [
{
"field": "num_sets",
Expand All @@ -1219,7 +1229,7 @@
"doc_path": "rules/minimumvertexcover_minimumsetcovering/index.html"
},
{
"source": 49,
"source": 50,
"target": 12,
"overhead": [
{
Expand All @@ -1234,8 +1244,8 @@
"doc_path": "rules/qubo_ilp/index.html"
},
{
"source": 49,
"target": 53,
"source": 50,
"target": 54,
"overhead": [
{
"field": "num_spins",
Expand All @@ -1245,7 +1255,7 @@
"doc_path": "rules/spinglass_qubo/index.html"
},
{
"source": 51,
"source": 52,
"target": 4,
"overhead": [
{
Expand All @@ -1260,7 +1270,7 @@
"doc_path": "rules/sat_circuitsat/index.html"
},
{
"source": 51,
"source": 52,
"target": 16,
"overhead": [
{
Expand All @@ -1275,7 +1285,7 @@
"doc_path": "rules/sat_coloring/index.html"
},
{
"source": 51,
"source": 52,
"target": 21,
"overhead": [
{
Expand All @@ -1290,7 +1300,7 @@
"doc_path": "rules/sat_ksat/index.html"
},
{
"source": 51,
"source": 52,
"target": 30,
"overhead": [
{
Expand All @@ -1305,8 +1315,8 @@
"doc_path": "rules/sat_maximumindependentset/index.html"
},
{
"source": 51,
"target": 39,
"source": 52,
"target": 40,
"overhead": [
{
"field": "num_vertices",
Expand All @@ -1320,8 +1330,8 @@
"doc_path": "rules/sat_minimumdominatingset/index.html"
},
{
"source": 53,
"target": 49,
"source": 54,
"target": 50,
"overhead": [
{
"field": "num_vars",
Expand All @@ -1331,7 +1341,7 @@
"doc_path": "rules/spinglass_qubo/index.html"
},
{
"source": 54,
"source": 55,
"target": 25,
"overhead": [
{
Expand All @@ -1346,8 +1356,8 @@
"doc_path": "rules/spinglass_maxcut/index.html"
},
{
"source": 54,
"target": 53,
"source": 55,
"target": 54,
"overhead": [
{
"field": "num_spins",
Expand All @@ -1361,7 +1371,7 @@
"doc_path": "rules/spinglass_casts/index.html"
},
{
"source": 59,
"source": 60,
"target": 12,
"overhead": [
{
Expand All @@ -1376,8 +1386,8 @@
"doc_path": "rules/travelingsalesman_ilp/index.html"
},
{
"source": 59,
"target": 49,
"source": 60,
"target": 50,
"overhead": [
{
"field": "num_vars",
Expand Down
Loading
Loading