Skip to content

Commit 2baa18e

Browse files
GiggleLiuclaude
andcommitted
chore: rustfmt formatting fixes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d324570 commit 2baa18e

12 files changed

Lines changed: 866 additions & 51 deletions
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Design: ILP Type Parameter for Variable Domain
2+
3+
## Motivation
4+
5+
The current `ILP` struct carries a `bounds: Vec<VarBounds>` field, but every reduction into ILP produces binary variables (`VarBounds::binary()`), except Factoring which uses bounded integers for carries. Meanwhile, ILP → QUBO requires binary variables and checks this with a runtime assert. The `bounds` field adds complexity without value for the common case, and makes the ILP → QUBO overhead expression inaccurate (slack bits depend on coefficient magnitudes, not expressible symbolically).
6+
7+
## Design
8+
9+
### Type Parameter
10+
11+
Replace `ILP` with `ILP<V>` where `V` determines the variable domain:
12+
13+
```rust
14+
pub struct ILP<V> {
15+
pub num_vars: usize,
16+
pub constraints: Vec<LinearConstraint>,
17+
pub objective: Vec<(usize, f64)>,
18+
pub sense: ObjectiveSense,
19+
_marker: PhantomData<V>,
20+
}
21+
```
22+
23+
- `ILP<bool>`: Binary variables. `dims() = vec![2; n]`. Config `0 → 0`, `1 → 1`.
24+
- `ILP<i32>`: Non-negative integers `0..2_147_483_647`. `dims() = vec![i32::MAX as usize; n]`. Config index = value. Bounded ranges expressed as constraints (e.g., `x_i <= 5`).
25+
26+
The `bounds` field is removed entirely.
27+
28+
### Reduction Graph
29+
30+
Two variant nodes following the existing pattern (like `MIS {graph: "SimpleGraph"}` / `MIS {graph: "KingsSubgraph"}`):
31+
32+
- `ILP {variable: "bool"}` — binary integer linear programming
33+
- `ILP {variable: "i32"}` — general integer linear programming
34+
35+
Natural cast edge: `ILP<bool>``ILP<i32>` (zero cost — every binary program is a valid integer program).
36+
37+
### Impact on Reductions
38+
39+
| Reduction | Before | After |
40+
|---|---|---|
41+
| MIS → ILP | `ILP` with `VarBounds::binary()` | `ILP<bool>` |
42+
| MVC → ILP (if re-added) | `ILP` with `VarBounds::binary()` | `ILP<bool>` |
43+
| MaxClique → ILP | `ILP` with `VarBounds::binary()` | `ILP<bool>` |
44+
| MaxMatching → ILP | `ILP` with `VarBounds::binary()` | `ILP<bool>` |
45+
| MinDS → ILP | `ILP` with `VarBounds::binary()` | `ILP<bool>` |
46+
| MinSetCovering → ILP | `ILP` with `VarBounds::binary()` | `ILP<bool>` |
47+
| KColoring → ILP | `ILP` with `VarBounds::binary()` | `ILP<bool>` |
48+
| TSP → ILP | `ILP` with `VarBounds::binary()` | `ILP<bool>` |
49+
| CircuitSAT → ILP | `ILP` with `VarBounds::binary()` | `ILP<bool>` |
50+
| Factoring → ILP | `ILP` with mixed bounds | `ILP<i32>` with carry ranges as constraints |
51+
| ILP → QUBO | Runtime assert binary | `impl ReduceTo<QUBO<f64>> for ILP<bool>` — compile-time guarantee |
52+
| QUBO → ILP | Produces binary ILP | `ILP<bool>` |
53+
54+
### ILP → QUBO Overhead Fix
55+
56+
With `ILP<bool>`, all source variables are binary. Slack variables from inequality constraints have a worst-case count bounded by `num_constraints * ceil(log2(num_vars + 1))`. The overhead expression becomes:
57+
58+
```rust
59+
#[reduction(overhead = {
60+
num_vars = "num_vars + num_constraints * num_vars", // worst-case slack
61+
})]
62+
impl ReduceTo<QUBO<f64>> for ILP<bool> { ... }
63+
```
64+
65+
This removes ILP → QUBO from the `UNTRUSTED_EDGES` list in `analysis.rs`.
66+
67+
### ILP Solver
68+
69+
The `ILPSolver` works with both `ILP<bool>` and `ILP<i32>`:
70+
- `ILP<bool>`: HiGHS variables set as binary `[0, 1]`
71+
- `ILP<i32>`: HiGHS variables set as integer `[0, i32::MAX]`, constraints provide effective bounds
72+
73+
No `VarBounds` needed in the solver interface.
74+
75+
### VarBounds
76+
77+
Removed from `ILP`. Retained for `ClosestVectorProblem<T>` which genuinely needs per-variable bounds for lattice enumeration.
78+
79+
### Constructors
80+
81+
- `ILP::<bool>::new(num_vars, constraints, objective, sense)` — replaces `ILP::binary()`
82+
- `ILP::<i32>::new(num_vars, constraints, objective, sense)` — general integer
83+
- `ILP::binary()` convenience removed (redundant with `ILP::<bool>::new`)
84+
85+
### variant() Implementation
86+
87+
```rust
88+
impl<V: VariableDomain> Problem for ILP<V> {
89+
fn variant() -> Vec<(&'static str, &'static str)> {
90+
vec![("variable", V::NAME)]
91+
}
92+
}
93+
```
94+
95+
Where `VariableDomain` is a sealed trait implemented for `bool` ("bool") and `i32` ("i32").
96+
97+
### Complexity
98+
99+
```rust
100+
declare_variants! {
101+
ILP<bool> => "2^num_vars",
102+
ILP<i32> => "num_vars^num_vars",
103+
}
104+
```
105+
106+
Binary ILP is `O(2^n)` brute-force; general ILP is `O(n^n)` since each variable can take up to `n^n` combinations.

0 commit comments

Comments
 (0)