◐ Off-By-One · answer catalog

go-minimum-weight-spill-set-interval-interference-exact

2 answer(s)gogo1.26gogo1.26

We are given N live intervals. Interval i has a start point si, an end point ei, and a spill weight wi > 0, plus K physical registers. Two intervals interfere when simultaneously live. The interference graph of intervals is an interval graph, and an interval graph is K-colorable iff its maximum clique is at most K. For intervals, the maximum clique is exactly the maximum depth:

📦 Source in repository (JSON)

Answer 1

I diagnosed the problem, implemented and verified an exact solver, and wrote the report to ~/spill/SOLUTION.md. Here is the solution:


Exact Minimum-Weight Spill Set for Interval Interference

1. Problem

We are given N live intervals. Interval i has a start point s_i, an end point e_i, and a spill weight w_i > 0, plus K physical registers. Two intervals interfere when simultaneously live. The interference graph of intervals is an interval graph, and an interval graph is K-colorable iff its maximum clique is at most K. For intervals, the maximum clique is exactly the maximum depth:

survivors are K-colorable ⇔ at every program point at most K survivors are live.

We must choose a set S of intervals to spill minimizing Σ_{i∈S} w_i subject to survivors having depth ≤ K. Print spilled indices ascending, then total spilled weight, breaking equal-weight ties by choosing the larger index first.

Input format:

N K
s_1 e_1 w_1
...
s_N e_N w_N

Overlap semantics are compiled in via closed: closed = true means [1,2] and [2,3] clash (share point 2); closed = false means half-open [1,2)/[2,3) (linear-scan convention).

2. Root-cause analysis: the greedy is not exact

The standard linear-scan heuristic sweeps by start and, on overflow, spills the lightest currently live interval. It has no lookahead and is provably suboptimal.

Witness (K = 1):

idx interval weight
1 [3, 12] 6
2 [9, 18] 6
3 [1, 10] 1
4 [5, 7] 2

Greedy: spills {3,4,1} → 1+2+6 = 9. Exact: spills {1,3} → 6+1 = 7; survivors {2,4} are disjoint. The heavy interval 1 overlaps several lights; greedy wastes cheap spills (3, then 4) protecting it and then must spill it anyway. Any local overflow decision cannot see this.

3. Exact fix

3.1 DP over the sweep with a bitmask of the active set

Process intervals in increasing start order. At interval i's start, only which retained intervals are still live matters. Let f(i, mask) be the minimum spilled weight for intervals i..N-1, where mask is the set of previously retained intervals active at s_i. For interval i:

Clear bits that die before the next start (mask &= active[i+1]). Answer f(0, ∅).

Checking depth only at start points suffices: if depth is maximal at p, let s be the largest start among intervals covering p; every such interval also covers s, so depth at start s is at least that of p.

3.2 Tie-break

Give interval j (0-based) bit value 2^j. Listing a spilled set in descending index order and comparing lexicographically is identical to comparing numeric mask values (largest differing index dominates all lower bits). So "choose the larger index first" = "prefer the larger spill mask". This is safe inside the DP because prefix/suffix spill sets are disjoint, so total value = prefix + suffix and maximizing the suffix mask is optimal for every prefix.

3.3 Complexity

Memoized state (i, active-mask): worst case O(N·2^N) time / O(2^N) states, but ended-interval bit clearing collapses states heavily in practice. For very large N, the same optimum is a min-cost flow on the timeline (send K units; timeline edges cap K, cost 0; interval edges cap 1, cost -w_i), but the bitmask DP is the direct exact fix for the stated class.

4. Code

~/spill/solution.go:

// Exact minimum-weight spill set for interval interference.
package main

import (
    "bufio"
    "fmt"
    "math/bits"
    "os"
    "sort"
)

type Interval struct {
    s, e, w int
    idx     int
}

type result struct {
    cost  int
    spill uint64
}

func better(a, b result) bool {
    if a.cost != b.cost {
        return a.cost < b.cost
    }
    return a.spill > b.spill
}

var closed = true

func activeKept(e, s int) bool {
    if closed {
        return e >= s
    }
    return e > s
}

type key struct {
    i    int
    mask uint64
}

func solveExactBitmask(iv []Interval, k int) result {
    n := len(iv)
    if n == 0 {
        return result{}
    }
    order := make([]int, n)
    for i := range order {
        order[i] = i
    }
    sort.Slice(order, func(a, b int) bool {
        ia, ib := iv[order[a]], iv[order[b]]
        if ia.s != ib.s {
            return ia.s < ib.s
        }
        if ia.e != ib.e {
            return ia.e < ib.e
        }
        return ia.idx < ib.idx
    })

    active := make([]uint64, n)
    for i := 0; i < n; i++ {
        var m uint64
        ci := iv[order[i]]
        for j := 0; j < i; j++ {
            cj := iv[order[j]]
            if activeKept(cj.e, ci.s) {
                m |= 1 << uint(cj.idx-1)
            }
        }
        active[i] = m
    }

    memo := make(map[key]result, 1<<14)

    var f func(i int, mask uint64) result
    f = func(i int, mask uint64) result {
        if i == n {
            return result{}
        }
        mask &= active[i]
        kk := key{i, mask}
        if r, ok := memo[kk]; ok {
            return r
        }
        ci := iv[order[i]]
        bit := uint64(1) << uint(ci.idx-1)

        sub := f(i+1, mask)
        best := result{cost: ci.w + sub.cost, spill: sub.spill | bit}

        if bits.OnesCount64(mask)+1 <= k {
            sub = f(i+1, mask|bit)
            if better(sub, best) {
                best = sub
            }
        }
        memo[kk] = best
        return best
    }

    return f(0, 0)
}

func main() {
    in := bufio.NewReader(os.Stdin)
    out := bufio.NewWriter(os.Stdout)
    defer out.Flush()

    var n, k int
    if _, err := fmt.Fscan(in, &n, &k); err != nil {
        return
    }
    iv := make([]Interval, n)
    for i := 0; i < n; i++ {
        if _, err := fmt.Fscan(in, &iv[i].s, &iv[i].e, &iv[i].w); err != nil {
            fmt.Fprintln(os.Stderr, "bad input")
            os.Exit(1)
        }
        iv[i].idx = i + 1
    }

    res := solveExactBitmask(iv, k)

    first := true
    for i := 0; i < n; i++ {
        if res.spill&(uint64(1)<<uint(i)) != 0 {
            if !first {
                fmt.Fprint(out, " ")
            }
            fmt.Fprintf(out, "%d", i+1)
            first = false
        }
    }
    fmt.Fprintf(out, "\n%d\n", res.cost)
}

~/spill/solution_test.go verifies against exhaustive brute force (see file in the workspace; it enumerates all 2^N spill sets, checks depth at every interval endpoint, and compares both the total weight and the exact spill mask, under both closed and half-open semantics).

5. Verification

go mod init spill
gofmt -w solution.go solution_test.go
go vet ./...
go test -v

Observed:

=== RUN   TestRandomAgainstBrute
--- PASS: TestRandomAgainstBrute (9.07s)
=== RUN   TestGreedyCanBeSuboptimal
--- PASS: TestGreedyCanBeSuboptimal (0.00s)
PASS
ok      spill   9.070s

End-to-end:

printf '4 1\n3 12 6\n9 18 6\n1 10 1\n5 7 2\n' | go run .
1 3
7

Survivors [9,18] (idx 2) and [5,7] (idx 4) are disjoint, so one register suffices.

6. Summary

Evidence & signatures

# Evidence
- Problem class: go-minimum-weight-spill-set-interval-interference-exact
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-24T22:08:10.551Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "In an SSA linear-scan register allocator, given N live intervals (each with start point, end point, and spill weight) and K physical registers, compute an EXACT minimum-total-weight set of intervals to spill so the remaining intervals are K-colorable. The interference graph is an interval graph, so max-weight removal to drop the maximum clique below K is solvable by DP over intervals sorted by end point while tracking the active set at each start point in a bitmask -- the naive greedy 'spill the lowest weight live at each overflow' heuristic is provably suboptimal on instances where a heavy interval overlaps many light ones. Print the spilled interval indices in ascending order followed by the total spilled weight; break ties between equal-weight candidates by choosing the larger index first.", "environment": "go1.26", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-minimum-weight-spill-set-interval-interference-exact", "provider": "openrouter", "solved_at": "2026-09-24T22:08:10.552Z", "version": "1.26"}

Answer 2

I diagnosed the problem, implemented and verified an exact solver, and wrote the report to ~/spill/SOLUTION.md. Here is the solution:


Exact Minimum-Weight Spill Set for Interval Interference

1. Problem

We are given N live intervals. Interval i has a start point s_i, an end point e_i, and a spill weight w_i > 0, plus K physical registers. Two intervals interfere when simultaneously live. The interference graph of intervals is an interval graph, and an interval graph is K-colorable iff its maximum clique is at most K. For intervals, the maximum clique is exactly the maximum depth:

survivors are K-colorable ⇔ at every program point at most K survivors are live.

We must choose a set S of intervals to spill minimizing Σ_{i∈S} w_i subject to survivors having depth ≤ K. Print spilled indices ascending, then total spilled weight, breaking equal-weight ties by choosing the larger index first.

Input format:

N K
s_1 e_1 w_1
...
s_N e_N w_N

Overlap semantics are compiled in via closed: closed = true means [1,2] and [2,3] clash (share point 2); closed = false means half-open [1,2)/[2,3) (linear-scan convention).

2. Root-cause analysis: the greedy is not exact

The standard linear-scan heuristic sweeps by start and, on overflow, spills the lightest currently live interval. It has no lookahead and is provably suboptimal.

Witness (K = 1):

idx interval weight
1 [3, 12] 6
2 [9, 18] 6
3 [1, 10] 1
4 [5, 7] 2

Greedy: spills {3,4,1} → 1+2+6 = 9. Exact: spills {1,3} → 6+1 = 7; survivors {2,4} are disjoint. The heavy interval 1 overlaps several lights; greedy wastes cheap spills (3, then 4) protecting it and then must spill it anyway. Any local overflow decision cannot see this.

3. Exact fix

3.1 DP over the sweep with a bitmask of the active set

Process intervals in increasing start order. At interval i's start, only which retained intervals are still live matters. Let f(i, mask) be the minimum spilled weight for intervals i..N-1, where mask is the set of previously retained intervals active at s_i. For interval i:

Clear bits that die before the next start (mask &= active[i+1]). Answer f(0, ∅).

Checking depth only at start points suffices: if depth is maximal at p, let s be the largest start among intervals covering p; every such interval also covers s, so depth at start s is at least that of p.

3.2 Tie-break

Give interval j (0-based) bit value 2^j. Listing a spilled set in descending index order and comparing lexicographically is identical to comparing numeric mask values (largest differing index dominates all lower bits). So "choose the larger index first" = "prefer the larger spill mask". This is safe inside the DP because prefix/suffix spill sets are disjoint, so total value = prefix + suffix and maximizing the suffix mask is optimal for every prefix.

3.3 Complexity

Memoized state (i, active-mask): worst case O(N·2^N) time / O(2^N) states, but ended-interval bit clearing collapses states heavily in practice. For very large N, the same optimum is a min-cost flow on the timeline (send K units; timeline edges cap K, cost 0; interval edges cap 1, cost -w_i), but the bitmask DP is the direct exact fix for the stated class.

4. Code

~/spill/solution.go:

// Exact minimum-weight spill set for interval interference.
package main

import (
    "bufio"
    "fmt"
    "math/bits"
    "os"
    "sort"
)

type Interval struct {
    s, e, w int
    idx     int
}

type result struct {
    cost  int
    spill uint64
}

func better(a, b result) bool {
    if a.cost != b.cost {
        return a.cost < b.cost
    }
    return a.spill > b.spill
}

var closed = true

func activeKept(e, s int) bool {
    if closed {
        return e >= s
    }
    return e > s
}

type key struct {
    i    int
    mask uint64
}

func solveExactBitmask(iv []Interval, k int) result {
    n := len(iv)
    if n == 0 {
        return result{}
    }
    order := make([]int, n)
    for i := range order {
        order[i] = i
    }
    sort.Slice(order, func(a, b int) bool {
        ia, ib := iv[order[a]], iv[order[b]]
        if ia.s != ib.s {
            return ia.s < ib.s
        }
        if ia.e != ib.e {
            return ia.e < ib.e
        }
        return ia.idx < ib.idx
    })

    active := make([]uint64, n)
    for i := 0; i < n; i++ {
        var m uint64
        ci := iv[order[i]]
        for j := 0; j < i; j++ {
            cj := iv[order[j]]
            if activeKept(cj.e, ci.s) {
                m |= 1 << uint(cj.idx-1)
            }
        }
        active[i] = m
    }

    memo := make(map[key]result, 1<<14)

    var f func(i int, mask uint64) result
    f = func(i int, mask uint64) result {
        if i == n {
            return result{}
        }
        mask &= active[i]
        kk := key{i, mask}
        if r, ok := memo[kk]; ok {
            return r
        }
        ci := iv[order[i]]
        bit := uint64(1) << uint(ci.idx-1)

        sub := f(i+1, mask)
        best := result{cost: ci.w + sub.cost, spill: sub.spill | bit}

        if bits.OnesCount64(mask)+1 <= k {
            sub = f(i+1, mask|bit)
            if better(sub, best) {
                best = sub
            }
        }
        memo[kk] = best
        return best
    }

    return f(0, 0)
}

func main() {
    in := bufio.NewReader(os.Stdin)
    out := bufio.NewWriter(os.Stdout)
    defer out.Flush()

    var n, k int
    if _, err := fmt.Fscan(in, &n, &k); err != nil {
        return
    }
    iv := make([]Interval, n)
    for i := 0; i < n; i++ {
        if _, err := fmt.Fscan(in, &iv[i].s, &iv[i].e, &iv[i].w); err != nil {
            fmt.Fprintln(os.Stderr, "bad input")
            os.Exit(1)
        }
        iv[i].idx = i + 1
    }

    res := solveExactBitmask(iv, k)

    first := true
    for i := 0; i < n; i++ {
        if res.spill&(uint64(1)<<uint(i)) != 0 {
            if !first {
                fmt.Fprint(out, " ")
            }
            fmt.Fprintf(out, "%d", i+1)
            first = false
        }
    }
    fmt.Fprintf(out, "\n%d\n", res.cost)
}

~/spill/solution_test.go verifies against exhaustive brute force (see file in the workspace; it enumerates all 2^N spill sets, checks depth at every interval endpoint, and compares both the total weight and the exact spill mask, under both closed and half-open semantics).

5. Verification

go mod init spill
gofmt -w solution.go solution_test.go
go vet ./...
go test -v

Observed:

=== RUN   TestRandomAgainstBrute
--- PASS: TestRandomAgainstBrute (9.07s)
=== RUN   TestGreedyCanBeSuboptimal
--- PASS: TestGreedyCanBeSuboptimal (0.00s)
PASS
ok      spill   9.070s

End-to-end:

printf '4 1\n3 12 6\n9 18 6\n1 10 1\n5 7 2\n' | go run .
1 3
7

Survivors [9,18] (idx 2) and [5,7] (idx 4) are disjoint, so one register suffices.

6. Summary

Evidence & signatures

# Evidence
- Problem class: go-minimum-weight-spill-set-interval-interference-exact
- Model: openrouter/deepseek/deepseek-v4.1-flash
- Solved: 2026-09-24T22:08:10.551Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "In an SSA linear-scan register allocator, given N live intervals (each with start point, end point, and spill weight) and K physical registers, compute an EXACT minimum-total-weight set of intervals to spill so the remaining intervals are K-colorable. The interference graph is an interval graph, so max-weight removal to drop the maximum clique below K is solvable by DP over intervals sorted by end point while tracking the active set at each start point in a bitmask -- the naive greedy 'spill the lowest weight live at each overflow' heuristic is provably suboptimal on instances where a heavy interval overlaps many light ones. Print the spilled interval indices in ascending order followed by the total spilled weight; break ties between equal-weight candidates by choosing the larger index first.", "environment": "go1.26", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "go-minimum-weight-spill-set-interval-interference-exact", "provider": "openrouter", "solved_at": "2026-09-24T22:08:10.552Z", "version": "1.26"}
Generated from the verified corpus · MIT licensedBack to the catalog