Compare commits

..

59 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
Luke Nelson 10178550a0 Properly handle tags in Docker workflow 2022-03-07 21:29:36 -08:00
Luke Nelson eeb5e127bc Run Docker workflow on tags 2022-03-07 21:25:33 -08:00
Luke Nelson e35e920b2f 4.1 Release notes 2022-03-07 20:33:05 -08:00
Luke Nelson bc90edd502 Use pretty-write instead of pretty-print in print-forms
Using an example from the Rosette documentation, compare the output of
pretty-print (with print-as-expression set to #t):

(list
 'define
 '(bvmul2_bitfast x)
 (list 'bvadd 'x (list 'bvxor 'x (bv #x00 8))))

With the output of pretty-write:

(define (bvmul2_bitfast x) (bvadd x (bvxor x (bv #x00 8))))

The latter is properly formatted as Racket code and matches what is
shown in the Rosette guide.

Partially reverts 8fabaa8a0a ("Cleanup.").
2022-03-07 17:11:09 -08:00
dependabot[bot] c53aff68f8 Bump Bogdanp/setup-racket from 1.1 to 1.7
Bumps [Bogdanp/setup-racket](https://github.com/Bogdanp/setup-racket) from 1.1 to 1.7.
- [Release notes](https://github.com/Bogdanp/setup-racket/releases)
- [Commits](https://github.com/Bogdanp/setup-racket/compare/v1.1...v1.7)

---
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-03-07 14:37:07 -06:00
Nicolas Jeannerod 54e1df67f9
Add Docker image and continuous deployment for it (#219)
* Add Docker image and continuous deployment for it

* Implement suggestions by @lukenels & @jamesbornholt

* Cleanup unused comments

* ensure `expeditor` is available for the REPL
2022-03-07 11:56:14 -08:00
Emina Torlak 9d14d447d0 Fix ite* rewrite bug. 2021-12-05 21:16:58 -08:00
Emina Torlak 3d84cdc17f Bump up the required Racket version to 8.1. 2021-11-18 15:19:44 -08:00
Emina Torlak 8684625ffd Bump up the required Racket version to 8.1. 2021-11-18 15:16:37 -08:00
sorawee c6e8dbc2ff
Fix bitvector type sharing in extract and use hasheq (#207)
extract seems to unintentionally de-shares bitvector types. This PR
makes the types shared properly again.

The hasheq change is technically backward-incompatible for programs that use
(bitvector 2^64), but I really hope no one does that in practice.
2021-11-18 15:09:49 -08:00
James Bornholt 2e2896db37
Fix model parsing for Boolector 3.2.2 (#206)
The latest Boolector release [changed][] the format of SMT models to conform
to the SMT-LIB spec by not including the `model` symbol, which our
parser was expecting (mostly because that's what Z3 does). It's not hard
to support both versions, so let's do that.

[changed]: 5c862bcdbc
2021-11-10 18:54:11 -08:00
Emina Torlak dbfd8476d9 Weakens the synthesize query to match the documented formula (Closes #205). 2021-11-06 13:46:45 -07:00
James Bornholt 7ac31ffbb4
Fix one more spurious CAS failure (#199)
Follow-up to #198.
2021-07-23 16:19:25 -07:00
sorawee 7cac2c93a5
Workaround spurious CAS failures (#198)
* Workaround spurious CAS failures

Some processors, such as ARM, can't perform the CAS (compare-and-swap)
operation accurately. So we simply retry on failure for several times.

* retry the right way
2021-07-23 09:28:53 -05:00
John Clements 38743f6a5f
remove dependency on now-nonexistent file (#191)
* remove dependency on now-nonexistent file

see commit c76b803836 which removes
the file and the use of define/lift

* remove rosette/lib/lift from tooltip in guide docs
2021-05-20 08:36:22 -07:00
Emina Torlak 9f6322c9da Drop outdated support for Yices (#189). 2021-04-16 13:41:10 -07:00
Emina Torlak 3432d9529d Add int2bv feature to bvlib rotate tests (#189). 2021-04-16 12:39:27 -07:00
sorawee a7ea8a849b
optimize: restrict keyword to #:maximize and #:minimize (#188)
* optimize: restrict keyword to #:maximize and #:minimize

* allow #:maximize and then #:minimize

Providing #:minimize twice will still be prohibited,
since it will error already by function application
after the expansion of `optimize`.
2021-04-14 13:12:03 -07:00
sorawee a64e2bccfe
Scribble-ify (#184)
- More linkify
- Fix minor typos
- Fix quote style
2021-03-18 08:45:45 -07:00
52 changed files with 958 additions and 439 deletions

6
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,6 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"

50
.github/workflows/docker.yml vendored Normal file
View File

@ -0,0 +1,50 @@
name: Docker
on:
push:
tags:
- '*'
branches:
- master
pull_request:
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Clone Repository
uses: actions/checkout@v4
- name: Configure Docker Metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=ref,event=tag
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Authenticate to Package Registry
uses: docker/login-action@v3
if: ${{ github.event_name != 'pull_request' }}
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and Publish Rosette Image
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

View File

@ -5,12 +5,16 @@ 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:
strategy:
matrix:
racket-version: ['8.0', 'current']
racket-version: ['8.1', 'current']
racket-variant: ['CS']
allow-failure: [false]
name: Racket ${{ matrix.racket-version }} (${{ matrix.racket-variant }})
@ -19,12 +23,14 @@ jobs:
steps:
- uses: actions/checkout@master
- name: Setup Racket
uses: Bogdanp/setup-racket@v1.1
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

97
Dockerfile Normal file
View File

@ -0,0 +1,97 @@
FROM alpine:3.15
## ========================== [ Install Racket ] =========================== ##
## Define default Racket version and variant. The Racket version is of the form
## <major>.<minor>. The variant can be "cs" (Chez Scheme), "bc" (Before Chez) or
## "natipkg" (where external libraries are included in the Racket packages).
##
ARG RACKET_VERSION=8.4
ARG RACKET_VARIANT=cs
## Install Racket. We first install system dependencies: [gcompat] is needed for
## Racket and [ncurses] is needed for the [xrepl] and [expeditor] packages,
## providing the REPL. We then download the installer, run it with the right
## parameters, then remove it. After that, all that remains is to set-up the
## Racket packages and install [expeditor]. See later for a description of the
## arguments to [raco pkg install].
##
RUN apk add --no-cache gcompat ncurses
RUN wget "https://download.racket-lang.org/installers/${RACKET_VERSION}/racket-minimal-${RACKET_VERSION}-x86_64-linux-${RACKET_VARIANT}.sh"
RUN echo 'yes\n1\n' | sh racket-minimal-${RACKET_VERSION}-x86_64-linux-${RACKET_VARIANT}.sh --create-dir --unix-style --dest /usr/
RUN rm racket-minimal-${RACKET_VERSION}-x86_64-linux-${RACKET_VARIANT}.sh
RUN raco setup --no-docs
RUN raco pkg install -i --batch --auto --no-docs expeditor-lib
## =================== [ Install Rosette's Dependencies ] =================== ##
## Work on Rosette's installation within /usr/local. This directory will be
## cleaned up later on so it could be anything.
##
WORKDIR /usr/local/rosette
## Get all the info.rkt files. Trying to install Rosette based only on these
## files would fail, but we can use them to only install dependencies.
##
COPY info.rkt .
COPY rosette/info.rkt rosette/
## Install only Rosette's dependencies. We have to install the external
## dependencies [libstdc++] and [libgcc] because Z3 needs them at runtime. As
## for the Racket dependencies only, we achieve that in three steps:
##
## 1. We use [raco pkg install --no-setup] to download and register Rosette
## and all its dependencies without setting them up, that is without
## compiling them. At this point, the system is in an inconsistent state,
## where packages are registered but not actually present. The other flags
## are the following:
##
## -i install packages for all users
## --batch disable interactive mode and suppress prompts
## --auto download missing packages automatically
##
## 2. We use [raco pkg remove --no-setup] to unregister Rosette. This keeps
## the dependencies as registered. The system is still in an inconsistent
## state. See above for the flags.
##
## 3. We use [raco setup] to set up all the registered package. This brings
## the system back in a consistent state. Since Rosette's dependencies were
## registered but not Rosette itself, this achieves our goal. The flags are
## the following:
##
## --fail-fast fail on the first error encountered
## --no-docs do not compile the documentations
##
RUN apk add --no-cache libstdc++ libgcc
RUN raco pkg install -i --batch --auto --no-setup ../rosette
RUN raco pkg remove -i --no-setup rosette
RUN raco setup --fail-fast --no-docs
## ========================== [ Install Rosette ] =========================== ##
## Get all of Rosette; build and install it. The dependencies should all be
## installed, so we can remove the --auto flag which will lead us to failure if
## a dependency cannot be found. The additional flags are the following:
##
## --copy copy content to install path (instead of linking)
##
COPY . .
RUN raco pkg install -i --batch --copy --no-docs ./rosette
RUN rm -R /usr/local/rosette
## ===================== [ Prepare Clean Entry Point ] ====================== ##
## For further use of the image, we can start with user `rosette`, group
## `rosette` in `/rosette` by default.
##
RUN addgroup rosette
RUN adduser --system --shell /bin/false --disabled-password \
--home /rosette --ingroup rosette rosette
RUN chown -R rosette:rosette /rosette
USER rosette
WORKDIR /rosette
## Rosette files are simply Racket files using the Rosette library: the default
## entry point of this image is therefore the Racket executable.
##
ENTRYPOINT ["/usr/bin/racket", "-I", "rosette"]

View File

@ -1,5 +1,9 @@
# Release Notes
## Version 4.1
This is a minor bug-fixing release.
## Version 4.0
This is a major release with significant changes to the language and the runtime. Rosette 4.0 is *not backward compatible* with Rosette 3.x. But porting Rosette 3.x code to Rosette 4.0 should be straightforward for most applications.

View File

@ -9,7 +9,7 @@ The Rosette Language
The easiest way to install Rosette is from Racket's package manager:
* Download and install Racket 8.0 or later from http://racket-lang.org
* Download and install Racket 8.1 or later from http://racket-lang.org
* Use Racket's `raco` tool to install Rosette:
@ -19,7 +19,7 @@ The easiest way to install Rosette is from Racket's package manager:
Alternatively, you can install Rosette from source:
* Download and install Racket 8.0 or later from http://racket-lang.org
* Download and install Racket 8.1 or later from http://racket-lang.org
* Clone the rosette repository:

View File

@ -5,7 +5,7 @@
(define deps '("custom-load"
"sandbox-lib"
"scribble-lib"
("racket" #:version "8.0")
("racket" #:version "8.1")
"r6rs-lib"
"rfc6455"
"net-lib"

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,20 +14,19 @@
@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 ----------------- ;;
; Cache of all bitvector types constructed so far, mapping sizes to types.
(define bitvector-types (make-hash))
(define bitvector-types (make-hasheq))
; Returns the bitvector type of the given size.
(define (bitvector-type size)
(assert (exact-positive-integer? size) (argument-error 'bitvector "exact-positive-integer?" size))
(or (hash-ref bitvector-types size #f)
(let ([t (bitvector size)])
(hash-set! bitvector-types size t)
t)))
(assert (and (exact-positive-integer? size) (fixnum? size))
(argument-error 'bitvector "(and/c exact-positive-integer? fixnum?)" size))
(hash-ref! bitvector-types size (λ () (bitvector size))))
; Represents a bitvector type.
(struct bitvector (size)
@ -340,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)
@ -347,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 ----------------- ;;
@ -595,7 +603,7 @@
_))
(if (< i size)
(extract i j a)
(expression @bvop a (bitvector (add1 i))))]
(expression @bvop a (bitvector-type (add1 i))))]
[(_ _ _) (expression @extract i j x)]))
(define-operator @extract

View File

@ -152,7 +152,7 @@
(match* ((car p) (cdr p))
[(a (expression (== ite) a x _)) (cons a x)]
[(a (expression (== ite) (expression (== @!) a) _ x)) (cons a x)]
[((expression (== @!) a) (expression (== ite) a _ x)) (cons a x)]
[((and (expression (== @!) a) !a) (expression (== ite) a _ x)) (cons !a x)]
[(_ _) p]))

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

@ -140,7 +140,7 @@ equality (@racket[bveq]) and signed / unsigned versions of
[(bvor [x (bitvector n)] ...+) (bitvector n)]
[(bvxor [x (bitvector n)] ...+) (bitvector n)])]{
Returns the bitwise "and", "or", "xor" of one or more bitvector values of the same type.
Returns the bitwise ``and'', ``or'', ``xor'' of one or more bitvector values of the same type.
@examples[#:eval rosette-eval
(bvand (bv -1 4) (bv 2 4))
@ -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

@ -3,7 +3,11 @@
@(require (for-label
rosette/solver/solver rosette/solver/solution
rosette/solver/smt/z3 rosette/solver/smt/cvc4
rosette/solver/smt/boolector rosette/solver/smt/yices
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)
@ -21,8 +25,11 @@
rosette/solver/solution
rosette/solver/smt/z3
rosette/solver/smt/cvc4
rosette/solver/smt/yices
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
@ -30,8 +37,11 @@
rosette/solver/solution
rosette/solver/smt/z3
rosette/solver/smt/cvc4
rosette/solver/smt/yices
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
@ -281,37 +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}
@subsection{Yices}
@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 symbol? 'ALL]
[#: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["http://yices.csl.sri.com/"]{Yices} solver from SRI.
Returns a @racket[solver?] wrapper for the @hyperlink["https://yices.csl.sri.com/"]{Yices2} solver.
To use this solver, download and install Yices (version 2.6.0 or later),
and either add the @tt{yices-smt2} executable to your @tt{PATH}
or pass the path to the executable as the optional @racket[path] argument.
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. The default is @racket['ALL].
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 Yices
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 ':random-seed 5)]
will send the command @tt{(set-option :random-seed 5)} to Yices prior to solving.
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 Yices solver is available for use (i.e., Rosette can locate a @tt{yices-smt2} binary).
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

@ -3,6 +3,7 @@
@(require (for-label
rosette/base/form/define rosette/query/query
rosette/base/core/term
rosette/solver/solution
(only-in rosette/base/base assert define-symbolic union?
vc clear-vc! bitvector bitvector? bv?
bitvector->natural integer->bitvector

View File

@ -1,19 +1,21 @@
#lang scribble/manual
@(require (for-label racket (only-in racket/sandbox with-deep-time-limit))
(for-label
@(require (for-label
racket
(only-in racket/sandbox with-deep-time-limit)
rosette/base/form/define
(only-in rosette/base/base assert assume vc vc-asserts vc-assumes clear-vc!)
rosette/query/query
(only-in rosette/base/base bv? bitvector
rosette/solver/solution
(only-in rosette/base/base
assert assume vc vc-asserts vc-assumes clear-vc!
bv? bitvector
bvsdiv bvadd bvsle bvsub bvand
bvor bvxor bvshl bvlshr bvashr
bvnot bvneg)
rosette/lib/synthax))
@(require racket/sandbox racket/runtime-path scribble/core scribble/racket
scribble/example scribble/html-properties scriblib/footnote
(only-in racket [unsyntax racket/unsyntax]))
@(require racket/sandbox racket/runtime-path scribble/core scribble/racket
scribble/example scribble/html-properties scriblib/footnote)
@(require (only-in "../refs.scrbl" ~cite rosette:onward13 rosette:pldi14)
"../util/lifted.rkt")
@ -140,7 +142,7 @@ Assumptions behave analogously to assertions on both concrete and symbolic value
@section[#:tag "sec:queries"]{Solver-Aided Queries}
The solver reasons about assumed and asserted properties only when we ask a question about them---for example, "Does my program have an execution that violates an assertion while satisfying all the assumptions?" We pose such @emph{solver-aided queries} with the help of constructs explained in the remainder of this chapter.
The solver reasons about assumed and asserted properties only when we ask a question about them---for example, ``Does my program have an execution that violates an assertion while satisfying all the assumptions?'' We pose such @emph{solver-aided queries} with the help of constructs explained in the remainder of this chapter.
We will illustrate the queries on the following toy example. Suppose that we want to implement a
procedure @racket[bvmid] that takes as input two non-negative 32-bit integers, @racket[lo] ≤ @racket[hi],
@ -321,7 +323,7 @@ The synthesis query takes the form @racket[(synthesize #:forall #, @var[input] #
Rosette supports one more solver-aided query, which we call angelic execution. This query is the dual of verification. Given a program with symbolic values, it instructs the solver to find a binding for them that will cause the program to execute normally---that is, without any assumption or assertion failures.
Angelic execution can be used to solve puzzles, to run incomplete code, or to "invert" a program, by searching for inputs that produce a desired output. For example, we can ask the solver to search for two distinct legal inputs, @racket[l] and @racket[h], whose midpoint is the bitwise-and of their bits:
Angelic execution can be used to solve puzzles, to run incomplete code, or to ``invert'' a program, by searching for inputs that produce a desired output. For example, we can ask the solver to search for two distinct legal inputs, @racket[l] and @racket[h], whose midpoint is the bitwise-and of their bits:
@examples[#:eval rosette-eval #:label #f
(define (bvmid-fast lo hi)
(bvlshr (bvadd hi lo) (bv #x00000001 32)))
@ -480,7 +482,7 @@ n2
n3]
In general, recursion terminates under symbolic evaluation only when the stopping condition is reached with concrete values.
We can force termination by placing a concrete bound @var{k} on the number of times @racket[bvsqrt] can call itself recursively. This approach is called @deftech{finitization}, and it is the standard way to handle unbounded loops and recursion under symbolic evaluation. The following code shows how to implement a @emph{sound} finitization policy. If a @racket[verify] query returns @racket[(unsat)] under a sound policy, we know that (1) the unrolling bound @var{k} is sufficient to execute all possible inputs to @racket[bvsqrt], and (2) all of these executions satisfy the query. If we pick a bound that is too small, the query will generate a counterexample input that needs a larger bound to compute the result. In our example, the bound of 16 is sufficient to verify the correctness of @racket[sqrt] on all inputs:
We can force termination by placing a concrete bound @var{k} on the number of times @racket[bvsqrt] can call itself recursively. This approach is called @deftech{finitization}, and it is the standard way to handle unbounded loops and recursion under symbolic evaluation. The following code shows how to implement a @emph{sound} finitization policy. If a @racket[verify] query returns @racket[(unsat)] under a sound policy, we know that (1) the unrolling bound @var{k} is sufficient to execute all possible inputs to @racket[bvsqrt], and (2) all of these executions satisfy the query. If we pick a bound that is too small, the query will generate a counterexample input that needs a larger bound to compute the result. In our example, the bound of 16 is sufficient to verify the correctness of @racket[bvsqrt] on all inputs:
@(rosette-eval '(clear-vc!))
@(rosette-eval '(require (only-in racket make-parameter parameterize)))
@examples[#:eval rosette-eval #:label #f #:no-prompt

View File

@ -5,7 +5,7 @@
@title[#:tag "ch:syntactic-forms" #:style 'toc]{Syntactic Forms}
The core of the Rosette language (@racket[rosette/safe]) consists of two kinds of syntax forms: a set of basic forms @deftech[#:key "lifted constructs"]{lifted} from Racket, and a set of forms for @seclink["ch:essentials"]{solver-aided programming}. We use the term "lifted" to refer to parts of the Racket language that can be used with symbolic values and other solver-aided constructs.
The core of the Rosette language (@racketmodname[rosette/safe]) consists of two kinds of syntax forms: a set of basic forms @deftech[#:key "lifted constructs"]{lifted} from Racket, and a set of forms for @seclink["ch:essentials"]{solver-aided programming}. We use the term ``lifted'' to refer to parts of the Racket language that can be used with symbolic values and other solver-aided constructs.
@[table-of-contents]
@include-section["racket-forms.scrbl"]

View File

@ -4,7 +4,7 @@
@title[#:tag "ch:libraries" #:style 'toc]{Libraries}
Chapters @seclink["ch:getting-started"]{1}-@seclink["ch:programmer-defined-datatypes"]{5} introduce the basic constructs and datatypes for programming in Rosette. This chapter describes the parts of the core Racket libraries (e.g., I/O procedures) that are exported by @racket[rosette/safe], as well as Rosette libraries that provide additional facilities for solver-aided development.
Chapters @seclink["ch:getting-started"]{1}-@seclink["ch:programmer-defined-datatypes"]{5} introduce the basic constructs and datatypes for programming in Rosette. This chapter describes the parts of the core Racket libraries (e.g., I/O procedures) that are exported by @racketmodname[rosette/safe], as well as Rosette libraries that provide additional facilities for solver-aided development.
@[table-of-contents]

View File

@ -17,5 +17,4 @@ Rosette exports the following facilities from the core Racket libraries:
These facilities are safe to use in Rosette programs, even in the presence of symbolic values, assertions, and solver-aided queries. They are not, however, @tech[#:key "lifted constructs"]{lifted}: if their Racket implementation expects a concrete value of a given type, they will fail when given a symbolic value. These constructs are safe to use in the sense that they will fail in a predictable fashion, according to their concrete Racket specification, instead of causing the enclosing Rosette program to exhibit unexpected behavior.
The @racket[rosette/safe] language allows programs to import arbitrary Racket code using the standard @racket[require] mechanism. This is strongly discouraged, however, unless the use of such code obeys the restrictions outlined in the @seclink["ch:unsafe"]{Chapter 8}. Violating these restrictions may lead to incorrect program behavior, crashes, and loss of data (for programs that perform external side-effects, such as writing to files). In other words, arbitrary Racket code is, by default, unsafe to use.
The @racketmodname[rosette/safe] language allows programs to import arbitrary Racket code using the standard @racket[require] mechanism. This is strongly discouraged, however, unless the use of such code obeys the restrictions outlined in the @seclink["ch:unsafe"]{Chapter 8}. Violating these restrictions may lead to incorrect program behavior, crashes, and loss of data (for programs that perform external side-effects, such as writing to files). In other words, arbitrary Racket code is, by default, unsafe to use.

View File

@ -367,7 +367,7 @@ sol
generated for programs that have been saved to disk.
This procedure cooperates with the constructs in the
@racket[rosette/lib/synthax] library to turn solutions into
@racketmodname[rosette/lib/synthax] library to turn solutions into
code. It works by scanning program files for
@racketlink[??]{constant}, @racketlink[choose]{choice}, and
@racketlink[define-grammar]{grammar} holes, and replacing

View File

@ -55,7 +55,7 @@ integers and reals (while being correct under the
finite-precision semantics). For example, this program
incorrectly says that no integer greater than 15 exists,
because the setting of @racket[current-bitwidth] causes it
to consider only values of @racket{x} that can be
to consider only values of @racket[x] that can be
represented as a 5-bit bitvector.
@examples[#:eval rosette-eval #:label #f
@ -387,15 +387,15 @@ the performance of @tt{verify-xform} to degrade, from a
couple of seconds when @tt{N} = 5 to over a minute when @tt{N}
= 20. To identify the source of this performance issue, we
can invoke the @tech{symbolic profiler} on the verifier,
producing the output below (after selecting the "Collapse
solver time" checkbox):
producing the output below (after selecting the ``Collapse
solver time'' checkbox):
@(image profile-xform.png #:scale 0.425)
The symbolic profiler identifies @tt{list-set} as the
bottleneck in this program. The output shows that @tt{list-set}
creates many symbolic terms, and performs many symbolic
operations (the "Union Size" and "Merge Cases" columns).
operations (the ``Union Size'' and ``Merge Cases'' columns).
The core issue here is an @tech{algorithmic mismatch}: @tt{list-set}
makes a recursive call guarded by a short-circuiting

View File

@ -241,8 +241,8 @@ as well as for tuning the performance of symbolic
evaluation.
@declare-exporting[rosette/base/core/forall rosette/lib/lift
#:use-sources (rosette/base/core/forall rosette/lib/lift)]
@declare-exporting[rosette/base/core/forall
#:use-sources (rosette/base/core/forall)]
@defform[(for/all ([id val-expr maybe-exhaustive]) body ...+)
#:grammar [(maybe-exhaustive (code:line) #:exhaustive)]]{

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)"))
@(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 ".")
@ -13,20 +13,20 @@
@title[#:tag "ch:unsafe"]{Unsafe Operations}
Throughout this guide, we have assumed that Rosette programs are
written in the @racket[rosette/safe] dialect of the full language.
written in the @racketmodname[rosette/safe] dialect of the full language.
This dialect extends a core subset of Racket with @seclink["ch:essentials"]{solver-aided
functionality}. In this chapter, we briefly discuss the @racket[rosette]
functionality}. In this chapter, we briefly discuss the @racketmodname[rosette]
dialect of the language, which exports all of Racket.
Safe use of the full @racket[rosette] language requires a basic understanding
of how Rosette's Symbolic Virtual Machine (SVM) works @~cite[rosette:pldi14].
Safe use of the full @racketmodname[rosette] language requires a basic understanding
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 @racket[rosette/safe]. Any programs that are
implemented exclusively in the @racket[rosette/safe] language are therefore
constructs that are exported by @racketmodname[rosette/safe]. Any programs that are
implemented exclusively in the @racketmodname[rosette/safe] language are therefore
fully under the SVM's control. This means that the SVM can correctly interpret
the application of a procedure or a macro to a symbolic value, and it
can correctly handle any side-effects (in particular, writes to memory) performed
by @racket[rosette/safe] code.
by @racketmodname[rosette/safe] code.
The following snippet demonstrates the non-standard execution that the SVM needs to
perform in order to assign the expected meaning to Rosette code:
@ -53,17 +53,17 @@ y
(define sol2 (solve (assert (not b))))
(evaluate y sol2)]
Because the SVM controls only the execution of @racket[rosette/safe] code,
it cannot, in general, guarantee the safety or correctness of arbitrary @racket[rosette] programs.
As soon as a @racket[rosette] program calls an @tech[#:key "lifted construct"]{unlifted} Racket construct
(that is, a procedure or a macro not implemented in or provided by the @racket[rosette/safe] language),
Because the SVM controls only the execution of @racketmodname[rosette/safe] code,
it cannot, in general, guarantee the safety or correctness of arbitrary @racketmodname[rosette] programs.
As soon as a @racketmodname[rosette] program calls an @tech[#:key "lifted construct"]{unlifted} Racket construct
(that is, a procedure or a macro not implemented in or provided by the @racketmodname[rosette/safe] language),
the execution escapes back to the Racket interpreter. The SVM has no control over the side-effects
performed by the Racket interpreter, or the meaning that it (perhaps incorrectly) assigns to programs
in the presence of symbolic values. As a result, the programmer is responsible for ensuring that
a @racket[rosette] program continues to behave correctly after the execution returns from the Racket interpreter.
a @racketmodname[rosette] program continues to behave correctly after the execution returns from the Racket interpreter.
As an example of incorrect behavior, consider the following @racket[rosette] snippet.
The procedures @racket[make-hash], @racket[hash-ref], and @racket[hash-clear!] are not in @racket[rosette/safe].
As an example of incorrect behavior, consider the following @racketmodname[rosette] snippet.
The procedures @racket[make-hash], @racket[hash-ref], and @racket[hash-clear!] are not in @racketmodname[rosette/safe].
Whenever they are invoked, the execution escapes to the Racket interpreter.
@(rosette-eval '(require (only-in racket make-hash hash-clear! hash-ref)))

View File

@ -16,13 +16,13 @@ Rosette is a @emph{solver-aided} programming system with two components:
compiles them to logical constraints. The SVM enables Rosette
to use the solver to automatically reason about program behaviors.}]
The name "Rosette" refers both to the language and the whole system.
The name ``Rosette'' refers both to the language and the whole system.
@section[#:tag "sec:get"]{Installing Rosette}
To install Rosette, you will need to
@itemlist[@item{Download and install @hyperlink["http://racket-lang.org"]{Racket} (version 8.0 or later).}
@itemlist[@item{Download and install @hyperlink["http://racket-lang.org"]{Racket} (version 8.1 or later).}
@item{Use Racket's @tt{raco} tool to install Rosette:
@nested{
@verbatim|{> raco pkg install rosette}|}}]

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

@ -78,8 +78,13 @@
; all events from the box. if that happened then the ENTER we're trying
; to delete has already been published, and so we need to retain the
; corresponding EXIT.
(unless (box-cas! the-box evts (cdr evts))
(do-record-exit! out))]))))))
(let loop ()
(unless (box-cas! the-box evts (cdr evts))
(if (eq? evts (unbox the-box))
; spurious CAS failure; retry
(loop)
; box has changed, so we need to retain the EXIT
(do-record-exit! out))))]))))))
; Default version just uses the current-profile/current-reporter params
(define default-record-exit

View File

@ -296,4 +296,4 @@
(define (print-forms sol)
(for ([f (generate-forms sol)])
(printf "~a:~a:~a\n" (syntax-source f) (syntax-line f) (syntax-column f))
(pretty-print (syntax->datum f))))
(pretty-write (syntax->datum f))))

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

@ -14,37 +14,40 @@
; the procedure for handling connections
(define (ws-connection conn _state)
; only one client may connect
(cond
[(box-cas! connected? #f #t) ; we won the race to connect
; tell the main thread we're connected
(channel-put channel 'connected)
; loop until we're done
(let loop ()
(define sync-result (sync/timeout/enable-break interval channel))
(define messages (get-message))
(let loop ()
(cond
[(box-cas! connected? #f #t) ; we won the race to connect
; tell the main thread we're connected
(channel-put channel 'connected)
; loop until we're done
(let loop ()
(define sync-result (sync/timeout/enable-break interval channel))
(define messages (get-message))
; send the messages; bail out if it fails
(define continue? (not (eq? sync-result 'finish)))
(with-handlers ([exn:fail? (lambda (e)
(eprintf "~e\n" e)
(set! continue? #f))])
(ws-send! conn (jsexpr->bytes messages)))
(if continue?
(loop)
(begin
(with-handlers ([exn:fail? void]) ; the connection might be dead, but we don't care
(ws-send! conn (jsexpr->bytes (list (get-finish-message))))
(ws-close! conn))
; if we weren't told to shut down, we need to wait until we are.
(cond
[on-shutdown (on-shutdown)]
[else
(unless (eq? sync-result 'finish)
(channel-get channel))
(channel-put channel 'finish)]))))]
[else
(channel-put channel "another client is already connected")
(ws-close! conn)]))
; send the messages; bail out if it fails
(define continue? (not (eq? sync-result 'finish)))
(with-handlers ([exn:fail? (lambda (e)
(eprintf "~e\n" e)
(set! continue? #f))])
(ws-send! conn (jsexpr->bytes messages)))
(if continue?
(loop)
(begin
(with-handlers ([exn:fail? void]) ; the connection might be dead, but we don't care
(ws-send! conn (jsexpr->bytes (list (get-finish-message))))
(ws-close! conn))
; if we weren't told to shut down, we need to wait until we are.
(cond
[on-shutdown (on-shutdown)]
[else
(unless (eq? sync-result 'finish)
(channel-get channel))
(channel-put channel 'finish)]))))]
[(unbox connected?)
;; it's already connected
(channel-put channel "another client is already connected")
(ws-close! conn)]
[else (loop)])))
; start the server
(define conf-channel (make-async-channel))

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

@ -150,12 +150,12 @@
; ∃H. (∀I. assumes => asserts) ∧ (∃I. assumes).
(define (cegis inputs assumes asserts guesser checker)
(define φ (append assumes asserts))
(define φ `(,(=> (apply && assumes) (apply && asserts))))
(define ¬φ `(,@assumes ,(apply || (map ! asserts))))
(define (guess sol)
(solver-assert guesser (evaluate φ sol))
(define (guess ψ)
(solver-assert guesser ψ)
(match (solver-check guesser)
[(model m) (sat (for/hash ([(c v) m] #:unless (member c inputs)) (values c v)))]
[other other]))
@ -171,14 +171,14 @@
v)))))]
[other other]))
(let loop ([candidate (begin0 (guess (sat)) (solver-clear guesser))])
(let loop ([candidate (guess (append assumes asserts))])
(cond
[(unsat? candidate) candidate]
[else
(let ([cex (check candidate)])
(cond
[(unsat? cex) candidate]
[else (loop (guess cex))]))])))
[else (loop (guess (evaluate φ cex)))]))])))

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

@ -1,6 +1,7 @@
#lang racket
(require "core.rkt"
(require syntax/parse/define
"core.rkt"
(only-in "../base/core/reflect.rkt" symbolics)
(only-in "../base/core/result.rkt" result-state)
(only-in "../base/core/bool.rkt" ! vc with-vc vc-assumes vc-asserts vc-true))
@ -70,14 +71,15 @@
; generate any assumptions or assertions, these are reflected in the (vc) after
; the optimize query returns. The assumptions and assertions generated by expr
; are not added to (vc) after optimize returns.
(define-syntax optimize
(syntax-rules ()
[(_ kw opt #:guarantee expr)
(let ([obj opt] ; evaluate objective first to add its spec to (vc)
(define-syntax-parser optimize
[(_ {~and kw {~or* #:minimize #:maximize}} opt #:guarantee expr)
#'(let ([obj opt] ; evaluate objective first to add its spec to (vc)
[post (query-vc expr)])
(∃-solve `(,@(pre) ,(vc-assumes post) ,(vc-asserts post)) kw obj))]
[(_ kw1 opt1 kw2 opt2 #:guarantee expr)
(let ([obj1 opt1] ; evaluate objectives first to add their spec to (vc)
[(_ {~and kw1 {~or* #:minimize #:maximize}} opt1
{~and kw2 {~or* #:minimize #:maximize}} opt2
#:guarantee expr)
#'(let ([obj1 opt1] ; evaluate objectives first to add their spec to (vc)
[obj2 opt2]
[post (query-vc expr)])
(∃-solve `(,@(pre) ,(vc-assumes post) ,(vc-asserts post)) kw1 obj1 kw2 obj2))]))
(∃-solve `(,@(pre) ,(vc-assumes post) ,(vc-asserts post)) kw1 obj1 kw2 obj2))])

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
@ -131,26 +134,31 @@
; 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,28 +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) 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) '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

@ -1,13 +1,9 @@
#lang racket
(require racket/runtime-path
"server.rkt" "env.rkt" "cmd.rkt"
"server.rkt" "env.rkt"
"../solver.rkt"
(only-in "smtlib2.rkt" get-model echo)
(prefix-in base/ "base-solver.rkt")
(only-in "../../base/core/term.rkt" term? expression)
(only-in "../../base/core/bool.rkt" @forall @exists)
(only-in "../../base/core/bitvector.rkt" @integer->bitvector))
(prefix-in base/ "base-solver.rkt"))
(provide (rename-out [make-yices yices]) yices? yices-available?)
@ -15,17 +11,17 @@
(define yices-opts '("--incremental"))
(define (yices-available?)
(not (false? (base/find-solver "yices" yices-path #f))))
(define (make-yices [solver #f] #:options [options (hash)] #:logic [logic 'ALL] #:path [path #f])
(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" yices-path path))
(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 binary is not available (expected to be at ~a); try passing the #:path argument to (yices)" (path->string (simplify-path yices-path))))
(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) '()))
@ -36,13 +32,13 @@
#:methods gen:solver
[
(define (solver-features self)
'(qf_bv qf_uf qf_lia qf_lra))
'(qf_bv))
(define (solver-options self)
(base/solver-options self))
(define (solver-assert self bools)
(base/solver-assert self bools yices-wfcheck))
(base/solver-assert self bools))
(define (solver-minimize self nums)
(base/solver-minimize self nums))
@ -63,85 +59,11 @@
(base/solver-pop self k))
(define (solver-check self)
(base/solver-check self yices-read-solution))
(base/solver-check self))
(define (solver-debug self)
(base/solver-debug self))])
(define (set-default-options server)
void)
; Check whether a term v is well-formed for Yices -- it must not
; use integer->bitvector, which Yices doesn't support natively,
; nor a quantifier.
(define (yices-wfcheck v [cache (mutable-set)])
(unless (set-member? cache v)
(set-add! cache v)
(when (term? v)
(match v
[(expression (or (== @forall) (== @exists)) vars body)
(error 'yices "yices does not support quantified formulas (value: ~v)" v)]
[(expression (== @integer->bitvector) rest ...)
(error 'yices "yices does not support integer->bitvector (value: ~v)" v)]
[(expression op es ...)
(for ([e es]) (yices-wfcheck e cache))]
[_ #t]))))
; 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.
;
; For Yices, we need to adapt to its strange way of printing models,
; which are just a list of terms of the form (= x y), with no delimiters
; for the start and end of a model. We print a "done" symbol to detect when
; to stop reading terms. We also need to handle Yices' format for printing
; uninterpreted functions:
; (= x @fun_6)
; (function @fun_6
; (type (-> int int))
; (= (@fun_6 0) 0)
; (= (@fun_6 1) 1)
; (default 2))
; We convert these models into define-fun forms, with each case becoming
; a nested ITE. The define-fun forms have fake type information, since
; decode doesn't use it (preferring to use the type info from env).
(define (yices-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)
(echo "done"))
(let loop ([model (hash)][functions (hash)])
(match (server-read server (read))
[(list (== '=) var val)
(loop (hash-set model var `(define-fun ,var () X ,val)) functions)]
[(list (== 'function) var type cases ...)
(define args (for/list ([x (in-range (- (length (cadr type)) 2))]) (gensym)))
(define (call->guard call)
(if (equal? (length args) 1)
`(= ,(car args) ,(cadr call))
`(and ,@(for/list ([a args][c (cdr call)]) `(= ,a ,c)))))
(define fun
(let inner ([cases cases])
(match (car cases)
[(list (== 'default) val) val]
[(list (== '=) call val)
`(ite ,(call->guard call) ,val ,(inner (cdr cases)))])))
(loop model
(hash-set functions var `(define-fun ,var ,(for/list ([a args]) `(,a X)) X ,fun)))]
['done
(for/hash ([(var defn) (in-dict model)])
(define val (fifth defn))
(values var (hash-ref functions val defn)))]
[other (error 'read-solution "expected model, given ~a" other)]))]
[(== 'unsat) 'unsat]
[(== 'unknown) 'unknown]
[other (error 'read-solution "unrecognized solver output: ~a" other)])))
(decode raw-model env))

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

@ -1,7 +1,6 @@
#lang rosette
(require
rosette/lib/lift
(prefix-in racket/ (only-in racket string-append symbol->string regexp-match?)))
(provide (all-defined-out))

View File

@ -3,7 +3,11 @@
(require (only-in rosette solver-features current-solver) "base/solver.rkt"
rosette/lib/roseunit
rosette/solver/smt/z3 rosette/solver/smt/cvc4
rosette/solver/smt/boolector rosette/solver/smt/yices
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"
@ -81,8 +86,20 @@
(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 Yices tests =====\n")
(printf "===== Running Yices2 tests =====\n")
(run-tests-with-solver yices))
)

View File

@ -272,13 +272,13 @@
(define tests:rotate-left
(test-suite+
"Tests for rotate-left in rosette/base/bvlib.rkt"
#:features '(qf_lia qf_bv)
#:features '(qf_lia int2bv qf_bv)
(check-rotate rotate-left rotate-right bvrol)))
(define tests:rotate-right
(test-suite+
"Tests for rotate-right in rosette/base/bvlib.rkt"
#:features '(qf_lia qf_bv)
#:features '(qf_lia int2bv qf_bv)
(check-rotate rotate-right rotate-left bvror)))
(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)))