Skip to content
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
6d6c8a3
Z3 via API, initial attempt. Simple examples verify.
marcoeilers Jun 3, 2022
8fbf230
Caching and small fixes
marcoeilers Jun 3, 2022
a7b1abd
Things work
marcoeilers Jun 4, 2022
3d54f06
Re-enabled parallel branch verification
marcoeilers Jun 6, 2022
a3511bb
Merge branch 'master' into meilers_z3_api
marcoeilers Jul 19, 2022
f0a561a
java 14 z3 4.8.6 lib, portable tests with api
marcoeilers Jul 20, 2022
ea3fdf1
Fixed expected version, added option to encode macros via functions
marcoeilers Jul 21, 2022
70094d3
Merge
marcoeilers Jul 21, 2022
57f1620
Attempt at parallelism with ForkJoinPool
marcoeilers Jul 21, 2022
4684253
Trying to debug
marcoeilers Jul 22, 2022
0614f79
Cleanup
marcoeilers Jul 25, 2022
2526422
Merge
marcoeilers Jul 25, 2022
652ad87
Getting models from Z3 API, catching Z3 exceptions
marcoeilers Jul 25, 2022
7b41482
Added randomization option, set test default back to StdIO Z3
marcoeilers Jul 26, 2022
28626cd
Cleanup and support for builtin SMT functions and sorts
marcoeilers Jul 26, 2022
2986947
More cleanup
marcoeilers Jul 26, 2022
8e8dd21
Re-added sortCache that I accidentally removed
marcoeilers Jul 28, 2022
353feaa
Fixed case_split setting which is apparently important for some examp…
marcoeilers Jul 28, 2022
090cba2
Forgot to clear sort cache
marcoeilers Jul 28, 2022
08cfb51
Added comments after Aurel's feedback
marcoeilers Jul 28, 2022
b93f7fe
Merge
marcoeilers Aug 7, 2022
7f08ad8
Actually verifying branches in parallel (needs to be caught in executor)
marcoeilers Aug 7, 2022
71b26e9
Removed debug printlns
marcoeilers Aug 7, 2022
1ebe250
Only parallelizing normal edges
marcoeilers Aug 7, 2022
36e1481
Fixed stack pop issue
marcoeilers Aug 8, 2022
06ec917
Merge branch 'master' into meilers_parallel_branches
marcoeilers Aug 8, 2022
953839e
Fixed random verification failures
marcoeilers Aug 9, 2022
3294c00
Final cleanup
marcoeilers Aug 11, 2022
f95af0e
Final cleanup
marcoeilers Aug 11, 2022
56aa774
Switched to library dependency instead of unmanaged jar
marcoeilers Aug 11, 2022
10659df
Merge branch 'meilers_z3_api' into meilers_parallel_branches
marcoeilers Aug 11, 2022
b192d39
Fixed Z3 version, waiting before resetting or stopping provers to pre…
marcoeilers Aug 19, 2022
bbd467f
Cleanup
marcoeilers Aug 22, 2022
0aacee0
Testing parallel branch verification option on examples directory
marcoeilers Aug 22, 2022
3336fee
Merge
marcoeilers Sep 1, 2022
823afa4
Changes after code review
marcoeilers Sep 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ lazy val silicon = (project in file("."))
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
libraryDependencies += "org.apache.commons" % "commons-pool2" % "2.9.0",
libraryDependencies += "io.spray" %% "spray-json" % "1.3.6",
libraryDependencies += "com.microsoft.z3" % "z3" % "4.8.7" from "https://www.sosy-lab.org/ivy/org.sosy_lab/javasmt-solver-z3/com.microsoft.z3-4.8.7.jar",

// Only get a few compilation errors at once
maxErrors := 5,
Expand Down
14 changes: 10 additions & 4 deletions src/main/scala/Config.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import scala.util.matching.Regex
import scala.util.Properties._
import org.rogach.scallop._
import viper.silicon.Config.StateConsolidationMode.StateConsolidationMode
import viper.silicon.decider.{Z3ProverStdIO, Cvc5ProverStdIO}
import viper.silicon.decider.{Cvc5ProverStdIO, Z3ProverAPI, Z3ProverStdIO}
import viper.silver.frontend.SilFrontendConfig

class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
Expand Down Expand Up @@ -635,6 +635,12 @@ class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
noshort = true
)

val parallelizeBranches= opt[Boolean]("parallelizeBranches",
descr = "Verify different branches in parallel.",
default = Some(false),
noshort = true
)

