JavaSMT - Unified Java API for SMT solvers.
Java C Other
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.idea Update AutoValue to 1.6 May 28, 2018
.settings Sync build-system improvements from Jun 19, 2018
build Sync build-system improvements from Jun 19, 2018
doc Update package name in README examples and Javadoc overview. Apr 14, 2017
lib update Princess to latest version 2.12 from 2018-07-30. Jul 30, 2018
solvers_ivy_conf Remove libz3j.so May 20, 2016
src/org/sosy_lab/java_smt fix warning from compiler. Jul 30, 2018
website website: update documentation, comment Mar 11, 2017
.appveyor.yml Always publish JUnit report as artifact, not only when tests succeed Aug 24, 2017
.checkstyle Sync build-system improvements from Jun 19, 2018
.classpath Revert accidently commited file. Jul 30, 2018
.factorypath.template Add common.jar to .factorypath.template for Eclipse users Jun 20, 2018
.gitignore Replace FindBugs with its successor SpotBugs Dec 5, 2017
.gitlab-ci.yml Add CI on GitLab, and use it for testing with Java 9. May 28, 2018
.project Concentrate Eclipse config in .settings where possible. Dec 5, 2017
.travis.yml Replace FindBugs with its successor SpotBugs Dec 5, 2017
CHANGELOG.md prepare documentation for release 2.0.0 Jan 12, 2018
Developers.md Remove special linking script for Z3 binary. May 25, 2018
KnownIssues.md Update known issues Jun 19, 2017
License_Apache-2.0.txt Added Apache License. Nov 27, 2015
README.md remove unused footnote from Readme Jun 12, 2018
build.xml Refactor build system such that build-documentation.xml is not Jun 19, 2018
pom_template.xml update maintainers. Mar 24, 2018

README.md

JavaSMT

Build Status Build Status on Windows Code Quality Test Coverage Apache 2.0 License Maven Central

Unified Java API for SMT solvers.

Project Description & Philosophy

JavaSMT is a common API layer for accessing various SMT solvers. It was published as a paper at VSTTE 2016.

