Imports
Fixed-width binary blocks for the SUBSET-SUM reduction
The mathematical reduction packs small column digits in a power-of-two radix. This file exposes the same number as a concrete list of fixed-width binary blocks, followed by a streaming canonicalization pass. It is the semantic interface used by the reduction machine: no general multiplication or exponentiation routine is needed at runtime.
namespace CLRS.Chapter34.SubsetSumReduction
A little-endian, zero-padded binary block of exactly blockWidth cells
whenever digit < 2 ^ blockWidth.
def fixedBinaryBlock (blockWidth digit : Nat) : List Bool :=
(Nat.digitsAppend 2 blockWidth digit).map fun value => decide (value = 1)
theorem fixedBinaryBlock_toNat {blockWidth digit : Nat} :
(fixedBinaryBlock blockWidth digit).map Bool.toNat =
Nat.digitsAppend 2 blockWidth digit := by
simp only [fixedBinaryBlock, List.map_map]
have hmaps : List.map
(Bool.toNat ∘ fun value => decide (value = 1))
(Nat.digitsAppend 2 blockWidth digit) =
List.map id (Nat.digitsAppend 2 blockWidth digit) := by
apply List.map_congr_left
intro value hvalue
have hlt : value < 2 :=
Nat.lt_of_mem_digitsAppend (by omega) blockWidth value hvalue
interval_cases value <;> decide
simpa only [List.map_id] using hmapstheorem fixedBinaryBlock_length {blockWidth digit : Nat}
(hdigit : digit < 2 ^ blockWidth) :
(fixedBinaryBlock blockWidth digit).length = blockWidth := by
simp [fixedBinaryBlock, Nat.length_digitsAppend (by omega) _ hdigit]
theorem fixedBinaryBlock_value {blockWidth digit : Nat}
(hdigit : digit < 2 ^ blockWidth) :
Nat.ofDigits 2 ((fixedBinaryBlock blockWidth digit).map Bool.toNat) =
digit := by
rw [fixedBinaryBlock_toNat]
exact (Nat.setInvOn_digitsAppend_ofDigits (by omega) blockWidth).2 hdigitLittle-endian concatenation of all fixed-width column blocks.
def packedBitsLE (blockWidth : Nat) : Nat → (Nat → Nat) → List Bool
| 0, _ => []
| width + 1, digits =>
fixedBinaryBlock blockWidth (digits 0) ++
packedBitsLE blockWidth width (fun column => digits (column + 1))@[simp] theorem packedBitsLE_zero (blockWidth : Nat) (digits : Nat → Nat) :
packedBitsLE blockWidth 0 digits = [] := rfl@[simp] theorem packedBitsLE_succ (blockWidth width : Nat)
(digits : Nat → Nat) :
packedBitsLE blockWidth (width + 1) digits =
fixedBinaryBlock blockWidth (digits 0) ++
packedBitsLE blockWidth width (fun column => digits (column + 1)) := rfl
theorem packedBitsLE_length {blockWidth width : Nat}
{digits : Nat → Nat}
(hdigits : ∀ column < width, digits column < 2 ^ blockWidth) :
(packedBitsLE blockWidth width digits).length = blockWidth * width := by
induction width generalizing digits with
| zero => simp
| succ width ih =>
rw [packedBitsLE_succ, List.length_append,
fixedBinaryBlock_length (hdigits 0 (by omega)),
ih (fun column hcolumn => hdigits (column + 1) (by omega))]
simp [Nat.mul_succ, Nat.add_comm]
theorem packedBitsLE_value {blockWidth width : Nat}
{digits : Nat → Nat}
(hdigits : ∀ column < width, digits column < 2 ^ blockWidth) :
Nat.ofDigits 2 ((packedBitsLE blockWidth width digits).map Bool.toNat) =
packColumns (2 ^ blockWidth) width digits := by
induction width generalizing digits with
| zero => simp
| succ width ih =>
rw [packedBitsLE_succ, List.map_append, Nat.ofDigits_append,
fixedBinaryBlock_value (hdigits 0 (by omega)), List.length_map,
fixedBinaryBlock_length (hdigits 0 (by omega)),
ih (fun column hcolumn => hdigits (column + 1) (by omega))]
rflRemove big-endian leading zeroes, using the unique one-bit encoding for zero. A fixed two-state streaming controller implements this function.
def canonicalizeBinaryBits : List Bool → List Bool
| [] => [false]
| false :: bits => canonicalizeBinaryBits bits
| true :: bits => true :: bits
theorem canonicalizeBinaryBits_value (bits : List Bool) :
binaryNatValue (canonicalizeBinaryBits bits) = binaryNatValue bits := by
induction bits with
| nil => simp [canonicalizeBinaryBits, binaryNatValue]
| cons bit bits ih =>
cases bit
· rw [canonicalizeBinaryBits, ih]
simp [binaryNatValue, List.reverse_cons, Nat.ofDigits_append]
· rfltheorem canonicalizeBinaryBits_isCanonical (bits : List Bool) :
isCanonicalBinaryNat (canonicalizeBinaryBits bits) = true := by
induction bits with
| nil => simp [canonicalizeBinaryBits, isCanonicalBinaryNat]
| cons bit bits ih =>
cases bit
· simpa [canonicalizeBinaryBits] using ih
· simp [canonicalizeBinaryBits, isCanonicalBinaryNat]
theorem canonicalizeBinaryBits_eq_encode (bits : List Bool) :
canonicalizeBinaryBits bits = encodeBinaryNat (binaryNatValue bits) := by
symm
apply encodeBinaryNat_of_decode_eq_some
rw [decodeBinaryNat_eq_some_iff]
exact ⟨canonicalizeBinaryBits_isCanonical bits,
canonicalizeBinaryBits_value bits⟩Canonical big-endian encoding obtained from fixed-width little-endian column blocks.
def encodePackedColumns (blockWidth width : Nat)
(digits : Nat → Nat) : List Bool :=
canonicalizeBinaryBits (packedBitsLE blockWidth width digits).reverse
theorem encodePackedColumns_eq {blockWidth width : Nat}
{digits : Nat → Nat}
(hdigits : ∀ column < width, digits column < 2 ^ blockWidth) :
encodePackedColumns blockWidth width digits =
encodeBinaryNat (packColumns (2 ^ blockWidth) width digits) := by
rw [encodePackedColumns, canonicalizeBinaryBits_eq_encode]
congr 1
simp only [binaryNatValue, List.reverse_reverse]
exact packedBitsLE_value hdigitsBit-block target stream for a formula.
def reductionTargetBits (formula : CNF) : List Bool :=
encodePackedColumns (reductionBlockWidth formula)
(reductionWidth formula) (targetDigit formula)Bit-block value stream for one generated item.
def reductionItemBits (formula : CNF) (item : SubsetSumItem) : List Bool :=
encodePackedColumns (reductionBlockWidth formula)
(reductionWidth formula) (itemDigit formula item)
theorem reductionTargetBits_eq (formula : CNF) :
reductionTargetBits formula = encodeBinaryNat (reductionTarget formula) := by
rw [reductionTargetBits, reductionTarget, reductionBase]
exact encodePackedColumns_eq
(fun column _ => targetDigit_lt_reductionBase formula column)
theorem reductionItemBits_eq {formula : CNF}
(hthree : IsThreeCNF formula) (item : SubsetSumItem) :
reductionItemBits formula item = encodeBinaryNat (itemValue formula item) := by
rw [reductionItemBits, itemValue, reductionBase]
apply encodePackedColumns_eq
intro column _
have hdigit := itemDigit_le_three hthree item column
have hbase : 4 < 2 ^ reductionBlockWidth formula := by
simpa [reductionBase] using four_lt_reductionBase formula
omegaend CLRS.Chapter34.SubsetSumReduction