Conversation
IC3/PDR (Property Directed Reachability) proves safety properties without requiring a bound, complementing the existing BMC and k-induction engines. It incrementally constructs frame-based over-approximations of reachable states, blocks counterexample cubes via generalization (unsat cores + integer inequality abstraction), and detects fixpoints through clause propagation. Supports counterexample trace generation for print_cex. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
LGTM |
macos-13 is no longer supported by GitHub Actions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The macOS CI was failing because olafurpg/setup-scala (deprecated) relied on the sbt launcher to bootstrap from Maven Central without caching, causing transient download failures. Align macOS job with Ubuntu by using actions/setup-java + coursier/setup-action + SBT caching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
actions/setup-java@v1 defaults to x64 architecture, installing an x86_64 JVM on the macos-14 ARM64 runner. This causes UnsatisfiedLinkError when loading the ARM64 Z3 native libraries. Use setup-java@v4 with Zulu distribution which provides native ARM64 JDK 11 for macOS. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
polgreen
left a comment
There was a problem hiding this comment.
Minor point:
- the tests aren't included in the regression tests run by the CI
- it would be helpful if it could output the final frame so you could sanity check that frame is actually inductive and sufficient to prove the property
Major point:
- this doesn't work. I haven't looked into why, but this property passes using IC3, and fails using BMC:
/* Test IC3: property should fail due to overflow */
module main {
var x : bv3;
init {
x = 1bv3;
}
next {
x' = x + 1bv3;
}
invariant x_non_neg : x > 0bv3;
control {
v1 = bmc(3); // fails
check;
v1.print_cex(x);
v2 = ic3; // passes, and should not
check;
v2.print_cex(x);
}
}
| libraryDependencies += "com.github.scopt" %% "scopt" % "3.7.1" | ||
| libraryDependencies += "org.json4s" %% "json4s-jackson" % "4.0.3" | ||
|
|
||
| fork in run := true |
| javaOptions in run += s"-Djava.library.path=${baseDirectory.value}/z3/bin" | ||
|
|
||
| fork in Test := true | ||
| javaOptions in Test += s"-Djava.library.path=${baseDirectory.value}/z3/bin" |
There was a problem hiding this comment.
These tests need to be added to the regression tests that are run by CI
| /** Store mapping from Z3 BoolExpr to smt.Expr for unsat core retrieval. */ | ||
| var assumptionMap: scala.collection.immutable.Map[z3.BoolExpr, Expr] = scala.collection.immutable.Map.empty | ||
|
|
||
| override def checkAssumptions(assumptions: List[Expr]): SolverResult = { |
There was a problem hiding this comment.
I don't know if this should be inside the Z3 interface or within IC3, it seems specific to IC3
|
Also, really hard to debug this because I can't make sense of the SMT files it prints, because it prints one to check the initial state, and then it prints two that just contain the property and nothing else |
Register test-ic3-0, test-ic3-1, and test-ic3-2 in VerifierSpec.scala under a new IC3VerifSpec class, following the existing test pattern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- build.sbt: Add comments explaining fork/javaOptions are needed for Z3 JNI native library loading via sbt (complements LD_LIBRARY_PATH from setup scripts) - Context.scala, Z3Interface.scala: Document checkAssumptions and getUnsatCore as standard SMT-LIB operations (check-sat-assuming, get-unsat-core) - IC3Engine.scala: Disable SMT file generation during IC3 execution to prevent empty/broken output files from the shared solver's filePrefix mechanism Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After IC3 reaches a fixpoint, output the final frame clauses as the inductive invariant. Clauses are deduplicated and printed with user-level variable names instead of internal symbol encodings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Z3Model.evaluate() only handled IntNum and Bool values from Z3 models, throwing RuntimeError for bitvector (BitVecNum) values. In IC3's extractConcreteCube(), this error was silently caught, causing all bitvector state variables to be dropped and producing a trivial `true` cube. This led to a `false` blocking clause that poisoned frames, creating a spurious fixpoint and incorrectly reporting properties as PASSED. Add BitVecNum handling to evaluate() that returns proper BitVectorLit with the correct width. Add regression test with 3-bit bitvector overflow (x increments from 1bv3 and wraps to 0bv3 after 7 steps). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
This doesn't work: |
polgreen
left a comment
There was a problem hiding this comment.
See the example I've given above; this needs to handle and test all the datatypes we support, not just integers and bitvecs
| val bvNum = value.asInstanceOf[z3.BitVecNum] | ||
| val bigInt = bvNum.getBigInteger() | ||
| val width = e.typ.asInstanceOf[BitVectorType].width | ||
| smt.BitVectorLit(bigInt, width) |
There was a problem hiding this comment.
You need to consider all the datatypes we support, not just bitvectors and integers
Summary
ic3as a new control command (usage:v = ic3; check; print_results; v.print_cex;)print_cexandprint_cex_jsonChanges
IC3Engine.scala(new): Core IC3/PDR algorithm — frame management, proof obligations, consecution checks, cube generalization (unsat cores + sign-based inequality abstraction), clause propagation, fixpoint detection, and BMC-style CEX trace reconstructionContext.scala: AddcheckAssumptions()/getUnsatCore()to solver interfaceZ3Interface.scala: Implement assumption-based checking and unsat core extraction via Z3 Java APIControlCommandChecker.scala: Addic3command validationSymbolicSimulator.scala: Addic3command dispatch with label support forprint_cexbuild.sbt: Configurejava.library.pathfor Z3 native librariestest-ic3-0.ucl(property proved),test-ic3-1.ucl(CEX found + printed),test-ic3-2.ucl(requires strengthening)Test plan
test-ic3-0.ucl:x >= 0proved (1-inductive, fixpoint at frame 2)test-ic3-1.ucl:x < 5fails with CEX trace (x: 0→1→2→3→4→5)test-ic3-2.ucl:y <= xproved with strengthening (not 1-inductive, fixpoint at frame 4)examples/cpu_induction.ucl: All 9 properties proved (bitvectors, enums, uninterpreted types, arrays)🤖 Generated with Claude Code