Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SMT-LIB 2.6 conformance, support for cvc5, and generalization for alternative SMT-solvers #609

Merged
merged 23 commits into from
May 24, 2022

Conversation

lfwa
Copy link
Contributor

@lfwa lfwa commented Apr 22, 2022

This pull request contains the following:

  • Modified Silicon to only produce SMT-LIB 2.6 conformant encodings (removed Z3-specific statements).
  • Support for the cvc5 SMT-solver via option prover.
  • Backend generalized to support alternative SMT-solvers.
  • Backwards-compatible config options.

All tests pass with the Z3 solver, but using cvc5 results in ~100 tests failing mostly due to timeouts when using quantifiers.

README.md Outdated Show resolved Hide resolved
case Some(t) => t
// Not set, so compute default value based on prover selected.
case _ => prover.toOption match {
case Some(Cvc5ProverStdIO.name) => 180
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? It seems strange to have a different default based on the prover. The description of this in line 191 is also not great.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the description in commit 2924e00 and added a comment to the file.

The default timeout for cvc5 is set to 180 since it does not support per-checks timeouts set after instantiation of the solver so any checks or saturation checks can cause the verifier to hang indefinitely.
But maybe we just let the default be 0 for all provers and we let cvc5 users deal with this themselves?

I appreciate any input on this :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a strong opinion here, but it seems cleaner to not "misuse" the global timeout to compensate for cvc5's lack of per-check timeouts. Please revert to a default of 0 for all provers.

Copy link
Contributor Author

@lfwa lfwa Apr 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed/reverted back to default of 0 for all provers in 37e3adb, 6ab9858, 4215b09, and d5b896c.


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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be an enum at this point (created when parsing config flags) rather than a String?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Letting the factory handle strings instead of anything else was primarily motivated by its simplicity.

We could create an enum and an extra ValueConverter in Config.scala that converts the strings to an enum but wouldn't we still need a factory that just matches on the enum to create new ProverStdIO objects? To me it seems like this would add another place in the code to update when introducing additional SMT solvers with no added benefits. Admittedly, I am very new to Scala so there are likely advantages that I do not see or a way to easily create a factory with enums.

If you have any suggestions on a clean/nice way to do this, I would be more than happy to introduce the changes if I have time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enums (or sealed traits) have the advantage over strings that the compiler can perform exhaustiveness checks for the former. It is therefore good practice to turn strings into enums as early as possible (i.e. in the command-line parser). Another disadvantage of strings is that you always need to account for upper-/lowercase spelling.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks for the explanation.
I will introduce enums instead of the string factory if I have time. :)

"min", "List", "const",

/* cvc5 - Transcendental operators, see https://github.com/cvc5/cvc5/blob/main/src/parser/smt2/smt2.cpp */
"exp", "sin", "cos", "tan", "csc", "sec", "cot", "arcsin", "arccos", "arctan", "arccsc", "arcsec", "arccot", "sqrt",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How much of this is CVC5 specific? Are most of these also keywords to Z3? (I see some duplicates.)

Copy link
Contributor Author

@lfwa lfwa Apr 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed any duplicates already defined for Z3 or SMTLIB in commit 6bc0d29. All the keywords I added are defined in the cvc5 source code and if used in verification will lead to an exception when running the cvc5 prover on the smt file.

object Z3ProverStdIO {
val name = "Z3"
val minVersion = Version("4.5.0")
val maxVersion = None // Some(Version("4.5.0")) /* X.Y.Z if that is the *last supported* version */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there were actual problems with higher versions @mschwerhoff ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot offer any input on this since I have not tested it. The minVersion and maxVersion are just moved from Silicon.scala and the values are kept the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Aurel300 maxVersion is currently disabled because no Z3 version really brakes Silicon - whereas Z3 prior to 4.5.0 isn't supported anymore due to configuration option changes. Currently, newer versions make a specify subset of our tests fail (old VerCors examples we suspect of matching loops), but ignoring those, newer versions are supported.

@Aurel300
Copy link
Member

The CVC5 support should be tested on the CI also.

@lfwa
Copy link
Contributor Author

lfwa commented Apr 22, 2022

The CVC5 support should be tested on the CI also.

@Aurel300 How would I go about this?

@Aurel300
Copy link
Member

Aurel300 commented Apr 24, 2022

@lfwa The CI file is here. Z3 is installed as part of the base "Gobra" container, I think. I don't think this includes CVC5, so it would have to be installed manually. Then, the whole test suite should be run with the --prover cvc5 algorithm passed (somehow, not sure what the syntax is for sbt test).

(You say in the description that 100 tests fail with CVC5, so maybe this should be an optional step. @mschwerhoff Do we want to skip some tests with CVC5? Or try to find out why they are timing out and fix them?)

@mschwerhoff mschwerhoff merged commit 18cea46 into viperproject:master May 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants