Skip to content

[Rule] PARTITION to MINIMUM SUM OF SQUARES #393

@isPANN

Description

@isPANN

Source: Partition
Target: SumOfSquaresPartition
Motivation: Establishes NP-hardness of SumOfSquaresPartition from Partition (one of Karp's 21). The reduction is Garey & Johnson SP19's textbook construction restricted to K = 2: among all 2-way partitions of A, the sum of squared group sums is minimized when the two groups have equal sums (S/2 each), giving minimum S²/2. Hence Partition is YES iff the minimum sum of squares is ⌈S²/2⌉ (equivalently, ≤ S²/2 when S is even).
Reference: Garey & Johnson, Computers and Intractability, SP19, p. 225.

GJ Source Entry

[SP19] MINIMUM SUM OF SQUARES
INSTANCE: Finite set A, a size s(a) in Z^+ for each a in A, positive integers K<=|A| and J.
QUESTION: Can A be partitioned into K disjoint sets A_1,A_2,...,A_K such that
Sum_{i=1}^{K}(Sum_{a in A_i} s(a))^2 <= J ?
Reference: Transformation from PARTITION or 3-PARTITION.
Comment: NP-complete in the strong sense. NP-complete in the ordinary sense and solvable in pseudo-polynomial time for any fixed K. Variants in which the bound K on the number of sets is replaced by a bound B on either the maximum set cardinality or the maximum total set size are also NP-complete in the strong sense [Wong and Yao, 1976].

Codebase Note: Why This Is a Witness Reduction (No J Field)

The SumOfSquaresPartition model in this codebase is a pure minimization problem with Value = Min<i64> and fields (sizes, num_groups). There is no J bound field and no Decision<SumOfSquaresPartition> registered. So the reduction is implemented in the same witness-style form as partition_multiprocessorscheduling.rs:

  • The target SumOfSquaresPartition instance encodes the construction (identical sizes, K = 2).
  • ReductionResult::extract_solution is the identity (the group assignment is a valid Partition subset assignment).
  • The closed-loop test relies on source.evaluate(extracted_config)Partition::evaluate already returns Or(true) exactly when the config splits the sum in half. The bound J = S²/2 is therefore an implicit property of the optimal target witness, not a stored field.

This matches the precedent set by partition_multiprocessorscheduling.rs and other Partition → ... reductions where the target is constructed to make Partition's YES/NO answer recoverable from source.evaluate(extract_solution(target_witness)).

(A separate follow-up issue may introduce Decision<SumOfSquaresPartition> with an explicit J bound; this issue does not depend on that.)

Reduction Algorithm

Given a Partition instance with sizes A = {s_1, ..., s_n} (s_i > 0, source Value = Or), construct a SumOfSquaresPartition (Value = Min<i64>) as follows:

  1. Guard small instances. If n < 2 (i.e. K = 2 > n would violate SumOfSquaresPartition's constructor invariant num_groups ≤ num_elements), emit a sentinel target SumOfSquaresPartition::new(vec![1, 1], 2) and remember source_n. extract_solution returns vec![0; source_n], on which Partition::evaluate returns Or(false) — the correct YES/NO answer because a single positive element cannot be split into two equal-sum groups (and Partition::new already rejects n = 0).
  2. Normal case (n ≥ 2). Cast each s_i: u64 to i64 (sizes in Partition are bounded by u64::MAX; in practice all canonical examples and reductions in this repo use values well within i64::MAX). Construct target = SumOfSquaresPartition::new(sizes_i64, 2).
  3. Witness extraction. extract_solution(target_config) = target_config.to_vec() when its length equals source_n; otherwise (sentinel case) vec![0; source_n].

Why this works (G&J SP19 specialized to K=2). Let S = Σ s_i and let S_1, S_2 be the two group sums under a 2-partition (S_1 + S_2 = S). Then
S_1² + S_2² = (S_1 + S_2)² − 2 S_1 S_2 = S² − 2 S_1 S_2,
which is minimized when S_1 S_2 is maximized, i.e. when S_1 = S_2 = S/2. The minimum is S²/2 (achievable iff S is even and a balanced subset exists).

So:

  • Partition YES ⇔ some 2-partition of A has S_1 = S_2min Σ (group_sum)² = S²/2 ⇔ the target's optimal witness is a balanced split ⇔ Partition::evaluate(extracted_witness) = Or(true).
  • Partition NO ⇔ every 2-partition has S_1 ≠ S_2 ⇔ target's optimum strictly exceeds S²/2 ⇔ the optimal witness is unbalanced ⇔ Partition::evaluate(extracted_witness) = Or(false).

This is the standard test pattern used by test_partition_to_multiprocessorscheduling_solution_extraction.

Size Overhead

Symbols:

  • num_elements = |A| (getter on Partition).
Target metric (code name) Polynomial expression
num_elements num_elements
num_groups 2

(Field names match SumOfSquaresPartition's size_fields = ["num_elements", "num_groups"]. The macro overhead validator will reject any other name.)

Construction is O(n) time and O(n) space.

Validation Method

  • Closed-loop test (balanced even-sum case). Input Partition::new(vec![3, 1, 1, 2, 2, 1]) (n=6, S=10). Expected: target optimal min = 50 = S²/2; Partition::evaluate(extracted_witness) = Or(true).
  • Closed-loop test (odd-sum NO case). Input Partition::new(vec![2, 4, 5]) (n=3, S=11). Expected: target optimal min > 60.5 (in fact = 61 = 5² + 6² for split {5},{2,4}); Partition::evaluate(extracted_witness) = Or(false).
  • Closed-loop test (even-sum but unbalanced NO case). Input Partition::new(vec![1, 1, 1, 5]) (n=4, S=8). No balanced subset (smallest gap is {5} vs {1,1,1} giving 5 vs 3). Expected: target min > 32; extracted witness fails Partition::evaluate.
  • Singleton corner case. Input Partition::new(vec![5]) (n=1). Sentinel path triggers; extract_solution returns [0]; Partition::evaluate([0]) = Or(false).
  • Structure tests. For each non-sentinel input, assert target.sizes() == source.sizes().map(i64::from), target.num_groups() == 2, target.num_elements() == source.num_elements().

Example

Source (Partition): A = {3, 1, 1, 2, 2, 1} (n = 6, S = 10).
A balanced partition requires each half to sum to S/2 = 5.

Constructed target (SumOfSquaresPartition):

  • sizes = [3, 1, 1, 2, 2, 1] (as Vec<i64>),
  • num_groups = 2.
  • (No J field — the bound S²/2 = 50 is an implicit property of the optimum.)

Optimal target witness (one of several): [0, 1, 1, 0, 1, 1] → group 0 sums to 3+2 = 5, group 1 sums to 1+1+2+1 = 5. Target value: 5² + 5² = 50 = S²/2.

Source-side check: Partition::evaluate([0, 1, 1, 0, 1, 1]) = Or(5+5 == 10) = Or(true). ✓

Imbalanced comparison. Witness [0, 0, 0, 1, 0, 0] → groups {3,1,1,2,1} (sum 8) vs {2} (sum 2). Target value: 64 + 4 = 68 > 50. Source-side: Partition::evaluate([0,0,0,1,0,0]) = Or(2 ≠ 8) = Or(false). Confirms only balanced splits achieve the optimum.

Singleton sentinel. Partition::new(vec![5]) → sentinel target SumOfSquaresPartition::new(vec![1,1], 2). extract_solution(any) = [0] (length matches source_n = 1). Partition::evaluate([0]) = Or(false) — correct.

References

  • Garey, M. R. and Johnson, D. S. (1979). Computers and Intractability: A Guide to the Theory of NP-Completeness, problem SP19, p. 225. W. H. Freeman.
  • C. K. Wong and A. C. Yao (1976). "A combinatorial optimization problem related to data set allocation." Revue Française d'Automatique, Informatique, Recherche Opérationnelle, Sér. Bleue 10(suppl.), pp. 83–95.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GoodAn issue passed all checks.ruleA new reduction rule to be added.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions