IC3/PDR: Invariants Found by the Tool

Swap one engine line and watch PDR prove what k-induction could not, by building the helper invariant itself, one clause at a time.

Lesson
F2.5
Time
20 min
Runs on
SymbiYosys
Check
4 questions

A FIFO scoreboard property timed out in BMC on every SMT solver the team had, and induction stayed UNKNOWN through two days of helper writing. Someone changed one line of the task file to abc pdr. The proof came back in under two seconds, with no helpers at all.

Frames Instead of Copies

Frames Instead of CopiesPDR keeps a short chain of state sets. Each over-approximates what is reachable in that many steps and excludes every bad state.
Frames instead of copiesPDR keeps a short chain of state sets. Each over-approximates what is reachable in that many steps and excludes every bad state. frame F0 the initial states frame F1 reachable in ≤ 1step, or more frame Fk reachable in ≤ ksteps, or more property Bad states every Fi must excludethem cube Cube s a state in Fk with astep into Bad clause Clause ¬s learned, then pushedforward ⊆⊆one step?yes: take sunreachable fromFk-1
  1. Ask one step

    Can a state in Fk step into a bad state? One SAT query on one copy of the logic, never an unrolled strip.

  2. Take the cube

    If yes, the solver hands back such a state s, as a cube: a few state bits fixed.

  3. Block it relative to Fk-1

    Show that no state in Fk-1 steps into s. Then ¬s is a new clause for Fk, generalized to cover more states. If that fails, recurse backwards; reaching F0 is a real counterexample.

  4. Converge

    Clauses are pushed forward frame by frame. When two neighbouring frames become equal, that frame is an inductive invariant and the property is proven.

Read the diagram as text
  • F0: the initial states
  • F1: reachable in ≤ 1 step, or more
  • Fk: reachable in ≤ k steps, or more
  • Bad states: every Fi must exclude them
  • Cube s: a state in Fk with a step into Bad
  • Clause ¬s: learned, then pushed forward
  • F0 → F1: ⊆
  • F1 → Fk: ⊆
  • Fk → Bad states: one step?
  • Fk → Cube s: yes: take s
  • Cube s → Clause ¬s: unreachable from Fk-1

IC3 (Bradley 2011); PDR is the ABC implementation (Eén, Mishchenko, Brayton 2011). Drawn, not measured.

IC3 never unrolls. It keeps frames F0 to Fk. F0 is the initial states. Each later frame is a set of clauses, small lemmas about the state, that every state reachable in that many steps satisfies. Every frame excludes the bad states.

The Same FIFO, One Engine Line Changed

TaskEngineMeasured resultTime
fifo16, no helpers, depth 12smtbmc yicesUNKNOWN0.5 s
fifo16, no helpersabc pdrPASS1.5 s
fifo16, two helpers, depth 2smtbmc yicesPASS0.5 s

Whole-task time on this machine. PDR has no depth: the runner passes one, and PDR ignores it.

k-induction only has the property and a window of k states. PDR strengthens the property itself until it is inductive. Each clause it learns is a tiny helper invariant, proven relative to the frame before it. That is why it needs none from you on finite control logic.

The Invariant It Found

Measured: abc pdr -d wrote 220 clauses over 18 latch bits. The first 8 are shown.
.i 18
.o 1
.p 220
---------------1-0 1
---------------11- 1
-------------11--- 1
------------1-1--- 1
-----------1--1--- 1
----------1---1--- 1
----0----0----1--- 1
----0----100000--- 1
...

Each row is one lemma over the latch bits: 0 or 1 where it tests a bit, - where it ignores one. The 18 bits are the two 5-bit pointers and the 5-bit count, two flops that sample the assertion, and the first-step latch. The memory is gone: no property reads it.

Your two helpers say the same thing in two lines. PDR says it in 220 bit-level lemmas. The count changes from run to run, because ABC's PDR uses internal time limits. In this run the log reached frame 36 and ended with "Proved output 0 in frame 1 (converged)."

Its Counterexamples Start at Reset

012345678910111213141516171819202122clkfreerstfreewrfreerdcountwr_ptr01234567891011121314151617rd_ptr012345678910111213141501empty

Measured abc pdr trace for the buggy FIFO. Step 0 is reset; the failure is sampled at 21 and reported at 22.

PDR reports a failure only after tracing a bad cube back to F0, so its traces are real counterexamples from reset. They need not be the shortest: on this bug PDR reported step 22, while BMC at depth 20 reported step 19.

Where It Shines, and Where It Stalls

Four-entry FIFO scoreboardMeasured resultTime
bmc, depth 20, smtbmc yicestime limit, no verdict20.1 s
bmc, depth 20, smtbmc boolectortime limit, no verdict20.1 s
bmc, depth 20, smtbmc bitwuzlatime limit, no verdict20.1 s
bmc, depth 20, smtbmc z3time limit, no verdict20.1 s
prove, depth 20, smtbmc yicestime limit, no verdict20.1 s
prove, abc pdrPASS1.8 s

The engine study FIFO with its own queue model (F4.4 builds it). A time limit claims nothing about the property.

PDR works on the bit-level AIGER. Wide arithmetic becomes thousands of gates, and there it can stall where word-level induction with a helper finishes quickly. F2.6 measures one such case.

Asked in Interviews

QuestionAnswer
What does IC3/PDR do differently from induction?No unrolling. It builds an inductive strengthening of the property from relatively inductive clauses kept in frames.
Why do its counterexamples never start in unreachable states?It reports a failure only after tracing a bad state back to the initial states.
When would you not use PDR?On wide datapaths, where bit-blasting hurts and word-level induction with a helper is faster.

Try It

The lab runs fifo16 without helpers under abc pdr. Measured: PASS in 1.5 s.

  1. Change one line

    Switch the engine to smtbmc yices, depth 12, and re-run: UNKNOWN. Switch back to abc pdr. What did the engine know that the window did not?

  2. The engineer’s route

    Add the two F2.4 helpers and run smtbmc yices at depth 2. Compare the time with PDR’s.

  3. Break a pointer

    Make rd_ptr wrap at 16: rd_ptr <= rd_ptr == 5'd15 ? 5'd0 : rd_ptr + 5'd1;. Run abc pdr and read step 0 of its trace.

design.sv

props.sv

Use assert property (@(posedge clk) ...);. Leave blank for immediate assertions in the design.

Inputs are free unless constrained. Run to find a counterexample or check a proof.

Model: one positive-edge clock, binary data. Sampled history requires declaration-initialized variables; primary-input history is unsupported.

SBY summary and log

Check Yourself

Predict the outputfifo16, no helpers, mode prove, abc pdr, reset assumed in step 0. The verdict is:
module fifo16(input clk, rst, wr, rd, input [7:0] wdata,
  output [7:0] rdata, output empty, full);
  reg [7:0] mem [0:15];
  reg [4:0] wr_ptr=0, rd_ptr=0, count=0;
  assign empty = count == 5'd0;
  assign full  = count == 5'd16;
  wire do_wr = wr && !full, do_rd = rd && !empty;
  assign rdata = mem[rd_ptr[3:0]];
  always @(posedge clk)
    if (rst) begin wr_ptr <= 0; rd_ptr <= 0; count <= 0; end
    else begin
      if (do_wr) begin mem[wr_ptr[3:0]] <= wdata; wr_ptr <= wr_ptr + 5'd1; end
      if (do_rd) rd_ptr <= rd_ptr + 5'd1;
      count <= count + do_wr - do_rd;
    end
  always @(posedge clk) begin
    if ($initstate) begin assume(rst); end else begin assume(!rst); end
  end
  always @(posedge clk) if (!rst) begin
    if (empty) assert(wr_ptr == rd_ptr);
  end
endmodule
ConceptWhich claim about PDR is wrong?
ConceptWhy can PDR prove fifo16 without a helper where k-induction cannot?
Read the waveformIs this PDR trace a counterexample or an induction trace?
012345678910111213141516171819202122clkfreerstfreewrfreerdcountwr_ptr01234567891011121314151617rd_ptr012345678910111213141501empty

Measured abc pdr trace for the buggy FIFO. Step 0 is reset; the failure is sampled at 21 and reported at 22.

Remember

  • IC3/PDR keeps frames of clauses instead of unrolling.
  • Each clause is proven relative to the previous frame; equal frames are an inductive invariant.
  • PDR proves fifo16 with no helpers; its invariant is many bit-level lemmas.
  • Its counterexamples start at reset but need not be the shortest.