val printTranslatedProgram: ScallopOption[Boolean] = opt[Boolean]("printTranslatedProgram",
descr ="Print the final program that is going to be verified to stdout.",
default = Some(false),
Expand Down Expand Up @@ -717,7 +723,7 @@ class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
)

val prover: ScallopOption[String] = opt[String]("prover",
descr = s"One of the provers ${Z3ProverStdIO.name}, ${Cvc5ProverStdIO.name}. " +
descr = s"One of the provers ${Z3ProverStdIO.name}, ${Cvc5ProverStdIO.name}, ${Z3ProverAPI.name}. " +
s"(default: ${Z3ProverStdIO.name}).",
default = Some(Z3ProverStdIO.name),
noshort = true
Expand All @@ -726,8 +732,8 @@ class Config(args: Seq[String]) extends SilFrontendConfig(args, "Silicon") {
/* Option validation (trailing file argument is validated by parent class) */

validateOpt(prover) {
case Some(Z3ProverStdIO.name) | Some(Cvc5ProverStdIO.name) => Right(())
case prover => Left(s"Unknown prover '$prover' provided. Expected one of ${Z3ProverStdIO.name}, ${Cvc5ProverStdIO.name}.")
case Some(Z3ProverStdIO.name) | Some(Cvc5ProverStdIO.name) | Some(Z3ProverAPI.name) => Right(())
case prover => Left(s"Unknown prover '$prover' provided. Expected one of ${Z3ProverStdIO.name}, ${Cvc5ProverStdIO.name}, ${Z3ProverAPI.name}.")
}

validateOpt(timeout) {
Expand Down
2 changes: 2 additions & 0 deletions src/main/scala/decider/CVC5ProverStdIO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,6 @@ class Cvc5ProverStdIO(uniqueId: String,
protected def getProverPath: Path = {
Paths.get(Verifier.config.cvc5Exe)
}

override def emitSettings(contents: Iterable[String]): Unit = emit(contents)
}
98 changes: 59 additions & 39 deletions src/main/scala/decider/Decider.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ import scala.reflect.{ClassTag, classTag}
import com.typesafe.scalalogging.Logger
import viper.silver.ast
import viper.silver.components.StatefulComponent
import viper.silver.verifier.DependencyNotFoundError
import viper.silver.verifier.{DependencyNotFoundError, Model}
import viper.silicon._
import viper.silicon.common.collections.immutable.InsertionOrderedSet
import viper.silicon.interfaces._
import viper.silicon.interfaces.decider.{Prover, Unsat}
import viper.silicon.interfaces.decider._
import viper.silicon.logger.SymbExLogger
import viper.silicon.logger.records.data.{DeciderAssertRecord, DeciderAssumeRecord, ProverAssertRecord}
import viper.silicon.state._
Expand Down Expand Up @@ -60,15 +60,17 @@ trait Decider {
def appliedFresh(id: String, sort: Sort, appliedArgs: Seq[Term]): App

def generateModel(): Unit
def getModel(): String
def getModel(): Model
def clearModel(): Unit
def hasModel(): Boolean
def isModelValid(): Boolean

/* [BRANCH-PARALLELISATION] */
// def freshFunctions: InsertionOrderedSet[FunctionDecl]
// def freshMacros: Vector[MacroDecl]
// def declareAndRecordAsFreshFunctions(functions: InsertionOrderedSet[FunctionDecl]): Unit
// def declareAndRecordAsFreshMacros(functions: Vector[MacroDecl]): Unit
// def setPcs(other: PathConditionStack): Unit
def freshFunctions: InsertionOrderedSet[FunctionDecl]
def freshMacros: Vector[MacroDecl]
def declareAndRecordAsFreshFunctions(functions: InsertionOrderedSet[FunctionDecl]): Unit
def declareAndRecordAsFreshMacros(functions: Vector[MacroDecl]): Unit
def setPcs(other: PathConditionStack): Unit

def statistics(): Map[String, String]
}
Expand All @@ -87,23 +89,33 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>
def identifierFactory: IdentifierFactory

object decider extends Decider with StatefulComponent {
private var proverStdIO: ProverStdIO = _
private var proverStdIO: Prover = _
Comment thread
marcoeilers marked this conversation as resolved.
Outdated
private var pathConditions: PathConditionStack = _

// private var _freshFunctions: InsertionOrderedSet[FunctionDecl] = _ /* [BRANCH-PARALLELISATION] */
// private var _freshMacros: Vector[MacroDecl] = _
private var _freshFunctions: InsertionOrderedSet[FunctionDecl] = _ /* [BRANCH-PARALLELISATION] */
private var _freshMacros: Vector[MacroDecl] = _

def prover: ProverStdIO = proverStdIO
def prover: Prover = proverStdIO

def pcs: PathConditionStack = pathConditions

// def setPcs(other: PathConditionStack) = { /* [BRANCH-PARALLELISATION] */
// pathConditions = other
// pathConditions.assumptions foreach prover.assume
// }
private def getProverStdIO(prover: String): ProverStdIO = prover match {
def setPcs(other: PathConditionStack) = {
/* [BRANCH-PARALLELISATION] */
pathConditions = other
while (prover.pushPopScopeDepth > 1){
prover.pop()
}
val layeredStack = other.asInstanceOf[LayeredPathConditionStack]
Comment thread
marcoeilers marked this conversation as resolved.
layeredStack.layers.reverse.foreach(l => {
l.assumptions foreach prover.assume
prover.push()
})
}

private def getProverStdIO(prover: String): Prover = prover match {
case Z3ProverStdIO.name => new Z3ProverStdIO(uniqueId, termConverter, identifierFactory, reporter)
case Cvc5ProverStdIO.name => new Cvc5ProverStdIO(uniqueId, termConverter, identifierFactory, reporter)
case Z3ProverAPI.name => new Z3ProverAPI(uniqueId, new TermToZ3APIConverter(), identifierFactory, reporter)
case prover =>
val msg1 = s"Unknown prover '$prover' provided. Defaulting to ${Z3ProverStdIO.name}."
logger warn msg1
Expand All @@ -118,7 +130,11 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>
val proverStdIOVersion = proverStdIO.version()
// One can pass some options. This allows to check whether they have been received.

val msg = s"Using ${proverStdIO.name} $proverStdIOVersion located at ${proverStdIO.proverPath}"
val path = prover match {
case pio: ProverStdIO => pio.proverPath
case _ => "No Path"
}
val msg = s"Using ${proverStdIO.name} $proverStdIOVersion located at ${path}"
reporter report ConfigurationConfirmation(msg)
logger debug msg

Expand All @@ -141,16 +157,16 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>

def start(): Unit = {
pathConditions = new LayeredPathConditionStack()
// _freshFunctions = InsertionOrderedSet.empty /* [BRANCH-PARALLELISATION] */
// _freshMacros = Vector.empty
_freshFunctions = InsertionOrderedSet.empty /* [BRANCH-PARALLELISATION] */
_freshMacros = Vector.empty
createProver()
}

def reset(): Unit = {
proverStdIO.reset()
pathConditions = new LayeredPathConditionStack()
// _freshFunctions = InsertionOrderedSet.empty /* [BRANCH-PARALLELISATION] */
// _freshMacros = Vector.empty
_freshFunctions = InsertionOrderedSet.empty /* [BRANCH-PARALLELISATION] */
_freshMacros = Vector.empty
}

def stop(): Unit = {
Expand Down Expand Up @@ -298,7 +314,7 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>

prover.declare(macroDecl)

// _freshMacros = _freshMacros :+ macroDecl /* [BRANCH-PARALLELISATION] */
_freshMacros = _freshMacros :+ macroDecl /* [BRANCH-PARALLELISATION] */

macroDecl
}
Expand Down Expand Up @@ -334,35 +350,39 @@ trait DefaultDeciderProvider extends VerifierComponent { this: Verifier =>
HeapDepFun(proverFun.id, proverFun.argSorts, proverFun.resultSort).asInstanceOf[F]
}

// _freshFunctions = _freshFunctions + FunctionDecl(fun) /* [BRANCH-PARALLELISATION] */
_freshFunctions = _freshFunctions + FunctionDecl(fun) /* [BRANCH-PARALLELISATION] */

fun
}


/* [BRANCH-PARALLELISATION] */
// def freshFunctions: InsertionOrderedSet[FunctionDecl] = _freshFunctions
// def freshMacros: Vector[MacroDecl] = _freshMacros
//
// def declareAndRecordAsFreshFunctions(functions: InsertionOrderedSet[FunctionDecl]): Unit = {
// functions foreach prover.declare
//
// _freshFunctions = _freshFunctions ++ functions
// }
//
// def declareAndRecordAsFreshMacros(macros: Vector[MacroDecl]): Unit = {
// macros foreach prover.declare
//
// _freshMacros = _freshMacros ++ macros
// }
def freshFunctions: InsertionOrderedSet[FunctionDecl] = _freshFunctions
def freshMacros: Vector[MacroDecl] = _freshMacros

def declareAndRecordAsFreshFunctions(functions: InsertionOrderedSet[FunctionDecl]): Unit = {
functions foreach prover.declare

_freshFunctions = _freshFunctions ++ functions
}

def declareAndRecordAsFreshMacros(macros: Vector[MacroDecl]): Unit = {
macros foreach prover.declare

_freshMacros = _freshMacros ++ macros
}

/* Misc */

def statistics(): Map[String, String] = prover.statistics()

override def generateModel(): Unit = proverAssert(False(), None)

override def getModel(): String = prover.getLastModel()
override def getModel(): Model = prover.getModel()

override def hasModel(): Boolean = prover.hasModel()

override def isModelValid(): Boolean = prover.isModelValid()

override def clearModel(): Unit = prover.clearLastModel()
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/decider/PathConditions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ private[decider] class LayeredPathConditionStack
with PathConditionStack
with Cloneable {

private var layers: Stack[PathConditionStackLayer] = Stack.empty
var layers: Stack[PathConditionStackLayer] = Stack.empty
Comment thread
marcoeilers marked this conversation as resolved.
Outdated
private var markToLength: Map[Mark, Int] = Map.empty
private var scopeMarks: List[Mark] = List.empty
private var markCounter = new Counter(0)
Expand Down
18 changes: 11 additions & 7 deletions src/main/scala/decider/ProverStdIO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import viper.silicon.verifier.Verifier
import viper.silver.verifier.{DefaultDependency => SilDefaultDependency}
import viper.silicon.{Config, Map, toMap}
import viper.silver.reporter.{ConfigurationConfirmation, InternalWarningMessage, Reporter}
import viper.silver.verifier.Model

import scala.collection.mutable

Expand All @@ -30,7 +31,7 @@ abstract class ProverStdIO(uniqueId: String,
extends Prover
with LazyLogging {

protected var pushPopScopeDepth = 0
var pushPopScopeDepth = 0
Comment thread
marcoeilers marked this conversation as resolved.
Outdated
protected var lastTimeout: Int = -1
protected var logfileWriter: PrintWriter = _
protected var prover: Process = _
Expand All @@ -41,14 +42,9 @@ abstract class ProverStdIO(uniqueId: String,
var proverPath: Path = _
var lastModel : String = _

def name: String
def minVersion: Version
def maxVersion: Option[Version]
def exeEnvironmentalVariable: String
def dependencies: Seq[SilDefaultDependency]
def staticPreamble: String
def startUpArgs: Seq[String]
def randomizeSeedsOptions: Seq[String]

protected def setTimeout(timeout: Option[Int]): Unit
protected def getProverPath: Path
Expand Down Expand Up @@ -289,6 +285,14 @@ abstract class ProverStdIO(uniqueId: String,
}
}

override def hasModel(): Boolean = {
lastModel != null
}

override def isModelValid(): Boolean = {
lastModel != null && !lastModel.contains("model is not available")
}

protected def assertUsingSoftConstraints(goal: String): (Boolean, Long) = {
val guard = fresh("grd", Nil, sorts.Bool)

Expand Down Expand Up @@ -457,7 +461,7 @@ abstract class ProverStdIO(uniqueId: String,
output.println(out)
}

override def getLastModel(): String = lastModel
override def getModel(): Model = Model(lastModel)

override def clearLastModel(): Unit = lastModel = null
}
9 changes: 6 additions & 3 deletions src/main/scala/decider/SMTLib2PreambleReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,18 @@ class SMTLib2PreambleReader extends PreambleReader[String, String] {
lineAcc.replace(orig, repl)})
}

def emitPreamble(preamble: Iterable[String], sink: ProverLike): Unit = {
sink.emit(preamble)
def emitPreamble(preamble: Iterable[String], sink: ProverLike, isOptions: Boolean): Unit = {
if (isOptions)
sink.emitSettings(preamble)
else
sink.emit(preamble)
}

def emitParametricPreamble(resource: String,
substitutions: Map[String, String],
sink: ProverLike)
: Unit = {

emitPreamble(readParametricPreamble(resource, substitutions), sink)
emitPreamble(readParametricPreamble(resource, substitutions), sink, false)
}
}
2 changes: 1 addition & 1 deletion src/main/scala/decider/TermToSMTLib2Converter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ class TermToSMTLib2Converter
else
render(t)

protected def render(id: Identifier, sanitizeIdentifier: Boolean = true): String = {
def render(id: Identifier, sanitizeIdentifier: Boolean = true): String = {
val repr: String = id match {
case SimpleIdentifier(name) => name
case SuffixedIdentifier(prefix, separator, suffix) => s"${render(prefix, false)}$separator$suffix"
Expand Down
Loading