Zulip Chat Archive

Stream: CSLib

Topic: formalizing reductions


Frederick Pu (Nov 18 2025 at 21:46):

I'm formalizing a reduction from 3SAT to 3DM. Right now the reduction is technically useless since we have no way of analyzing the time complexity of the reduction function. However, I think that the proof about the reduction functino being valid will be useful in the future when we are able to prove the time complexity of functions. I was wondering if there was anything similar already is in CSlib (or mathlib) and if I could get feedback on my formalism of 3SAT and 3DM as well as the reduction itself:

import Mathlib

structure CNF3 (n : Nat) where
  m : Nat
  C : Fin m  (Fin n × Bool) × (Fin n × Bool) × (Fin n × Bool)

def CNF3.sat (n : Nat) (s : CNF3 n) (x : Fin n  Bool) : Prop :=
   i : Fin s.m, let ((i, iv), (j, jv), (k, kv)) := (s.C i);
    x i == iv  x j = jv  x k = kv

def CNF3.occurances {n : Nat} (cnf : CNF3 n) (x : Fin n) : Nat :=
   i : Fin cnf.m,
    ((if (cnf.C i).1.1 == x then 1 else 0) +
    (if (cnf.C i).2.1.1 == x then 1 else 0) +
    (if (cnf.C i).2.2.1 == x then 1 else 0))

def CNF3.toOccurance₁ {n : Nat} (cnf : CNF3 n) (i : Fin cnf.m) : Fin (cnf.occurances (cnf.C i).1.1) := sorry

def CNF3.toOccurance₂ {n : Nat} (cnf : CNF3 n) (i : Fin cnf.m) : Fin (cnf.occurances (cnf.C i).2.1.1) := sorry

def CNF3.toOccurance₃ {n : Nat} (cnf : CNF3 n) (i : Fin cnf.m) : Fin (cnf.occurances (cnf.C i).2.2.1) := sorry

structure ThreeDM where
  (X Y Z : Type)
  (hX : Fintype X) (hY : Fintype Y) (hZ : Fintype Z)
  (T : Set (X × Y × Z))

def ThreeDM.sol (threedm : ThreeDM) (n : Nat) (M : Set (threedm.X × threedm.Y × threedm.Z)) : Prop :=
  M  threedm.T  M.ncard = n 
     (xyz : threedm.X × threedm.Y × threedm.Z), xyz  M  ∃! xyz'  M, xyz.1 = xyz'.1  xyz.2.1 = xyz'.2.1  xyz.2.2 = xyz'.2.2

namespace ThreeDM

inductive ValueZ {n : Nat} (cnf : CNF3 n) where
| true (i : Fin n) (occ : Fin (cnf.occurances i)) : ValueZ cnf
| false (i : Fin n) (occ : Fin (cnf.occurances i)) : ValueZ cnf
deriving Fintype

inductive GroundingX {n : Nat} (cnf : CNF3 n) where
| valueGadget (i : Fin n) (occ : Fin (cnf.occurances i)) : GroundingX cnf
| clauseGadget (clause : Fin cnf.m) : GroundingX cnf
-- every clause needs `(3 - 1) = 2` garbage collectors (each clause is responsible for 3 variables each of which has one unaccounted for value (after value gadget), and only one value gets accounted for by clause gadget)
| garbageGadget (clause : Fin cnf.m) (garbageIdx : Fin 2) : GroundingX cnf
deriving Fintype


inductive GroundingY {n : Nat} (cnf : CNF3 n) where
| valueGadget (i : Fin n) (occ : Fin (cnf.occurances i)) : GroundingY cnf
| clauseGadget (clause : Fin cnf.m) : GroundingY cnf
-- every clause needs `(3 - 1) = 2` garbage collectors (each clause is responsible for 3 variables each of which has one unaccounted for value (after value gadget), and only one value gets accounted for by clause gadget)
| garbageGadget (clause : Fin cnf.m) (garbageIdx : Fin 2) : GroundingY cnf
deriving Fintype

#check Set.range

/-
  if (N x) is the number of clauses containing variable $x$ then each variable will require nodes 4(N x) for the variable gadget.
  we will also need an additional 2 * (num clauses) for the clause gadgets
  and 2 * (num remaining T or F), each clause will only use one T or F, the total number of T or F is ∑ 2(N x) so we will need ∑ 2(N x) - (num clauses) garbage gadgets.
  this gives a total of
  `(∑ 4(N x)) + 2 s.m +  (∑ 2(N x)) - s.m = 6 ∑ N x + s.m`
  but `∑ N x = 3 * (num clauses)`
  so we get `6 * (3 * s.m) + s.m = 19 * s.m`

  now for picking which nodes go in which sets. Note that in any gadget each throuple will consist of one point representing a value (T or F) and the other two points being used to link to other throuples in the gadget.
  Thus, we can think of  `Z` as being the value set and `X, Y` being the grounding types