It was created out of our experience integrating and using different SMT solvers in the CPAchecker project. The library is developed for medium to large software projects which require access to SMT solvers. The API is optimized for performance (using JavaSMT has very little runtime overhead compared to using the solver API directly), customizability (features and settings exposed by various solvers should be visible through the wrapping layer) and type-safety (it shouldn't be possible to add boolean terms to integer ones at compile time) sometimes at the cost of verbosity.

Supported Solvers

Currently, we support the following SMT solvers:

Support for CVC4 is planned in the near future (cf. #2).

Supported Features

JavaSMT can express formulas in the following theories:

  • Integer
  • Rational
  • Bitvector
  • Floating point
  • Array
  • Uninterpreted Function

The following features are supported:

  • Satisfiability checking
  • Quantifiers and quantifier elimination
  • Incremental solving with assumptions
  • Incremental solving with push/pop
  • Multiple independent contexts
  • Model generation
  • Interpolation, including tree and sequential
  • Formula transformation using built-in tactics
  • Formula introspection using visitors

Multithreading Support

All solvers support multithreading (MathSAT only since JavaSMT 1.0.1-164-gd14ed28), provided that different threads use different contexts, and all operations on a single context are performed from a single thread. Interruption using ShutdownNotifier may be used to interrupt a a solver from any thread.

Garbage Collection in Native Solvers

JavaSMT exposes an API for performing garbage collection on solvers implemented in a native language. As a native solver has no way of knowing whether the created formula object is still referenced by the client application, this API is necessary to avoid leaking memory. Note that due to the hash consing usage inside the solvers, there is never more than one copy of an identical formula object in memory. Consequently, if all created formulas are later re-used (or re-created) in the application, it is not necessary to perform any garbage collection at all.

Z3

The parameter solver.z3.usePhantomReferences may be used to control whether JavaSMT will attempt to decrease references on Z3 formula objects once they are no longer referenced.

MathSAT5

Currently we do not support performing garbage collection for MathSAT5.

Installation

Automatic Installation from Maven Central

If you use Maven/Gradle/SBT/etc to build your project, a dependency to JavaSMT can be added using a single configuration item.

For Maven:

<dependency>
  <groupId>org.sosy-lab</groupId>
  <artifactId>java-smt</artifactId>
  <version>1.0.1</version>
</dependency>

Currently, only SMTInterpol is automatically fetched from Maven Central, and shared object for other solvers would have to be installed manually: see the section "Manual Installation" below.

Automatic Installation using Ivy

If your build tool supports fetching packages from Apache Ivy, you can point it to Sosy-Lab Ivy repository, which would automatically fetch JavaSMT and all of its dependencies.

After the repository URL is configured, you only need to add the following dependency:

<dependency org="org.sosy_lab" name="javasmt" rev="0.60" />

Manual Installation

JARs for JavaSMT and its dependencies can be downloaded from our Ivy repository manually. In order to perform the manual installation, the following steps should be followed:

  • The desired version has to be chosen. Latest version can be found by looking at the Ivy index.
  • Suppose the version 1.0.1 was chosen. Ivy description file ivy-1.0.1.xml can be consulted in order to determine all the files which should be fetched.
  • The artifacts tag specifies what files the release depends on. In the example case, those are javasmt-1.0.1.jar and (optionally) javasmt-1.0.1-sources.jar, located in the same directory.
  • Finally, the dependencies can be manually followed and resolved. E.g. in the example, Z3 version z3-4.4.1-1394-gd12efb6 is specified, which is described by the corresponding XML file, specifying what binaries should be fetched from the corresponding directory.

Binaries for Native Solvers (MathSAT and Z3)

When using Ivy for installation on a 64-bit Linux platform, solver binaries for native solvers are downloaded automatically. Everything should work as is after installation.

Without Ivy you need to download and install the binaries manually as described above under Manual Installation. You can either copy them into the directory of the JavaSMT JAR file, or in a directory ../native/<arch>-<os>/ relative to the directory of the JAR file. See NativeLibraries documentation for more details on which path is searched.

For systems other than 64-bit Linux (e.g., Windows, or 32-bit systems) we do not provide binaries so you need to download or compile them for yourself. For Z3, download either the official binaries or build it with the flags --java --git-describe according to its documentation. Then install the files libz3.(so|dll) and libz3java.(so|dll) as described above. In order to compile MathSAT binaries, see the comments in the lib/native/source/libmathsat5j/compile.sh script.

Solvers which run directly on JDK (currently Princess and SMTInterpol) do not require any configuration and work out of the box.

Quickstart Guide

Initialization

Below is a small example showing how to initialize the library using the entry point SolverContextFactory:

package org.sosy_lab.java_smt.test;

import org.sosy_lab.common.ShutdownManager;
import org.sosy_lab.common.configuration.Configuration;
import org.sosy_lab.common.configuration.InvalidConfigurationException;
import org.sosy_lab.common.log.BasicLogManager;
import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.java_smt.SolverContextFactory;
import org.sosy_lab.java_smt.SolverContextFactory.Solvers;
import org.sosy_lab.java_smt.api.SolverContext;

public class TestApp {
  public static void main(String[] args) throws InvalidConfigurationException {
    Configuration config = Configuration.fromCmdLineArguments(args);
    LogManager logger = BasicLogManager.create(config);
    ShutdownManager shutdown = ShutdownManager.create();

    // SolverContext is a class wrapping a solver context.
    // Solver can be selected either using an argument or a configuration option
    // inside `config`.
    SolverContext context = SolverContextFactory.createSolverContext(
        config, logger, shutdown.getNotifier(), Solvers.SMTINTERPOL);
  }
}

JavaSMT relies on three dependencies from the SoSy-Lab Common library. These dependencies are:

  • Configuration: JavaSMT accepts some configuration options and forwards options to the underlying SMT solver.
  • LogManager: JavaSMT can be configured to provide extensive logging for the operations related to all SMT queries.
  • ShutdownNotifier from a ShutdownManager: Many SMT queries can take a very long time, potentially more than the user is willing to wait. What's more, for a solver implemented in the native code usual ways of interrupting a Java process (e.g. interrupt signal) would not work. Shutdown manager provides a solution to gracefully request termination, and JavaSMT and the solvers will try to respond to such requests as soon as possible.

Here is how to get an instance of these dependencies:

Dependency Dummy instance that does nothing Regular instance
Configuration Configuration.defaultConfiguration() Configuration.fromCmdLineArguments(String[]) or Configuration.builder()...build() for more flexible definition of options (e.g., from .properties files)
LogManager LogManager.createNullLogManager() BasicLogManager.create(Configuration) for logging to the JDK logging API; for other logging frameworks just write a wrapper implementing LogManager
ShutdownNotifier ShutdownNotifier.createDummy() ShutdownManager.create().getNotifier()

Solving Constraints

Once the SolverContext is initialized, we can start posing queries to the solver. In this example, we want to find a satisfying example for a constraint over integers a, b and c:

a + b = c \/ a + c = 2 * b

Creating the required constraint is straightforward:

    // Assume we have a SolverContext instance.
    FormulaManager fmgr = context.getFormulaManager();

    BooleanFormulaManager bmgr = fmgr.getBooleanFormulaManager();
    IntegerFormulaManager imgr = fmgr.getIntegerFormulaManager();

    IntegerFormula a = imgr.makeVariable("a"),
                   b = imgr.makeVariable("b"),
                   c = imgr.makeVariable("c");
    BooleanFormula constraint = bmgr.or(
        imgr.equal(
            imgr.add(a, b), c
        ),
        imgr.equal(
            imgr.add(a, c), imgr.multiply(imgr.makeNumber(2), b)
        )
    );

Note the types of the formulas: IntegerFormula and BooleanFormula. Using different classes for different types of formulas adds additional guarantees at compile-time: unless and unsafe cast is used, it is impossible to e.g. add an integer to a boolean using JavaSMT API.

Once the constraint is generated, we can solve it and get the model:

    try (ProverEnvironment prover = context.newProverEnvironment(ProverOptions.GENERATE_MODELS)) {
      prover.addConstraint(constraint);
      boolean isUnsat = prover.isUnsat();
      if (!isUnsat) {
        Model model = prover.getModel();
      }
    }

Try-with-resources syntax will dispose of the prover once solving is finished.

Once the model is obtained we can get values from it either by iterating through all of the returned data, or by querying for the variables we need:

    BigInteger value = model.evaluate(a);

For further information, look at our full example HoudiniApp, or at the JavaDoc.

Further Documentation

Authors

Additional Acknowledgements