@@ -237,6 +237,40 @@ def Cache.init (aig : AIG α) : Cache aig .empty where
237237 hmarks := by simp
238238 inv := Inv_init
239239
240+ /--
241+ Reuse a `Cache` for an `AIG` that extends the original one. This is useful for incrementally
242+ generating CNF formulas for AIGs.
243+ -/
244+ -- Nospecialize as the type classes are not used at runtime so any specialization here is pointless
245+ @[nospecialize]
246+ def Cache.cast {aig1 aig2 : AIG α} (cache : Cache aig1 cnf)
247+ (hprefix : IsPrefix aig1.decls aig2.decls) : Cache aig2 cnf :=
248+ -- Crucial: never refer to `aig1` here so it can be erased at runtime.
249+ have hsize := hprefix.size_le
250+ have hmarks := cache.hmarks
251+ {
252+ marks := cache.marks ++ Array.replicate (aig2.decls.size - cache.marks.size) false
253+ hmarks := by simp; omega
254+ inv := by
255+ intro assign heval idx hbound hmarked
256+ have hidx : idx < aig1.decls.size := by
257+ apply Classical.byContradiction
258+ intro hnot
259+ have : cache.marks.size ≤ idx := by omega
260+ simp [Array.getElem_append_right this] at hmarked
261+ rw [Array.getElem_append_left (by omega)] at hmarked
262+ have h1 := cache.inv assign heval idx hidx hmarked
263+ rw [denote.eq_of_isPrefix ⟨aig1, ⟨idx, false , hidx⟩⟩ aig2 hprefix, ← h1]
264+ apply denote_congr
265+ intro a hmem
266+ rw [mem_def] at hmem
267+ rcases Array.getElem_of_mem hmem with ⟨i, hi, hia⟩
268+ have h2 : aig2.decls[i]'(by omega) = .atom a := by
269+ rw [hprefix.idx_eq i hi]
270+ exact hia
271+ rw [projectLeftAssign_atom h2, projectLeftAssign_atom hia]
272+ }
273+
240274/--
241275Add a `Decl.false` to a `Cache`.
242276-/
@@ -371,11 +405,17 @@ def Cache.addIte (cache : Cache aig cnf) {cond ifTrue ifFalse : Fanin} (idx : Na
371405 ⟨out, IsExtensionBy_set cache out idx hmarkbound (by simp [out])⟩
372406
373407/--
374- The key invariant about the `State` itself (without cache): The CNF we produce is always satisfiable
375- at `cnfSatAssignment`.
408+ The key invariant about the `State` itself (without cache):
409+ The CNF we produce is always satisfied by any assignment that evaluates the AIG at the variable
410+ of each node, in particular by `cnfSatAssignment`.
411+
412+ Note that this definition leaves variables that do not occur in the AIG unconstrained so that the
413+ CNF can be reused for an AIG that extends the current one.
376414-/
377415def State.Inv (aig : AIG α) (cnf : CNF Nat) : Prop :=
378- ∀ (assign1 : α → Bool), cnf.Sat (cnfSatAssignment aig assign1)
416+ ∀ (assign1 : α → Bool) (assign : Nat → Bool),
417+ (∀ (idx : Nat) (h : idx < aig.decls.size), assign idx = ⟦aig, ⟨idx, false , h⟩, assign1⟧) →
418+ cnf.Sat assign
379419
380420/--
381421The `State` invariant always holds when we have an empty CNF.
@@ -388,9 +428,9 @@ Combining two CNFs for which `State.Inv` holds preserves `State.Inv`.
388428-/
389429theorem State.Inv_append (h1 : State.Inv aig cnf1) (h2 : State.Inv aig cnf2) :
390430 State.Inv aig (cnf1 ++ cnf2) := by
391- intro assign1
392- specialize h1 assign1
393- specialize h2 assign1
431+ intro assign1 assign hagree
432+ specialize h1 assign1 assign hagree
433+ specialize h2 assign1 assign hagree
394434 simp [CNF.sat_def] at h1 h2 ⊢
395435 constructor <;> assumption
396436
@@ -400,22 +440,24 @@ theorem State.Inv_append (h1 : State.Inv aig cnf1) (h2 : State.Inv aig cnf2) :
400440theorem State.Inv_falseToCNF {upper : Nat} {h : upper < aig.decls.size}
401441 (heq : aig.decls[upper] = .false ) :
402442 State.Inv aig (Decl.falseToCNF upper) := by
403- intro assign1
404- simp [CNF.sat_def, denote_idx_false heq, h ]
443+ intro assign1 assign hagree
444+ simp [CNF.sat_def, hagree upper h, denote_idx_false heq ]
405445
406446/--
407447`State.Inv` holds for the CNF that we produce for a `Decl.gate`
408448-/
409449theorem State.Inv_gateToCNF {aig : AIG α} {h}
410450 (heq : aig.decls[upper]'h = .gate lhs rhs) :
411451 State.Inv aig (Decl.gateToCNF upper lhs.gate rhs.gate lhs.invert rhs.invert) := by
412- intro assign1
452+ intro assign1 assign hagree
413453 have hlhs : lhs.gate < aig.decls.size := Nat.lt_trans (aig.hdag h heq).left h
414454 have hrhs : rhs.gate < aig.decls.size := Nat.lt_trans (aig.hdag h heq).right h
415455 generalize hlinv : lhs.invert = linv
416456 generalize hrinv : rhs.invert = rinv
417457 rw [CNF.sat_def]
418- cases linv <;> cases rinv <;> simp [denote_idx_gate heq, hlinv, hrinv, h, hlhs, hrhs]
458+ cases linv <;> cases rinv
459+ <;> simp [denote_idx_gate heq, hlinv, hrinv, hagree upper h, hagree lhs.gate hlhs,
460+ hagree rhs.gate hrhs]
419461
420462/--
421463`State.Inv` holds for the CNF that we produce for an ITE.
@@ -429,9 +471,9 @@ theorem State.Inv_iteToCNF {aig : AIG α} {cond ifTrue ifFalse : Fanin} {idx : N
429471 ⟦aig, ⟨ifTrue.gate, ifTrue.invert, by omega⟩, assign⟧
430472 ⟦aig, ⟨ifFalse.gate, ifFalse.invert, by omega⟩, assign⟧) :
431473 State.Inv aig (Decl.iteToCNF idx cond.gate ifTrue.gate ifFalse.gate cond.invert ifTrue.invert ifFalse.invert) := by
432- intro assign1
433- rw [CNF.sat_def, Decl.iteToCNF_eval, satAssignment_lt h, hdenote, satAssignment_lt (by omega),
434- satAssignment_lt (by omega), satAssignment_lt (by omega)]
474+ intro assign1 assign hagree
475+ rw [CNF.sat_def, Decl.iteToCNF_eval, hagree idx h, hdenote, hagree cond.gate (by omega),
476+ hagree ifTrue.gate (by omega), hagree ifFalse.gate (by omega)]
435477 have {fi : Fanin} {aig : AIG α} {h} {assign : α → Bool} :
436478 ⟦aig, ⟨fi.gate, fi.invert, h⟩, assign⟧ = (⟦aig, ⟨fi.gate, false , h⟩, assign⟧ ^^ fi.invert) := by
437479 cases fi.invert <;> simp
@@ -462,6 +504,22 @@ def State.empty (aig : AIG α) : State aig where
462504 cache := Cache.init aig
463505 inv := State.Inv_nil
464506
507+ /--
508+ Reuse a `State` for an `AIG` that extends the original one, see `Cache.cast`.
509+ -/
510+ -- Nospecialize as the type classes are not used at runtime so any specialization here is pointless
511+ @[nospecialize]
512+ def State.cast {aig1 aig2 : AIG α} (state : State aig1) (hprefix : IsPrefix aig1.decls aig2.decls) :
513+ State aig2 where
514+ cnf := state.cnf
515+ cache := state.cache.cast hprefix
516+ inv := by
517+ intro assign1 assign hagree
518+ apply state.inv assign1 assign
519+ intro idx h
520+ rw [hagree idx (by have := hprefix.size_le; omega)]
521+ exact denote.eq_of_isPrefix ⟨aig1, ⟨idx, false , h⟩⟩ aig2 hprefix
522+
465523/--
466524State extension are `Cache.IsExtensionBy` for now.
467525-/
@@ -795,7 +853,8 @@ The CNF returned by `go` will always be SAT at `cnfSatAssignment`.
795853theorem toCNF.go_sat (aig : AIG α) (start : Nat) (h1 : start < aig.decls.size) (assign1 : α → Bool)
796854 (state : toCNF.State aig) :
797855 (go aig start h1 state).val.Sat (cnfSatAssignment aig assign1) := by
798- have := (go aig start h1 state).val.inv assign1
856+ have := (go aig start h1 state).val.inv assign1 (cnfSatAssignment aig assign1)
857+ (fun _ h => satAssignment_lt h)
799858 rw [State.sat_iff]
800859 simp [this]
801860
0 commit comments