-/
theorem threesat_reduction_threedm (n : Nat) (cnf : CNF3 n) :
     threedm : ThreeDM, ( x, cnf.sat n x)   M, threedm.sol (19 * cnf.m) M := by
{
  let threedm : ThreeDM := {
    X := GroundingX cnf,
    Y := GroundingY cnf,
    Z := ValueZ cnf,
    hX := inferInstance,
    hY := inferInstance,
    hZ := inferInstance,
    T :=
      let valueGadgetTrue : Set (GroundingX cnf × GroundingY cnf × ValueZ cnf) :=
        Set.range (fun (i, occ : Σ (i : Fin n), (Fin (cnf.occurances i))) => (.valueGadget i occ, .valueGadget i occ, .true i occ) )
      let valueGadgetFalse : Set (GroundingX cnf × GroundingY cnf × ValueZ cnf) :=
        Set.range (fun (i, occ : Σ (i : Fin n), (Fin (cnf.occurances i))) => (.valueGadget i occ, .valueGadget i occ, .false i occ) )
      let valueGadget := valueGadgetTrue  valueGadgetFalse

      let clauseGadget₁ : Set (GroundingX cnf × GroundingY cnf × ValueZ cnf) := Set.range (
        fun (i : Fin cnf.m) =>
          (.clauseGadget i,
           .clauseGadget i,
           if (cnf.C i).1.2 then
            .true (cnf.C i).1.1 (cnf.toOccurance₁ i)
          else
            .false (cnf.C i).1.1 (cnf.toOccurance₁ i)))
      let clauseGadget₂ : Set (GroundingX cnf × GroundingY cnf × ValueZ cnf) := Set.range (
        fun (i : Fin cnf.m) =>
        (.clauseGadget i,
         .clauseGadget i,
         if (cnf.C i).2.1.2 then
          .true (cnf.C i).2.1.1 (cnf.toOccurance₂ i)
        else
          .false (cnf.C i).2.1.1 (cnf.toOccurance₂ i)))
      let clauseGadget₃ : Set (GroundingX cnf × GroundingY cnf × ValueZ cnf) := Set.range (
        fun (i : Fin cnf.m) =>
        (.clauseGadget i,
         .clauseGadget i,
         if (cnf.C i).2.2.2 then
          .true (cnf.C i).2.2.1 (cnf.toOccurance₃ i)
        else
          .false (cnf.C i).2.2.1 (cnf.toOccurance₃ i)))
      let clauseGadget := clauseGadget₁  clauseGadget₂  clauseGadget₃

      -- for every clause and every variable attached to that clause, the point for tha variables at that clause is connected to both garbage collectors
      let garbageGadget₁ : Set (GroundingX cnf × GroundingY cnf × ValueZ cnf) := Set.range (
        fun (i : Fin cnf.m) =>
        (.garbageGadget i 0,
         .garbageGadget i 0,
         if (cnf.C i).1.2 then
            .true (cnf.C i).1.1 (cnf.toOccurance₁ i)
          else
            .false (cnf.C i).1.1 (cnf.toOccurance₁ i))
      )  Set.range (
        fun (i : Fin cnf.m) =>
        (.garbageGadget i 1,
         .garbageGadget i 1,
         if (cnf.C i).1.2 then
            .true (cnf.C i).1.1 (cnf.toOccurance₁ i)
          else
            .false (cnf.C i).1.1 (cnf.toOccurance₁ i))
      )
      let garbageGadget₂ : Set (GroundingX cnf × GroundingY cnf × ValueZ cnf) := Set.range (
        fun (i : Fin cnf.m) =>
        (.garbageGadget i 0,
         .garbageGadget i 0,
         if (cnf.C i).2.1.2 then
          .true (cnf.C i).2.1.1 (cnf.toOccurance₂ i)
        else
          .false (cnf.C i).2.1.1 (cnf.toOccurance₂ i)))  Set.range (
        fun (i : Fin cnf.m) =>
        (.garbageGadget i 1,
         .garbageGadget i 1,
         if (cnf.C i).2.1.2 then
          .true (cnf.C i).2.1.1 (cnf.toOccurance₂ i)
        else
          .false (cnf.C i).2.1.1 (cnf.toOccurance₂ i)))
      let garbageGadget₃ : Set (GroundingX cnf × GroundingY cnf × ValueZ cnf) := Set.range (
        fun (i : Fin cnf.m) =>
        (.garbageGadget i 0,
         .garbageGadget i 0,
         if (cnf.C i).2.2.2 then
          .true (cnf.C i).2.2.1 (cnf.toOccurance₃ i)
        else
          .false (cnf.C i).2.2.1 (cnf.toOccurance₃ i)))  Set.range (
        fun (i : Fin cnf.m) =>
        (.garbageGadget i 1,
         .garbageGadget i 1,
         if (cnf.C i).2.2.2 then
          .true (cnf.C i).2.2.1 (cnf.toOccurance₃ i)
        else
          .false (cnf.C i).2.2.1 (cnf.toOccurance₃ i)))
      let garbageGadget : Set (GroundingX cnf × GroundingY cnf × ValueZ cnf) := garbageGadget₁  garbageGadget₂  garbageGadget₃
      valueGadget  clauseGadget  garbageGadget

  }
  sorry
}

Frederick Pu (Nov 18 2025 at 21:46):

PS, im basing this off of the MIT open courseware lecture: https://www.youtube.com/watch?v=eHZifpgyH_4&t=2786s

Nadim Farhat (Nov 20 2025 at 17:26):

not sure whats the overlap but early on the idea was to formalize this book https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/ , also found this https://github.com/leanprover/cslib/blob/main/CslibTests/ReductionSystem.lean

Frederick Pu (Nov 21 2025 at 16:58):

does this formalize a notion of runtime complexity too?


Last updated: Dec 20 2025 at 21:32 UTC