Compare commits

...

40 Commits

Author SHA1 Message Date
xenia 25b2b677cd wip: feat: add support for z3 bit rotate exts 2026-05-31 23:42:41 -04:00
xenia 92d4091567 fix: test regression on newer Z3
z3 > 4.8.8 will return sign_extend and zero_extend operators in the
model, which were not handled by the smt-lib2 decoder, despite being
handled in the encoder. support for these operators has been added
2026-05-31 23:41:26 -04:00
xenia 38d467618e fix: always use system Z3 by default
rosette (for convenience) provides functionality to download and install
a z3 binary during raco installation. unfortunately this package is
currently very out of date, so this commit removes all install-time
functionality, causing rosette to fall back to searching for the z3
binary in the system PATH
2026-05-31 23:41:19 -04:00
dependabot[bot] 29808a02d2
Bump Bogdanp/setup-racket from 1.13 to 1.14 (#293)
Bumps [Bogdanp/setup-racket](https://github.com/bogdanp/setup-racket) from 1.13 to 1.14.
- [Release notes](https://github.com/bogdanp/setup-racket/releases)
- [Commits](https://github.com/bogdanp/setup-racket/compare/v1.13...v1.14)

---
updated-dependencies:
- dependency-name: Bogdanp/setup-racket
  dependency-version: '1.14'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-16 17:00:27 -07:00
dependabot[bot] e62e10e3a8 Bump Bogdanp/setup-racket from 1.11 to 1.13
Bumps [Bogdanp/setup-racket](https://github.com/bogdanp/setup-racket) from 1.11 to 1.13.
- [Release notes](https://github.com/bogdanp/setup-racket/releases)
- [Commits](https://github.com/bogdanp/setup-racket/compare/v1.11...v1.13)

---
updated-dependencies:
- dependency-name: Bogdanp/setup-racket
  dependency-version: '1.13'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-16 08:49:46 +07:00
Anish Athalye 128317d61c Fix incorrect type signatures 2025-05-16 08:49:35 +07:00
Gus Smith 3155c6ac72 Fix formatting 2025-05-01 10:06:04 +07:00
Gus Smith 61fdf3485d Print warning to stderr instead of stdout
This warning was cluttering stdout, which contained otherwise parseable data, causing errors downstream in my compiler. Moves the warning to stderr. Could also convert to using the logging package, but that would require more setup.
2025-05-01 10:06:04 +07:00
Gus Smith 53d54aa149 Fix STP build
See https://github.com/stp/stp/issues/503
2025-05-01 09:00:22 +07:00
dependabot[bot] cf703c60e2 Bump docker/build-push-action from 5 to 6
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-17 16:53:41 -07:00
Gus Smith bb0dec0e74 Attempt STP fix 2024-06-17 15:17:53 -07:00
Gus Smith edf682df5e
Add support for STP and Yices2 (#273)
Also add documentation for Bitwuzla and cvc5

---------

Co-authored-by: Vishal Canumalla <vishalc@cs.washington.edu>
2023-12-14 13:43:11 -08:00
dependabot[bot] 63524aa7fe
Bump Bogdanp/setup-racket from 1.10 to 1.11 (#269)
Bumps [Bogdanp/setup-racket](https://github.com/bogdanp/setup-racket) from 1.10 to 1.11.
- [Release notes](https://github.com/bogdanp/setup-racket/releases)
- [Commits](https://github.com/bogdanp/setup-racket/compare/v1.10...v1.11)

---
updated-dependencies:
- dependency-name: Bogdanp/setup-racket
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-30 05:13:13 -05:00
dependabot[bot] 2f183fd2f0
Bump docker/build-push-action from 4 to 5 (#266)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 5.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-14 09:27:49 +07:00
dependabot[bot] ad417cc928
Bump docker/metadata-action from 4 to 5 (#265)
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 4 to 5.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md)
- [Commits](https://github.com/docker/metadata-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-14 09:27:42 +07:00
dependabot[bot] b6e0ea375e
Bump docker/login-action from 2 to 3 (#264)
Bumps [docker/login-action](https://github.com/docker/login-action) from 2 to 3.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-14 09:27:35 +07:00
dependabot[bot] fd38ca31ca
Bump docker/setup-buildx-action from 2 to 3 (#263)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 2 to 3.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-14 09:27:27 +07:00
Gus Smith b3f792a3b4
Add support for Bitwuzla and CVC5 (#260)
Note: I've only enabled QF_BV for both solvers, as this is all I need at the moment. If you want to enable new solvers, you can just add new entries to the solver-features list in each file. This will likely involve having to fix tests as well.
2023-09-14 08:38:57 +07:00
dependabot[bot] 6096abafac Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-06 22:00:37 -07:00
sorawee 5dd348906d
avoid quadratic time processing in solver-(assert,min/maximize) (#261)
* avoid quadratic time processing in solver-(assert,min/maximize)

The time complexity of n calls to solver-assert / solver-minimize /
solver-maximize is currently O(n^2) due to list appending at the tail,
which requires traversal. This PR fixes the problem. The ordering of
solver-minimize and solver-maximize matters, however
(it specifies the lexicographic ordering minimization),
so rearranging them is slightly more complicated.

* Add an optimization order test

* Clear the solver
2023-08-10 18:38:48 -07:00
Emina Torlak 649184faf1 Update docs. 2023-07-04 13:37:56 -07:00
James Bornholt 15647f24b4
Install a custom Z3 build on Apple Silicon Macs (#254)
* Revert #145

The fix was shipped in Racket v7.7, and our minimum version is now v8.1,
so there's no longer a need for this.

* Install a custom Z3 build on Apple Silicon Macs

The Z3 version we use predates aarch64 Macs, so there's no pre-packaged
release available. The x86 version of Z3 works if the user has Rosetta
installed, but there's no obvious way to detect that, and it fails in
weird/silent ways if Rosetta isn't available.

So instead, let's install a custom Z3 4.8.8 aarch64 build in this case.
We can remove it whenever we go past Z3 4.8.16, which is when they
started releasing an aarch64 Mac binary. In the meantime, this makes
installation more obvious for users on Apple Silicon Macs.
2023-04-09 15:50:56 -07:00
dependabot[bot] 6d41d0e2fc Bump Bogdanp/setup-racket from 1.9 to 1.10
Bumps [Bogdanp/setup-racket](https://github.com/Bogdanp/setup-racket) from 1.9 to 1.10.
- [Release notes](https://github.com/Bogdanp/setup-racket/releases)
- [Commits](https://github.com/Bogdanp/setup-racket/compare/v1.9...v1.10)

---
updated-dependencies:
- dependency-name: Bogdanp/setup-racket
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-16 14:15:29 -05:00
dependabot[bot] 7cfd9b226c
Bump docker/build-push-action from 3 to 4 (#251)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 3 to 4.
2023-01-31 17:26:49 -08:00
sorawee 88b3fd96c4
Use cache for path->pkg (#250) 2023-01-19 16:52:50 -08:00
sorawee d3c7abf0e4
Fix unintentional value retain (#248)
* Fix unintentional value retain

To quote to the documentation of parameters
(https://docs.racket-lang.org/reference/parameters.html),

> as far as the memory manager is concerned,
> the value originally associated with a parameter through parameterize
> remains reachable as long the continuation is reachable,
> even if the parameter is mutated.

The parameter current-terms is initialized and/or parameterized to a
strong hash, making it not possible to GC the hash.
This PR fixes the issue by initializing and/or parameterizing to #f
first, and then mutates the parameter to a desired value later.

Fixes #247
2022-11-11 14:27:27 -08:00
sorawee b58652b26f
Fix the help description (#246)
Fix the help description
2022-11-11 14:23:14 -08:00
Anish Athalye 7e696132ca
Make evaluate preserve vector immutability (#244)
Prior to this patch, the following returned an immutable vector:

    (define empty-model (solve (void)))
    (evaluate (vector-immutable 1) empty-model)

However, the following returned a _mutable_ vector, even though
`evaluate` is given an immutable vector (containing no symbolics):

    (define-symbolic* b boolean?)
    (define model (solve (assert b)))
    (evaluate (vector-immutable 1) model)

With this patch, both examples above return an immutable vector.
2022-10-16 17:54:51 -07:00
dependabot[bot] 4c23c80712
Bump Bogdanp/setup-racket from 1.8 to 1.9 (#243)
Bumps [Bogdanp/setup-racket](https://github.com/Bogdanp/setup-racket) from 1.8 to 1.9.
- [Release notes](https://github.com/Bogdanp/setup-racket/releases)
- [Commits](https://github.com/Bogdanp/setup-racket/compare/v1.8...v1.9)

---
updated-dependencies:
- dependency-name: Bogdanp/setup-racket
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-14 18:34:48 -07:00
sorawee c407b871f2
Disallow define-symbolic with different types (#240)
Programs like:

```
(define (f type)
  (define-symbolic x type)
  x)

(+ 1 (f integer?))
(+ 2 (f boolean?))
```

should not work. The second call in particular should result in an
error, rather than using the cached term (which is an integer).

This PR makes the above program invalid. The SDSL benchmarks show that
the performance was not affected by the change.
2022-08-17 16:15:01 -07:00
James Bornholt ec1a0db464 Don't fail the whole install if Z3 fails
The Racket package server doesn't like this, and it gives up on
building/publishing the docs. The new error message is clear enough, so
just don't propagate the exception.
2022-08-15 11:47:44 -05:00
James Bornholt 426ffbfcf6 Make Z3 install failures more obvious on unsupported platforms
Previously, when installing on platforms that don't have a prebuilt Z3
binary available from GitHub, we'd silently install an x86 Linux binary
anyway, and then things would mysteriously fail at run time. So let's
make two changes:
(1) explicitly check the architecture and only install for x86_64
    systems, since there are no prebuilt Z3 binaries for other
    architectures on the version of Z3 we use; and
(2) provide more visible feedback if the install script fails to install
    a Z3 binary, by moving it to be a post-install rather than
    pre-install phase.
2022-08-13 19:36:32 -05:00
dependabot[bot] 096430e93e Bump docker/setup-buildx-action from 1 to 2
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 1 to 2.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-06 12:04:14 -05:00
dependabot[bot] f1dd43b229 Bump docker/build-push-action from 2 to 3
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 2 to 3.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-06 12:04:07 -05:00
dependabot[bot] 117d7aa240 Bump docker/login-action from 1 to 2
Bumps [docker/login-action](https://github.com/docker/login-action) from 1 to 2.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-06 12:04:01 -05:00
dependabot[bot] 374e728f6c Bump docker/metadata-action from 3 to 4
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 3 to 4.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Upgrade guide](https://github.com/docker/metadata-action/blob/master/UPGRADE.md)
- [Commits](https://github.com/docker/metadata-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-05 09:53:14 -05:00
dependabot[bot] 9520c30b8f Bump Bogdanp/setup-racket from 1.7 to 1.8
Bumps [Bogdanp/setup-racket](https://github.com/Bogdanp/setup-racket) from 1.7 to 1.8.
- [Release notes](https://github.com/Bogdanp/setup-racket/releases)
- [Commits](https://github.com/Bogdanp/setup-racket/compare/v1.7...v1.8)

---
updated-dependencies:
- dependency-name: Bogdanp/setup-racket
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-02 15:19:23 -05:00
sorawee 536953702b
improve error location (#228) 2022-04-09 11:07:33 -07:00
Emina Torlak 1d042d1368 Close #224. 2022-04-02 10:45:48 -07:00
James Bornholt c2975b9400 Fix parsing of SMT-LIB-compliant models
SMT-LIB says that models should not start with a 'model symbol, but most
SMT solvers have been doing so anyway until recently. So let's just
support both variants for the widest compatibility.

We had already fixed this specifically for Boolector, but we need to do
it everywhere, so this change makes a small refactoring to allow all SMT
solvers to share the same model parsing code, while still preserving
Boolector-specific fixups to the model after parsing.
2022-03-23 11:30:19 -05:00
30 changed files with 754 additions and 216 deletions

View File

@ -14,11 +14,11 @@ jobs:
steps:
- name: Clone Repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Configure Docker Metadata
id: meta
uses: docker/metadata-action@v3
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
@ -29,7 +29,7 @@ jobs:
type=semver,pattern={{major}}.{{minor}}
- name: Authenticate to Package Registry
uses: docker/login-action@v1
uses: docker/login-action@v3
if: ${{ github.event_name != 'pull_request' }}
with:
registry: ghcr.io
@ -37,10 +37,10 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
- name: Build and Publish Rosette Image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}

View File

@ -5,6 +5,10 @@ on: [push, pull_request]
env:
CVC4_URL: "http://cvc4.cs.stanford.edu/downloads/builds/x86_64-linux-opt/cvc4-1.8-x86_64-linux-opt"
BOOLECTOR_URL: "https://github.com/Boolector/boolector/archive/3.2.1.tar.gz"
CVC5_URL: "https://github.com/cvc5/cvc5/releases/download/cvc5-1.0.7/cvc5-Linux"
BITWUZLA_URL: "https://github.com/bitwuzla/bitwuzla/archive/93a3d930f622b4cef0063215e63b7c3bd10bd663.tar.gz"
STP_URL: "https://github.com/stp/stp/archive/d70085462f07c8a5a2f1225f727cda3ef505b141.tar.gz"
YICES2_URL: "https://github.com/SRI-CSL/yices2/archive/e27cf308cffb0ecc6cc7165c10e81ca65bc303b3.tar.gz"
jobs:
test:
@ -19,12 +23,14 @@ jobs:
steps:
- uses: actions/checkout@master
- name: Setup Racket
uses: Bogdanp/setup-racket@v1.7
uses: Bogdanp/setup-racket@v1.14
with:
architecture: x64
version: ${{ matrix.racket-version }}
variant: ${{ matrix.racket-variant }}
- name: Install solvers
# Note that setting LD_LIBRARY_PATH can be removed once this bug is
# fixed: https://github.com/stp/stp/issues/485
run: |
mkdir bin &&
wget $CVC4_URL -nv -O bin/cvc4 &&
@ -40,7 +46,50 @@ jobs:
make &&
popd &&
cp boolector/build/bin/boolector bin/ &&
rm -rf boolector*
rm -rf boolector* &&
wget $CVC5_URL -nv -O bin/cvc5 &&
chmod +x bin/cvc5 &&
sudo apt-get update &&
sudo apt-get install -y ninja-build &&
pip3 install meson &&
wget $BITWUZLA_URL -nv -O bitwuzla.tar.gz &&
mkdir bitwuzla &&
tar xzf bitwuzla.tar.gz -C bitwuzla --strip-components=1 &&
pushd bitwuzla &&
./configure.py &&
pushd build &&
ninja &&
popd &&
popd &&
cp bitwuzla/build/src/main/bitwuzla bin/ &&
sudo apt-get install -y build-essential git cmake bison flex libboost-all-dev libtinfo-dev python3 perl &&
wget $STP_URL -nv -O stp.tar.gz &&
mkdir stp &&
tar xzf stp.tar.gz -C stp --strip-components=1 &&
pushd stp &&
echo "LD_LIBRARY_PATH=$PWD/deps/cadical/build:$PWD/deps/cadiback/:$LD_LIBRARY_PATH" >> $GITHUB_ENV &&
./scripts/deps/setup-gtest.sh &&
./scripts/deps/setup-outputcheck.sh &&
./scripts/deps/setup-cms.sh &&
./scripts/deps/setup-minisat.sh &&
mkdir build &&
pushd build &&
cmake .. &&
cmake --build . &&
popd &&
popd &&
ln -s stp/build/stp bin/stp &&
sudo apt-get install -y gperf &&
wget $YICES2_URL -nv -O yices2.tar.gz &&
mkdir yices2 &&
tar xvf yices2.tar.gz -C yices2 --strip-components=1 &&
pushd yices2 &&
autoconf &&
./configure --prefix=$PWD/out/ &&
make &&
make install &&
popd &&
cp yices2/out/bin/yices-smt2 bin/yices-smt2
- name: Install Rosette
run: raco pkg install --auto --name rosette
- name: Compile Rosette tests

View File

@ -33,6 +33,7 @@
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
@bvneg @bvadd @bvsub @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
@concat @extract @sign-extend @zero-extend
@z3_ext_rotate_left @z3_ext_rotate_right
@integer->bitvector @bitvector->integer @bitvector->natural
; core/bvlib.rkt
bit lsb msb bvzero? bvadd1 bvsub1

View File

@ -14,6 +14,7 @@
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
@bvneg @bvadd @bvsub @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
@concat @extract @sign-extend @zero-extend
@z3_ext_rotate_left @z3_ext_rotate_right
@integer->bitvector @bitvector->integer @bitvector->natural)
;; ----------------- Bitvector Types ----------------- ;;
@ -338,6 +339,13 @@
(ite (bveq (bv 0 t) (bvand x (bv (bvsmin t) t))) (bv 0 t) (bv -1 t))]
[(_ _) (expression @bvashr x y)]))
(define (z3_ext_rotate_left x y)
(expression @z3_ext_rotate_left x y))
(define (z3_ext_rotate_right x y)
(expression @z3_ext_rotate_right x y))
(define-lifted-operator @bvnot bvnot T*->T)
(define-lifted-operator @bvand bvand T*->T)
(define-lifted-operator @bvor bvor T*->T)
@ -345,6 +353,8 @@
(define-lifted-operator @bvshl bvshl T*->T)
(define-lifted-operator @bvlshr bvlshr T*->T)
(define-lifted-operator @bvashr bvashr T*->T)
(define-lifted-operator @z3_ext_rotate_left z3_ext_rotate_left T*->T)
(define-lifted-operator @z3_ext_rotate_right z3_ext_rotate_right T*->T)
;; ----------------- Simplification ruules for bitwise operators ----------------- ;;

View File

@ -19,7 +19,12 @@
; These IDs are never reused, and they are used to impose an ordering on the children
; of expressions with commutative operators.
#|-----------------------------------------------------------------------------------|#
(define current-terms (make-parameter (make-hash)))
;; Initialize with #f so that the hash table cooperates with garbage collector.
;; See #247
(define current-terms (make-parameter #f))
(current-terms (make-hash))
(define current-index (make-parameter 0))
; Clears the entire term cache if invoked with #f (default), or
@ -77,17 +82,23 @@
; restores (terms) to its old value. If terms-expr is not given, it defaults to
; (terms), so (with-terms expr) is equivalent to (with-terms (terms) expr).
(define-syntax (with-terms stx)
;; Parameterize with #f so that the hash table cooperates with garbage collector.
;; See #247
(syntax-parse stx
[(_ expr)
#'(parameterize ([current-terms (hash-copy (current-terms))])
expr)]
#'(let ([orig-terms (current-terms)])
(parameterize ([current-terms #f])
(current-terms (hash-copy orig-terms))
expr))]
[(_ terms-expr expr)
#'(parameterize ([current-terms (hash-copy-clear (current-terms))])
(let ([ts terms-expr]
[cache (current-terms)])
(for ([t ts])
(hash-set! cache (term-val t) t))
expr))]))
#'(let ([orig-terms (current-terms)])
(parameterize ([current-terms #f])
(current-terms (hash-copy-clear orig-terms))
(let ([ts terms-expr]
[cache (current-terms)])
(for ([t ts])
(hash-set! cache (term-val t) t))
expr)))]))
@ -121,14 +132,21 @@
(define (term<? s1 s2) (< (term-ord s1) (term-ord s2)))
(define-syntax-rule (make-term term-constructor args type rest ...)
(let ([val args])
(or (hash-ref (current-terms) val #f)
(let* ([ord (current-index)]
[out (term-constructor val type ord rest ...)])
(current-index (add1 ord))
((current-reporter) 'new-term out)
(hash-set! (current-terms) val out)
out))))
(let ([val args]
[ty type])
(define cached (hash-ref (current-terms) val #f))
(cond
[cached
(unless (equal? (term-type cached) ty)
(error 'define-symbolic "type should remain unchanged"))
cached]
[else
(define ord (current-index))
(define out (term-constructor val ty ord rest ...))
(current-index (add1 ord))
((current-reporter) 'new-term out)
(hash-set! (current-terms) val out)
out])))
(define (make-const id t)
(unless (and (type? t) (solvable? t))

View File

@ -43,8 +43,8 @@
[type-cast type val [caller]] ; (-> type? any/c symbol? any/c)
[type-name type] ; (-> type? symbol?)
[type-applicable? type] ; (-> type? boolean?)
[type-eq? type u v] ; (-> type? (-> any/c any/c @boolean?)))
[type-equal? type u v] ; (-> type? (-> any/c any/c @boolean?)))
[type-eq? type u v] ; (-> type? any/c any/c @boolean?)
[type-equal? type u v] ; (-> type? any/c any/c @boolean?)
[type-compress type force? ps] ; (-> type? (listof (cons @boolean? any/c)) (listof (cons @boolean? any/c)))
[type-construct type vals] ; (-> type? (listof any/c) any/c)
[type-deconstruct type val]) ; (-> type? any/c (listof any/c))

View File

@ -434,7 +434,7 @@ leads to faster solving times.
@(rosette-eval '(clear-vc!))
@defproc[(bitvector->bits [x (bitvector n)]) (listof (bitvector n))]{
@defproc[(bitvector->bits [x (bitvector n)]) (listof (bitvector 1))]{
Returns the bits of @racket[x] as a list, i.e., @racket[(list (bit 0 x) ... (bit (- n 1) x))].

View File

@ -4,6 +4,10 @@
rosette/solver/solver rosette/solver/solution
rosette/solver/smt/z3 rosette/solver/smt/cvc4
rosette/solver/smt/boolector
rosette/solver/smt/bitwuzla
rosette/solver/smt/cvc5
rosette/solver/smt/stp
rosette/solver/smt/yices
rosette/base/form/define rosette/query/query
rosette/base/core/term (only-in rosette/base/base bv?)
(only-in rosette/base/base assert)
@ -22,6 +26,10 @@
rosette/solver/smt/z3
rosette/solver/smt/cvc4
rosette/solver/smt/boolector
rosette/solver/smt/bitwuzla
rosette/solver/smt/cvc5
rosette/solver/smt/stp
rosette/solver/smt/yices
#:use-sources
(rosette/query/finitize
rosette/query/query
@ -29,7 +37,11 @@
rosette/solver/solution
rosette/solver/smt/z3
rosette/solver/smt/cvc4
rosette/solver/smt/boolector)]
rosette/solver/smt/boolector
rosette/solver/smt/bitwuzla
rosette/solver/smt/cvc5
rosette/solver/smt/stp
rosette/solver/smt/yices)]
A @deftech{solver} is an automatic reasoning engine, used to answer
@seclink["sec:queries"]{queries} about Rosette programs. The result of
@ -279,6 +291,146 @@ Returns true if the Boolector solver is available for use (i.e., Rosette can loc
If this returns @racket[#f], @racket[(boolector)] will not succeed
without its optional @racket[path] argument.}
@subsection{Bitwuzla}
@defmodule[rosette/solver/smt/bitwuzla #:no-declare]
@defproc*[([(bitwuzla [#:path path (or/c path-string? #f) #f]
[#:logic logic (or/c symbol? #f) #f]
[#:options options (hash/c symbol? any/c) (hash)]) solver?]
[(bitwuzla? [v any/c]) boolean?])]{
Returns a @racket[solver?] wrapper for the @hyperlink["https://bitwuzla.github.io/"]{Bitwuzla} solver.
To use this solver, download prebuilt Bitwuzla or build it yourself,
and ensure the executable is on your @tt{PATH} or pass the path to the
executable as the optional @racket[path] argument.
Rosette currently tests Bitwuzla at commit
@tt{93a3d930f622b4cef0063215e63b7c3bd10bd663}.
The optional @racket[logic] argument specifies an SMT logic for the solver to use (e.g., @racket['QF_BV]).
Specifying a logic can improve solving performance, but Rosette makes no effort to check that
emitted constraints fall within the chosen logic. The default is @racket[#f],
which uses Bitwuzla's default logic.
The @racket[options] argument provides additional options that are sent to Bitwuzla
via the @tt{set-option} SMT command.
For example, setting @racket[options] to @racket[(hash ':seed 5)]
will send the command @tt{(set-option :seed 5)} to Bitwuzla prior to solving.
}
@defproc[(bitwuzla-available?) boolean?]{
Returns true if the Bitwuzla solver is available for use (i.e., Rosette can locate a @tt{bitwuzla} binary).
If this returns @racket[#f], @racket[(bitwuzla)] will not succeed
without its optional @racket[path] argument.}
@subsection{CVC5}
@defmodule[rosette/solver/smt/cvc5 #:no-declare]
@defproc*[([(cvc5 [#:path path (or/c path-string? #f) #f]
[#:logic logic (or/c symbol? #f) #f]
[#:options options (hash/c symbol? any/c) (hash)]) solver?]
[(cvc5? [v any/c]) boolean?])]{
Returns a @racket[solver?] wrapper for the @hyperlink["https://cvc5.github.io/"]{CVC5} solver.
To use this solver, download prebuilt CVC5 or build it yourself,
and ensure the executable is on your @tt{PATH} or pass the path to the
executable as the optional @racket[path] argument.
Rosette currently tests CVC5 at version 1.0.7.
The optional @racket[logic] argument specifies an SMT logic for the solver to use (e.g., @racket['QF_BV]).
Specifying a logic can improve solving performance, but Rosette makes no effort to check that
emitted constraints fall within the chosen logic. The default is @racket[#f],
which uses CVC5's default logic.
The @racket[options] argument provides additional options that are sent to CVC5
via the @tt{set-option} SMT command.
For example, setting @racket[options] to @racket[(hash ':seed 5)]
will send the command @tt{(set-option :seed 5)} to CVC5 prior to solving.
}
@defproc[(cvc5-available?) boolean?]{
Returns true if the CVC5 solver is available for use (i.e., Rosette can locate a @tt{cvc5} binary).
If this returns @racket[#f], @racket[(cvc5)] will not succeed
without its optional @racket[path] argument.}
@subsection{STP}
@defmodule[rosette/solver/smt/stp #:no-declare]
@defproc*[([(stp [#:path path (or/c path-string? #f) #f]
[#:logic logic (or/c symbol? #f) #f]
[#:options options (hash/c symbol? any/c) (hash)]) solver?]
[(stp? [v any/c]) boolean?])]{
Returns a @racket[solver?] wrapper for the @hyperlink["https://stp.github.io/"]{STP} solver.
To use this solver, download prebuilt STP or build it yourself,
and ensure the executable is on your @tt{PATH} or pass the path to the
executable as the optional @racket[path] argument.
Rosette currently tests STP at commit
@tt{0510509a85b6823278211891cbb274022340fa5c}.
Note that as of December 2023, the STP version on Mac Homebrew is too old to be
supported by Rosette.
The optional @racket[logic] argument specifies an SMT logic for the solver to use (e.g., @racket['QF_BV]).
Specifying a logic can improve solving performance, but Rosette makes no effort to check that
emitted constraints fall within the chosen logic. The default is @racket[#f],
which uses STP's default logic.
The @racket[options] argument provides additional options that are sent to STP
via the @tt{set-option} SMT command.
For example, setting @racket[options] to @racket[(hash ':seed 5)]
will send the command @tt{(set-option :seed 5)} to STP prior to solving.
}
@defproc[(stp-available?) boolean?]{
Returns true if the STP solver is available for use (i.e., Rosette can locate a @tt{stp} binary).
If this returns @racket[#f], @racket[(stp)] will not succeed
without its optional @racket[path] argument.}
@subsection{Yices2}
@defmodule[rosette/solver/smt/yices #:no-declare]
@defproc*[([(yices [#:path path (or/c path-string? #f) #f]
[#:logic logic (or/c symbol? #f) 'QF_BV]
[#:options options (hash/c symbol? any/c) (hash)]) solver?]
[(yices? [v any/c]) boolean?])]{
Returns a @racket[solver?] wrapper for the @hyperlink["https://yices.csl.sri.com/"]{Yices2} solver.
To use this solver, download prebuilt Yices2 or build it yourself,
and ensure the executable is on your @tt{PATH} or pass the path to the
executable as the optional @racket[path] argument.
Rosette specifically uses the @tt{yices-smt2} executable, which is the Yices2
solver with its SMTLIB2 frontend enabled.
Note that just building (without installing) Yices2 will produce an executable
named @tt{yices_smt2}. Running the installation step produces an executable
with the correct name. However, it is safe to skip the installation step and
simply rename or symlink the @tt{yices_smt2} executable to @tt{yices-smt2}.
Rosette currently tests Yices2 at commit
@tt{e27cf308cffb0ecc6cc7165c10e81ca65bc303b3}.
The optional @racket[logic] argument specifies an SMT logic for the solver to use (e.g., @racket['QF_BV]).
Specifying a logic can improve solving performance, but Rosette makes no effort to check that
emitted constraints fall within the chosen logic. Yices2 expects a logic to be
set; Rosette defaults to @racket['QF_BV].
The @racket[options] argument provides additional options that are sent to Yices2
via the @tt{set-option} SMT command.
For example, setting @racket[options] to @racket[(hash ':seed 5)]
will send the command @tt{(set-option :seed 5)} to Yices2 prior to solving.
}
@defproc[(yices-available?) boolean?]{
Returns true if the Yices2 solver is available for use (i.e., Rosette can locate a @tt{yices-smt2} binary).
If this returns @racket[#f], @racket[(yices)] will not succeed
without its optional @racket[path] argument.}
@section{Solutions}
A solution to a set of formulas may be satisfiable (@racket[sat?]), unsatisfiable (@racket[unsat?]),

View File

@ -9,21 +9,28 @@
@(define rosette:onward13
(make-bib
#:title @hyperlink["http://homes.cs.washington.edu/~emina/pubs/rosette.onward13.pdf"]{Growing Solver-Aided Languages with Rosette}
#:title @hyperlink["http://dl.acm.org/citation.cfm?id=2509586"]{Growing Solver-Aided Languages with Rosette}
#:author (authors "Emina Torlak" "Rastislav Bodik")
#:date 2013
#:location "New Ideas, New Paradigms, and Reflections on Programming and Software (Onward!)"))
@(define rosette:pldi14
(make-bib
#:title @hyperlink["http://homes.cs.washington.edu/~emina/pubs/rosette.pldi14.pdf"]{A Lightweight Symbolic Virtual Machine for Solver-Aided Host Languages}
#:title @hyperlink["http://dl.acm.org/citation.cfm?id=2594340"]{A Lightweight Symbolic Virtual Machine for Solver-Aided Host Languages}
#:author (authors "Emina Torlak" "Rastislav Bodik")
#:date 2014
#:location "Programming Language Design and Implementation (PLDI)"))
@(define sympro:oopsla18
(make-bib
#:title @hyperlink["https://unsat.cs.washington.edu/papers/bornholt-sympro.pdf"]{Finding Code That Explodes Under Symbolic Evaluation}
#:title @hyperlink["https://dl.acm.org/citation.cfm?id=3276519"]{Finding Code That Explodes Under Symbolic Evaluation}
#:author (authors "James Bornholt" "Emina Torlak")
#:date 2018
#:location "Object Oriented Programming, Systems, Languages, and Applications (OOPSLA)"))
#:location "Object Oriented Programming, Systems, Languages, and Applications (OOPSLA)"))
@(define rosette:popl22
(make-bib
#:title @hyperlink["https://doi.org/10.1145/3498709"]{A Formal Foundation for Symbolic Evaluation with Merging}
#:author (authors "Sorawee Porncharoenwase" "Luke Nelson" "Xi Wang" "Emina Torlak")
#:date 2022
#:location "Principles of Programming Languages (POPL)"))

View File

@ -4,7 +4,7 @@
@(require (for-label rosette/base/form/define rosette/query/query rosette/solver/solution
(only-in rosette/base/base assert vc-true? vc) )
racket/runtime-path racket/sandbox)
@(require (only-in "../refs.scrbl" ~cite rosette:pldi14))
@(require (only-in "../refs.scrbl" ~cite rosette:pldi14 rosette:popl22))
@(require "../util/lifted.rkt")
@(define-runtime-path root ".")
@ -19,7 +19,7 @@ functionality}. In this chapter, we briefly discuss the @racketmodname[rosette]
dialect of the language, which exports all of Racket.
Safe use of the full @racketmodname[rosette] language requires a basic understanding
of how Rosette's Symbolic Virtual Machine (SVM) works @~cite[rosette:pldi14].
of how Rosette's Symbolic Virtual Machine (SVM) works @~cite[rosette:pldi14 rosette:popl22].
Briefly, the SVM hijacks the normal Racket execution for all procedures and
constructs that are exported by @racketmodname[rosette/safe]. Any programs that are
implemented exclusively in the @racketmodname[rosette/safe] language are therefore

View File

@ -14,10 +14,7 @@
(experimental))))
;; Documentation category. On Racket 6.3+ this can be any string.
;; Runs the code in `private/install.rkt` before installing this collection.
(define pre-install-collection "private/install.rkt")
(define compile-omit-files '("private/install.rkt"
"lib/trace/report/node_modules"))
(define compile-omit-files '("lib/trace/report/node_modules"))
(define raco-commands
'(("symprofile"

View File

@ -48,10 +48,11 @@
(define-simple-macro (destruct val [pat:clause-pattern e:expr ...+] ...)
#:do [(for-each check-duplicate-identifier! (attribute pat.id-set))]
#:with match-expr (syntax/loc this-syntax (match var [pat (begin e ...)] ...))
#:with result
(syntax/loc this-syntax
(for/all ([var val]);(guarded-values val)])
(match var [pat (begin e ...)] ...)))
match-expr))
result)
(define-simple-macro (destruct* (val ...) [(pat:clause-pattern ...) e:expr ...+] ...)

View File

@ -40,7 +40,7 @@
"Only install the compile handler; do not run the profiler"
(run-profiler? #f)]
[("-m" "--module") name
"Run submodule <name> (defaults to 'main)"
"Run submodule <name> (defaults to 'main')"
(module-name (string->symbol name))]
[("-r" "--racket")
"Instrument code in any language, not just `#lang rosette`"

View File

@ -29,7 +29,7 @@
;; SymPro options
[("-m" "--module") name
"Run submodule <name> (defaults to 'main)"
"Run submodule <name> (defaults to 'main')"
(module-name (string->symbol name))]
[("-r" "--racket")
"Instrument code in any language, not just `#lang rosette`"

View File

@ -21,6 +21,8 @@
(string-prefix? (path->string (resolve-path a))
(path->string (resolve-path b))))
(define pkg-cache (make-hash))
(define (make-rosette-load/use-compiled pkgs-to-instrument)
(make-custom-load/use-compiled
#:blacklist
@ -28,6 +30,6 @@
(cond
[(path-prefix? path (find-collects-dir)) #f]
[else
(match (path->pkg path)
(match (path->pkg path #:cache pkg-cache)
[#f #t]
[pkg-name (member pkg-name pkgs-to-instrument)])]))))

View File

@ -1,107 +0,0 @@
#lang racket/base
;; Check whether z3 is installed during package setup.
;; If missing, builds & links a z3 binary.
(provide pre-installer)
(require racket/match
racket/file
racket/port
net/url
file/unzip)
(define (print-failure path msg)
(printf "\n\n********** Failed to install Z3 **********\n\n")
(printf "You'll need to manually install a Z3 binary\n")
(printf "to this location: ~a\n\n" path)
(printf "The problem was:\n~a\n\n" msg)
(printf "*********\n\n\n"))
(define (pre-installer collections-top-path racl-path)
(define bin-path (simplify-path (build-path racl-path ".." "bin")))
(define z3-path (build-path bin-path "z3"))
(with-handlers ([exn:fail? (lambda (e) (print-failure z3-path (exn-message e)))])
(unless (custom-z3-symlink? z3-path)
(define-values (z3-url z3-path-in-zip) (get-z3-url))
(define z3-port (get-pure-port (string->url z3-url) #:redirections 10))
(make-directory* bin-path) ;; Ensure that `bin-path` exists
(delete-directory/files z3-path #:must-exist? #f) ;; Delete old version of Z3, if any
(parameterize ([current-directory bin-path])
(call-with-unzip z3-port
(λ (dir)
(copy-directory/files (build-path dir z3-path-in-zip) z3-path)))
;; Unzipping loses file permissions, so we reset the z3 binary here
(file-or-directory-permissions
z3-path
(if (equal? (system-type) 'windows) #o777 #o755))))))
(define (custom-z3-symlink? z3-path)
(and (file-exists? z3-path)
(let ([p (simplify-path z3-path)])
(not (equal? (resolve-path p) p)))))
(define (get-z3-url)
(define site "https://github.com/Z3Prover/z3/releases/download")
(define version "z3-4.8.8")
(define-values (os exe)
(match (list (system-type) (system-type 'word))
['(unix 64) (values "x64-ubuntu-16.04" "z3")]
[`(macosx ,_) (values "x64-osx-10.14.6" "z3")]
['(windows 64) (values "x64-win" "z3.exe")]
[any (raise-user-error 'get-z3-url "Unknown system type '~a'" any)]))
(define name (format "~a-~a" version os))
(values
(format "~a/~a/~a.zip" site version name)
(format "~a/bin/~a" name exe)))
;; A copy of net/url's get-pure-port/headers, except with the Location header
;; for redirects made case-insensitive, fixing https://github.com/racket/racket/pull/3057
(require net/http-client net/url-connect)
(define (get-pure-port url #:redirections [redirections 0])
(let redirection-loop ([redirections redirections] [url url])
(define hc (http-conn-open (url-host url)
#:ssl? (if (equal? "https" (url-scheme url))
(current-https-protocol)
#f)))
(define access-string
(url->string
;; RFCs 1945 and 2616 say:
;; Note that the absolute path cannot be empty; if none is present in
;; the original URI, it must be given as "/" (the server root).
(let-values ([(abs? path)
(if (null? (url-path url))
(values #t (list (make-path/param "" '())))
(values (url-path-absolute? url) (url-path url)))])
(make-url #f #f #f #f abs? path (url-query url) (url-fragment url)))))
(http-conn-send! hc access-string #:method #"GET" #:content-decode '())
(define-values (status headers response-port)
(http-conn-recv! hc #:method #"GET" #:close? #t #:content-decode '()))
(define new-url
(ormap (λ (h)
(match (regexp-match #rx#"^[Ll]ocation: (.*)$" h)
[#f #f]
[(list _ m1b)
(define m1 (bytes->string/utf-8 m1b))
(with-handlers ((exn:fail? (λ (x) #f)))
(define next-url (string->url m1))
(make-url
(or (url-scheme next-url) (url-scheme url))
(or (url-user next-url) (url-user url))
(or (url-host next-url) (url-host url))
(or (url-port next-url) (url-port url))
(url-path-absolute? next-url)
(url-path next-url)
(url-query next-url)
(url-fragment next-url)))]))
headers))
(define redirection-status-line?
(regexp-match #rx#"^HTTP/[0-9]+[.][0-9]+ 3[0-9][0-9]" status))
(cond
[(and redirection-status-line? new-url (not (zero? redirections)))
(redirection-loop (- redirections 1) new-url)]
[else
response-port])))

View File

@ -47,7 +47,10 @@
[(cons x y)
(cons (eval-rec x sol cache) (eval-rec y sol cache))]
[(? vector?)
(for/vector #:length (vector-length expr) ([e expr]) (eval-rec e sol cache))]
(let ([v (for/vector #:length (vector-length expr) ([e expr]) (eval-rec e sol cache))])
(if (immutable? expr)
(vector->immutable-vector v)
v))]
[(? box?)
((if (immutable? expr) box-immutable box) (eval-rec (unbox expr) sol cache))]
[(? typed?)

View File

@ -12,6 +12,8 @@
(provide (all-defined-out))
(define (unique/reverse xs)
(reverse (unique xs)))
(define (find-solver binary base-path [user-path #f])
(cond
@ -42,14 +44,15 @@
(unless (list? bools)
(raise-argument-error 'solver-assert "(listof boolean?)" bools))
(define wfcheck-cache (mutable-set))
(set-solver-asserts! self
(append (solver-asserts self)
(for/list ([b bools] #:unless (equal? b #t))
(unless (or (boolean? b) (and (term? b) (equal? @boolean? (term-type b))))
(error 'assert "expected a boolean value, given ~s" b))
(when wfcheck
(wfcheck b wfcheck-cache))
b))))
(set-solver-asserts!
self
(append (for/list ([b bools] #:unless (equal? b #t))
(unless (or (boolean? b) (and (term? b) (equal? @boolean? (term-type b))))
(error 'assert "expected a boolean value, given ~s" b))
(when wfcheck
(wfcheck b wfcheck-cache))
b)
(solver-asserts self))))
(define (solver-minimize self nums)
(unless (null? nums)
@ -68,7 +71,7 @@
(server-shutdown (solver-server self)))
(define (solver-push self)
(match-define (solver server _ (app unique asserts) (app unique mins) (app unique maxs) env level) self)
(match-define (solver server _ (app unique asserts) (app unique/reverse mins) (app unique/reverse maxs) env level) self)
(server-write
server
(begin
@ -90,7 +93,7 @@
(set-solver-level! self (drop level k)))
(define (solver-check self [read-solution read-solution])
(match-define (solver server _ (app unique asserts) (app unique mins) (app unique maxs) env _) self)
(match-define (solver server _ (app unique asserts) (app unique/reverse mins) (app unique/reverse maxs) env _) self)
(cond [(ormap false? asserts) (unsat)]
[else (server-write
server
@ -122,35 +125,40 @@
; Reads the SMT solution from the server.
; The solution consists of 'sat or 'unsat, followed by
; followed by a suitably formatted s-expression. The
; output of this procedure is a hashtable from constant
; The solution consists of 'sat or 'unsat, followed by
; followed by a suitably formatted s-expression. The
; output of this procedure is a hashtable from constant
; identifiers to their SMTLib values (if the solution is 'sat);
; a non-empty list of assertion identifiers that form an
; unsatisfiable core (if the solution is 'unsat and a
; core was extracted); #f (if the solution is
; unsatisfiable core (if the solution is 'unsat and a
; core was extracted); #f (if the solution is
; 'unsat and no core was extracted); or 'unknown otherwise.
(define (read-solution server env #:unsat-core? [unsat-core? #f])
(decode
(parameterize ([current-readtable (make-readtable #f #\# #\a #f)]) ; read BV literals as symbols
(match (server-read server (read))
[(== 'sat)
(server-write server (get-model))
(let loop ()
(match (server-read server (read))
[(list (== 'objectives) _ ...) (loop)]
[(list (== 'model) def ...)
(for/hash ([d def] #:when (and (pair? d) (equal? (car d) 'define-fun)))
(values (cadr d) d))]
[other (error 'read-solution "expected model, given ~a" other)]))]
[(== 'unsat)
(if unsat-core?
(begin
(server-write server (get-unsat-core))
(match (server-read server (read))
[(list (? symbol? name) ...) name]
[other (error 'read-solution "expected unsat core, given ~a" other)]))
'unsat)]
[(== 'unknown) 'unknown]
[other (error 'read-solution "unrecognized solver output: ~a" other)]))
env))
(decode (parse-solution server #:unsat-core? unsat-core?) env))
(define (parse-solution server #:unsat-core? [unsat-core? #f])
(parameterize ([current-readtable (make-readtable #f #\# #\a #f)]) ; read BV literals as symbols
(match (server-read server (read))
[(== 'sat)
(server-write server (get-model))
(let loop ()
(match (server-read server (read))
[(list (== 'objectives) _ ...) (loop)]
; The SMT-LIB spec says that a model should be just a list of
; `define-fun`s, but many SMT solvers used to prefix that list
; with `model`, so let's support both versions.
; https://groups.google.com/g/smt-lib/c/5xpcIxdQ8-A/m/X4uQ7dIgAwAJ
[(or (list (== 'model) def ...) (list def ...))
(for/hash ([d def] #:when (and (pair? d) (equal? (car d) 'define-fun)))
(values (cadr d) d))]
[other (error 'read-solution "expected model, given ~a" other)]))]
[(== 'unsat)
(if unsat-core?
(begin
(server-write server (get-unsat-core))
(match (server-read server (read))
[(list (? symbol? name) ...) name]
[other (error 'read-solution "expected unsat core, given ~a" other)]))
'unsat)]
[(== 'unknown) 'unknown]
[other (error 'read-solution "unrecognized solver output: ~a" other)])))

View File

@ -0,0 +1,106 @@
;;; Requires Bitwuzla 0.1.0 or later.
#lang racket
(require racket/runtime-path
"server.rkt" "cmd.rkt" "env.rkt"
"../solver.rkt" "../solution.rkt"
(prefix-in base/ "base-solver.rkt")
(only-in "../../base/core/term.rkt" term term? term-type constant? expression constant with-terms)
(only-in "../../base/core/bool.rkt" @boolean? @forall @exists)
(only-in "../../base/core/bitvector.rkt" bitvector bitvector? bv? bv bv-value @extract @sign-extend @zero-extend @bveq)
(only-in "../../base/core/function.rkt" function-domain function-range function? function fv)
(only-in "../../base/core/type.rkt" type-of)
(only-in "../../base/form/control.rkt" @if))
(provide (rename-out [make-bitwuzla bitwuzla]) bitwuzla? bitwuzla-available?)
(define-runtime-path bitwuzla-path (build-path ".." ".." ".." "bin" "bitwuzla"))
(define bitwuzla-opts '("-m"))
(define (bitwuzla-available?)
(not (false? (base/find-solver "bitwuzla" bitwuzla-path #f))))
(define (make-bitwuzla [solver #f] #:options [options (hash)] #:logic [logic #f] #:path [path #f])
(define config
(cond
[(bitwuzla? solver)
(base/solver-config solver)]
[else
(define real-bitwuzla-path (base/find-solver "bitwuzla" bitwuzla-path path))
(when (and (false? real-bitwuzla-path) (not (getenv "PLT_PKG_BUILD_SERVICE")))
(error 'bitwuzla "bitwuzla binary is not available (expected to be at ~a); try passing the #:path argument to (bitwuzla)" (path->string (simplify-path bitwuzla-path))))
(base/config options real-bitwuzla-path logic)]))
(bitwuzla (server (base/config-path config) bitwuzla-opts (base/make-send-options config)) config '() '() '() (env) '()))
(struct bitwuzla base/solver ()
#:property prop:solver-constructor make-bitwuzla
#:methods gen:custom-write
[(define (write-proc self port mode) (fprintf port "#<bitwuzla>"))]
#:methods gen:solver
[
(define (solver-features self)
'(qf_bv))
(define (solver-options self)
(base/solver-options self))
(define (solver-assert self bools)
(base/solver-assert self bools bitwuzla-wfcheck))
(define (solver-minimize self nums)
(base/solver-minimize self nums))
(define (solver-maximize self nums)
(base/solver-maximize self nums))
(define (solver-clear self)
(base/solver-clear self))
(define (solver-shutdown self)
(base/solver-shutdown self))
(define (solver-push self)
(base/solver-push self))
(define (solver-pop self [k 1])
(base/solver-pop self k))
(define (solver-check self [read-solution base/read-solution])
(base/solver-check self read-solution))
(define (solver-debug self)
(base/solver-debug self))])
(define (set-default-options server)
void)
(define (valid-type? t)
(or (equal? t @boolean?)
(bitvector? t)
(and (function? t)
(for/and ([d (in-list (function-domain t))]) (valid-type? d))
(valid-type? (function-range t)))))
; Check whether a term v is well-formed for bitwuzla -- it must not mention
; types other than bitvectors, booleans, and uninterpreted functions over those
; types. If not, raise an exception.
(define (bitwuzla-wfcheck v [cache (mutable-set)])
(unless (set-member? cache v)
(set-add! cache v)
(cond
[(term? v)
(unless (valid-type? (type-of v))
(error 'bitwuzla "bitwuzla does not support values of type ~v (value: ~v)" (type-of v) v))
(match v
[(expression (or (== @forall) (== @exists)) vars body)
(error 'bitwuzla "bitwuzla does not support quantified formulas (value: ~v)" v)]
[(expression (== @extract) i j e)
(bitwuzla-wfcheck e cache)]
[(expression (or (== @sign-extend) (== @zero-extend)) v t)
(bitwuzla-wfcheck v cache)]
[(expression op es ...)
(for ([e es]) (bitwuzla-wfcheck e cache))]
[_ #t])]
[else
(unless (or (boolean? v) (bv? v))
(error 'bitwuzla "bitwuzla does not support value (expected boolean? or bv?): ~v" v))])))

View File

@ -107,27 +107,10 @@
; Reads the SMT solution from the server.
; The solution consists of 'sat or 'unsat, followed by
; followed by a suitably formatted s-expression. The
; output of this procedure is a hashtable from constant
; identifiers to their SMTLib values (if the solution is 'sat);
; a non-empty list of assertion identifiers that form an
; unsatisfiable core (if the solution is 'unsat and a
; core was extracted); #f (if the solution is
; 'unsat and no core was extracted); or 'unknown otherwise.
; This is the same as `base/read-solution` except that it applies some fixups
; for quirks in how various versions of Boolector have emitted models.
(define (boolector-read-solution server env)
(define raw-model
(parameterize ([current-readtable (make-readtable #f #\# #\a #f)]) ; read BV literals as symbols
(match (server-read server (read))
[(== 'sat)
(server-write server (get-model))
(match (server-read server (read))
[(list (== 'model) ... (and def (list (== 'define-fun) _ ...)) ...)
(for/hash ([d def]) (values (cadr d) d))]
[other (error 'read-solution "expected model, given ~a" other)])]
[(== 'unsat) 'unsat]
[(== 'unknown) 'unknown]
[other (error 'read-solution "unrecognized solver output: ~a" other)])))
(define raw-model (base/parse-solution server))
; First, we need to fix up the model's shadowing of incremental variables
(define stripped-raw-model (if (hash? raw-model) (fixup-incremental-names raw-model) raw-model))
; Now decode in an environment with fake types for UFs

View File

@ -0,0 +1,68 @@
#lang racket
(require racket/runtime-path
"server.rkt" "env.rkt"
"../solver.rkt"
(prefix-in base/ "base-solver.rkt"))
(provide (rename-out [make-cvc5 cvc5]) cvc5? cvc5-available?)
(define-runtime-path cvc5-path (build-path ".." ".." ".." "bin" "cvc5"))
(define cvc5-opts '("-L" "smt2" "-q" "-m" "-i" "--bv-print-consts-as-indexed-symbols"))
(define (cvc5-available?)
(not (false? (base/find-solver "cvc5" cvc5-path #f))))
(define (make-cvc5 [solver #f] #:options [options (hash)] #:logic [logic #f] #:path [path #f])
(define config
(cond
[(cvc5? solver)
(base/solver-config solver)]
[else
(define real-cvc5-path (base/find-solver "cvc5" cvc5-path path))
(when (and (false? real-cvc5-path) (not (getenv "PLT_PKG_BUILD_SERVICE")))
(error 'cvc5 "cvc5 binary is not available (expected to be at ~a); try passing the #:path argument to (cvc5)" (path->string (simplify-path cvc5-path))))
(base/config options real-cvc5-path logic)]))
(cvc5 (server (base/config-path config) cvc5-opts (base/make-send-options config)) config '() '() '() (env) '()))
(struct cvc5 base/solver ()
#:property prop:solver-constructor make-cvc5
#:methods gen:custom-write
[(define (write-proc self port mode) (fprintf port "#<cvc5>"))]
#:methods gen:solver
[
(define (solver-features self)
'(qf_bv))
(define (solver-options self)
(base/solver-options self))
(define (solver-assert self bools)
(base/solver-assert self bools))
(define (solver-minimize self nums)
(base/solver-minimize self nums))
(define (solver-maximize self nums)
(base/solver-maximize self nums))
(define (solver-clear self)
(base/solver-clear self))
(define (solver-shutdown self)
(base/solver-shutdown self))
(define (solver-push self)
(base/solver-push self))
(define (solver-pop self [k 1])
(base/solver-pop self k))
(define (solver-check self)
(base/solver-check self))
(define (solver-debug self)
(base/solver-debug self))])
(define (set-default-options server)
void)

View File

@ -14,7 +14,8 @@
@bvslt @bvsle @bvult @bvule
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
@bvneg @bvadd @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
@concat @extract))
@z3_ext_rotate_left @z3_ext_rotate_right
@concat @extract @sign-extend @zero-extend))
(provide decode-model)
@ -116,7 +117,6 @@
(hash-ref ~env id)]
[(== true) #t]
[(== false) #f]
[(? integer?) (inexact->exact expr)]
[(? real?) expr]
[(? symbol?)
(cond
@ -132,6 +132,10 @@
(bv n (bitvector len))]
[(list (list (== '_) (== 'extract) i j) s)
`(, @extract ,(inline i sol ~env) ,(inline j sol ~env) ,(inline s sol ~env))]
[(list (list (== '_) (== 'sign_extend) i) s)
`(, @sign-extend ,(inline i sol ~env) ,(inline s sol ~env))]
[(list (list (== '_) (== 'zero_extend) i) s)
`(, @zero-extend ,(inline i sol ~env) ,(inline s sol ~env))]
[(list (== 'let) binds body)
(substitute (inline body sol ~env)
(for/hash ([id:expr binds])
@ -162,6 +166,7 @@
'bvslt @bvslt 'bvsle @bvsle 'bvult @bvult 'bvule @bvule
'bvnot @bvnot 'bvor @bvor 'bvand @bvand 'bvxor @bvxor
'bvshl @bvshl 'bvlshr @bvlshr 'bvashr @bvashr
'ext_rotate_left @z3_ext_rotate_left 'ext_rotate_right @z3_ext_rotate_right
'bvneg @bvneg 'bvadd @bvadd 'bvmul @bvmul
'bvudiv @bvudiv 'bvsdiv @bvsdiv
'bvurem @bvurem 'bvsrem @bvsrem

View File

@ -16,6 +16,7 @@
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
@bvneg @bvadd @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
@concat @extract @zero-extend @sign-extend
@z3_ext_rotate_left @z3_ext_rotate_right
@integer->bitvector @bitvector->integer @bitvector->natural))
(provide enc)
@ -108,6 +109,7 @@
[@bveq $=] [@bvslt $bvslt] [@bvsle $bvsle] [@bvult $bvult] [@bvule $bvule]
[@bvnot $bvnot] [@bvor $bvor] [@bvand $bvand] [@bvxor $bvxor]
[@bvshl $bvshl] [@bvlshr $bvlshr] [@bvashr $bvashr]
[@z3_ext_rotate_left $ext_rotate_left] [@z3_ext_rotate_right $ext_rotate_right]
[@bvneg $bvneg] [@bvadd $bvadd] [@bvmul $bvmul] [@bvudiv $bvudiv] [@bvsdiv $bvsdiv]
[@bvurem $bvurem] [@bvsrem $bvsrem] [@bvsmod $bvsmod] [@concat $concat])

View File

@ -68,7 +68,8 @@
bvnot bvand bvor bvxor
bvule bvult bvuge bvugt bvsle bvslt bvsge bvsgt
bvneg bvadd bvsub bvmul bvsdiv bvudiv bvurem bvsrem bvsmod
bvshl bvlshr bvashr concat)
bvshl bvlshr bvashr concat
ext_rotate_left ext_rotate_right)
(define (extract i j s)
`((_ extract ,i ,j) ,s))

View File

@ -0,0 +1,69 @@
#lang racket
(require racket/runtime-path
"server.rkt" "env.rkt"
"../solver.rkt"
(prefix-in base/ "base-solver.rkt"))
(provide (rename-out [make-stp stp]) stp? stp-available?)
(define-runtime-path stp-path (build-path ".." ".." ".." "bin" "stp"))
(define stp-opts '("--SMTLIB2"))
(define (stp-available?)
(not (false? (base/find-solver "stp" stp-path #f))))
(define (make-stp [solver #f] #:options [options (hash)] #:logic [logic #f] #:path [path #f])
(define config
(cond
[(stp? solver)
(base/solver-config solver)]
[else
(define real-stp-path (base/find-solver "stp" stp-path path))
(when (and (false? real-stp-path) (not (getenv "PLT_PKG_BUILD_SERVICE")))
(error 'stp "stp binary is not available (expected to be at ~a); try passing the #:path argument to (stp)" (path->string (simplify-path stp-path))))
(base/config options real-stp-path logic)]))
(stp (server (base/config-path config) stp-opts (base/make-send-options config)) config '() '() '() (env) '()))
(struct stp base/solver ()
#:property prop:solver-constructor make-stp
#:methods gen:custom-write
[(define (write-proc self port mode) (fprintf port "#<stp>"))]
#:methods gen:solver
[
(define (solver-features self)
'(qf_bv))
(define (solver-options self)
(base/solver-options self))
(define (solver-assert self bools)
(base/solver-assert self bools))
(define (solver-minimize self nums)
(base/solver-minimize self nums))
(define (solver-maximize self nums)
(base/solver-maximize self nums))
(define (solver-clear self)
(base/solver-clear self))
(define (solver-shutdown self)
(base/solver-shutdown self))
(define (solver-push self)
(base/solver-push self))
(define (solver-pop self [k 1])
(base/solver-pop self k))
(define (solver-check self)
(base/solver-check self))
(define (solver-debug self)
(base/solver-debug self))])
(define (set-default-options server)
void)

View File

@ -0,0 +1,69 @@
#lang racket
(require racket/runtime-path
"server.rkt" "env.rkt"
"../solver.rkt"
(prefix-in base/ "base-solver.rkt"))
(provide (rename-out [make-yices yices]) yices? yices-available?)
(define-runtime-path yices-path (build-path ".." ".." ".." "bin" "yices-smt2"))
(define yices-opts '("--incremental"))
(define (yices-available?)
(not (false? (base/find-solver "yices-smt2" yices-path #f))))
(define default-logic 'QF_BV) ;; Yices2 needs a default logic set otherwise it will error
(define (make-yices [solver #f] #:options [options (hash)] #:logic [logic default-logic] #:path [path #f])
(define config
(cond
[(yices? solver)
(base/solver-config solver)]
[else
(define real-yices-path (base/find-solver "yices-smt2" yices-path path))
(when (and (false? real-yices-path) (not (getenv "PLT_PKG_BUILD_SERVICE")))
(error 'yices "yices-smt2 binary is not available (expected to be at ~a); try passing the #:path argument to (yices)" (path->string (simplify-path yices-path))))
(base/config options real-yices-path logic)]))
(yices (server (base/config-path config) yices-opts (base/make-send-options config)) config '() '() '() (env) '()))
(struct yices base/solver ()
#:property prop:solver-constructor make-yices
#:methods gen:custom-write
[(define (write-proc self port mode) (fprintf port "#<yices>"))]
#:methods gen:solver
[
(define (solver-features self)
'(qf_bv))
(define (solver-options self)
(base/solver-options self))
(define (solver-assert self bools)
(base/solver-assert self bools))
(define (solver-minimize self nums)
(base/solver-minimize self nums))
(define (solver-maximize self nums)
(base/solver-maximize self nums))
(define (solver-clear self)
(base/solver-clear self))
(define (solver-shutdown self)
(base/solver-shutdown self))
(define (solver-push self)
(base/solver-push self))
(define (solver-pop self [k 1])
(base/solver-pop self k))
(define (solver-check self)
(base/solver-check self))
(define (solver-debug self)
(base/solver-debug self))])
(define (set-default-options server)
void)

View File

@ -30,7 +30,9 @@
[else
(define real-z3-path (base/find-solver "z3" z3-path path))
(when (and (false? real-z3-path) (not (getenv "PLT_PKG_BUILD_SERVICE")))
(printf "warning: could not find z3 executable at ~a\n" (path->string (simplify-path z3-path))))
(fprintf (current-error-port)
"warning: could not find z3 executable at ~a\n"
(path->string (simplify-path z3-path))))
(define opts (hash-union default-options options #:combine (lambda (a b) b)))
(base/config opts real-z3-path logic)]))
(z3 (server (base/config-path config) z3-opts (base/make-send-options config)) config '() '() '() (env) '()))
@ -52,10 +54,10 @@
(base/solver-assert self bools))
(define (solver-minimize self nums)
(base/set-solver-mins! self (append (base/solver-mins self) (numeric-terms nums 'solver-minimize))))
(base/set-solver-mins! self (append (reverse (numeric-terms nums 'solver-minimize)) (base/solver-mins self))))
(define (solver-maximize self nums)
(base/set-solver-maxs! self (append (base/solver-maxs self) (numeric-terms nums 'solver-maximize))))
(base/set-solver-maxs! self (append (reverse (numeric-terms nums 'solver-maximize)) (base/solver-maxs self))))
(define (solver-clear self)
(base/solver-clear-stacks! self)

View File

@ -4,6 +4,10 @@
rosette/lib/roseunit
rosette/solver/smt/z3 rosette/solver/smt/cvc4
rosette/solver/smt/boolector
rosette/solver/smt/cvc5
rosette/solver/smt/bitwuzla
rosette/solver/smt/stp
rosette/solver/smt/yices
"config.rkt")
(error-print-width default-error-print-width)
@ -38,6 +42,7 @@
"base/distinct.rkt"
"base/generics.rkt"
"base/push-pop.rkt"
"base/optimize-order.rkt"
"base/reflect.rkt"
"base/decode.rkt"
"query/solve.rkt"
@ -80,6 +85,22 @@
(when (boolector-available?)
(printf "===== Running Boolector tests =====\n")
(run-tests-with-solver boolector))
(when (cvc5-available?)
(printf "===== Running cvc5 tests =====\n")
(run-tests-with-solver cvc5))
(when (bitwuzla-available?)
(printf "===== Running bitwuzla tests =====\n")
(run-tests-with-solver bitwuzla))
(when (stp-available?)
(printf "===== Running stp tests =====\n")
(run-tests-with-solver stp))
(when (yices-available?)
(printf "===== Running Yices2 tests =====\n")
(run-tests-with-solver yices))
)
(module+ test

View File

@ -0,0 +1,27 @@
#lang rosette
;; This test is taken from https://www.philipzucker.com/z3-rise4fun/optimization.html
(require rackunit rackunit/text-ui racket/generator
rosette/lib/roseunit)
(current-bitwidth #f)
(define-symbolic x y z integer?)
(define (check-model sol m)
(check-pred sat? sol)
(check-equal? (model sol) m))
(define optimization-order-tests
(test-suite+ "Tests for the optimization order"
#:features '(optimize)
(define solver (current-solver))
(solver-clear solver)
(solver-assert solver (list (< x z) (< y z) (< z 5) (not (= x y))))
(solver-maximize solver (list x))
(solver-maximize solver (list y))
(check-model (solver-check solver) (hash x 3 y 2 z 4))))
(module+ test
(time (run-tests optimization-order-tests)))

View File

@ -14,6 +14,10 @@
(define-symbolic b @boolean?)
(define-symbolic c @boolean?)
(define (f type)
(define-symbolic x type)
x)
(define (check-ordered v1 v2)
(check-true (and (or (term<? v1 v2) (term<? v2 v1))
(not (and (term<? v1 v2) (term<? v2 v1))))))
@ -49,7 +53,47 @@
(check-cached @/ x y)
(check-cached @remainder x y)
(check-cached @= x y)
(check-cached @< x y)))
(check-cached @< x y)
(f @integer?)
(check-exn #px"type should remain unchanged" (lambda () (f @boolean?)))))
(define clear-terms!+gc-terms!-tests
(test-suite+
"Tests for clear-terms! and gc-terms!"
(with-terms '()
(let ()
(define-symbolic x y z @integer?)
(define a (@+ x 1))
(define b (@+ y 2))
(define c (@+ z 3))
(check-equal? (length (terms)) 6)
;; this should evict z and c
(clear-terms! (list z))
(check-equal? (length (terms)) 4)
;; this doesn't affect strongly-held values
(set! b #f)
(check-equal? (length (terms)) 4)
(gc-terms!) ; change the representation
(collect-garbage)
(check-equal? (length (terms)) 3)
(clear-terms! (list x))
(collect-garbage)
(check-equal? (length (terms)) 1)
;; this is a dummy check to reference a, b, and c so that
;; they are not garbage-collected earlier
(check-equal? (length (list a b c)) 3)))))
(module+ test
(time (run-tests value-tests)))
(time (run-tests value-tests))
(time (run-tests clear-terms!+gc-terms!-tests)))