Compare commits
No commits in common. "xenia/patches" and "4.0" have entirely different histories.
xenia/patc
...
4.0
|
|
@ -1,6 +0,0 @@
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
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
|
|
||||||
|
|
@ -5,16 +5,12 @@ on: [push, pull_request]
|
||||||
env:
|
env:
|
||||||
CVC4_URL: "http://cvc4.cs.stanford.edu/downloads/builds/x86_64-linux-opt/cvc4-1.8-x86_64-linux-opt"
|
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"
|
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:
|
jobs:
|
||||||
test:
|
test:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
racket-version: ['8.1', 'current']
|
racket-version: ['8.0', 'current']
|
||||||
racket-variant: ['CS']
|
racket-variant: ['CS']
|
||||||
allow-failure: [false]
|
allow-failure: [false]
|
||||||
name: Racket ${{ matrix.racket-version }} (${{ matrix.racket-variant }})
|
name: Racket ${{ matrix.racket-version }} (${{ matrix.racket-variant }})
|
||||||
|
|
@ -23,14 +19,12 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Setup Racket
|
- name: Setup Racket
|
||||||
uses: Bogdanp/setup-racket@v1.14
|
uses: Bogdanp/setup-racket@v1.1
|
||||||
with:
|
with:
|
||||||
architecture: x64
|
architecture: x64
|
||||||
version: ${{ matrix.racket-version }}
|
version: ${{ matrix.racket-version }}
|
||||||
variant: ${{ matrix.racket-variant }}
|
variant: ${{ matrix.racket-variant }}
|
||||||
- name: Install solvers
|
- 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: |
|
run: |
|
||||||
mkdir bin &&
|
mkdir bin &&
|
||||||
wget $CVC4_URL -nv -O bin/cvc4 &&
|
wget $CVC4_URL -nv -O bin/cvc4 &&
|
||||||
|
|
@ -46,50 +40,7 @@ jobs:
|
||||||
make &&
|
make &&
|
||||||
popd &&
|
popd &&
|
||||||
cp boolector/build/bin/boolector bin/ &&
|
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
|
- name: Install Rosette
|
||||||
run: raco pkg install --auto --name rosette
|
run: raco pkg install --auto --name rosette
|
||||||
- name: Compile Rosette tests
|
- name: Compile Rosette tests
|
||||||
|
|
|
||||||
97
Dockerfile
97
Dockerfile
|
|
@ -1,97 +0,0 @@
|
||||||
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"]
|
|
||||||
4
NOTES.md
4
NOTES.md
|
|
@ -1,9 +1,5 @@
|
||||||
# Release Notes
|
# Release Notes
|
||||||
|
|
||||||
## Version 4.1
|
|
||||||
|
|
||||||
This is a minor bug-fixing release.
|
|
||||||
|
|
||||||
## Version 4.0
|
## 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.
|
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.
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ The Rosette Language
|
||||||
|
|
||||||
The easiest way to install Rosette is from Racket's package manager:
|
The easiest way to install Rosette is from Racket's package manager:
|
||||||
|
|
||||||
* Download and install Racket 8.1 or later from http://racket-lang.org
|
* Download and install Racket 8.0 or later from http://racket-lang.org
|
||||||
|
|
||||||
* Use Racket's `raco` tool to install Rosette:
|
* 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:
|
Alternatively, you can install Rosette from source:
|
||||||
|
|
||||||
* Download and install Racket 8.1 or later from http://racket-lang.org
|
* Download and install Racket 8.0 or later from http://racket-lang.org
|
||||||
|
|
||||||
* Clone the rosette repository:
|
* Clone the rosette repository:
|
||||||
|
|
||||||
|
|
|
||||||
2
info.rkt
2
info.rkt
|
|
@ -5,7 +5,7 @@
|
||||||
(define deps '("custom-load"
|
(define deps '("custom-load"
|
||||||
"sandbox-lib"
|
"sandbox-lib"
|
||||||
"scribble-lib"
|
"scribble-lib"
|
||||||
("racket" #:version "8.1")
|
("racket" #:version "8.0")
|
||||||
"r6rs-lib"
|
"r6rs-lib"
|
||||||
"rfc6455"
|
"rfc6455"
|
||||||
"net-lib"
|
"net-lib"
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
|
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
|
||||||
@bvneg @bvadd @bvsub @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
|
@bvneg @bvadd @bvsub @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
|
||||||
@concat @extract @sign-extend @zero-extend
|
@concat @extract @sign-extend @zero-extend
|
||||||
@z3_ext_rotate_left @z3_ext_rotate_right
|
|
||||||
@integer->bitvector @bitvector->integer @bitvector->natural
|
@integer->bitvector @bitvector->integer @bitvector->natural
|
||||||
; core/bvlib.rkt
|
; core/bvlib.rkt
|
||||||
bit lsb msb bvzero? bvadd1 bvsub1
|
bit lsb msb bvzero? bvadd1 bvsub1
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,20 @@
|
||||||
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
|
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
|
||||||
@bvneg @bvadd @bvsub @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
|
@bvneg @bvadd @bvsub @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
|
||||||
@concat @extract @sign-extend @zero-extend
|
@concat @extract @sign-extend @zero-extend
|
||||||
@z3_ext_rotate_left @z3_ext_rotate_right
|
|
||||||
@integer->bitvector @bitvector->integer @bitvector->natural)
|
@integer->bitvector @bitvector->integer @bitvector->natural)
|
||||||
|
|
||||||
;; ----------------- Bitvector Types ----------------- ;;
|
;; ----------------- Bitvector Types ----------------- ;;
|
||||||
|
|
||||||
; Cache of all bitvector types constructed so far, mapping sizes to types.
|
; Cache of all bitvector types constructed so far, mapping sizes to types.
|
||||||
(define bitvector-types (make-hasheq))
|
(define bitvector-types (make-hash))
|
||||||
|
|
||||||
; Returns the bitvector type of the given size.
|
; Returns the bitvector type of the given size.
|
||||||
(define (bitvector-type size)
|
(define (bitvector-type size)
|
||||||
(assert (and (exact-positive-integer? size) (fixnum? size))
|
(assert (exact-positive-integer? size) (argument-error 'bitvector "exact-positive-integer?" size))
|
||||||
(argument-error 'bitvector "(and/c exact-positive-integer? fixnum?)" size))
|
(or (hash-ref bitvector-types size #f)
|
||||||
(hash-ref! bitvector-types size (λ () (bitvector size))))
|
(let ([t (bitvector size)])
|
||||||
|
(hash-set! bitvector-types size t)
|
||||||
|
t)))
|
||||||
|
|
||||||
; Represents a bitvector type.
|
; Represents a bitvector type.
|
||||||
(struct bitvector (size)
|
(struct bitvector (size)
|
||||||
|
|
@ -339,13 +340,6 @@
|
||||||
(ite (bveq (bv 0 t) (bvand x (bv (bvsmin t) t))) (bv 0 t) (bv -1 t))]
|
(ite (bveq (bv 0 t) (bvand x (bv (bvsmin t) t))) (bv 0 t) (bv -1 t))]
|
||||||
[(_ _) (expression @bvashr x y)]))
|
[(_ _) (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 @bvnot bvnot T*->T)
|
||||||
(define-lifted-operator @bvand bvand T*->T)
|
(define-lifted-operator @bvand bvand T*->T)
|
||||||
(define-lifted-operator @bvor bvor T*->T)
|
(define-lifted-operator @bvor bvor T*->T)
|
||||||
|
|
@ -353,8 +347,6 @@
|
||||||
(define-lifted-operator @bvshl bvshl T*->T)
|
(define-lifted-operator @bvshl bvshl T*->T)
|
||||||
(define-lifted-operator @bvlshr bvlshr T*->T)
|
(define-lifted-operator @bvlshr bvlshr T*->T)
|
||||||
(define-lifted-operator @bvashr bvashr 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 ----------------- ;;
|
;; ----------------- Simplification ruules for bitwise operators ----------------- ;;
|
||||||
|
|
||||||
|
|
@ -603,7 +595,7 @@
|
||||||
_))
|
_))
|
||||||
(if (< i size)
|
(if (< i size)
|
||||||
(extract i j a)
|
(extract i j a)
|
||||||
(expression @bvop a (bitvector-type (add1 i))))]
|
(expression @bvop a (bitvector (add1 i))))]
|
||||||
[(_ _ _) (expression @extract i j x)]))
|
[(_ _ _) (expression @extract i j x)]))
|
||||||
|
|
||||||
(define-operator @extract
|
(define-operator @extract
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@
|
||||||
(match* ((car p) (cdr p))
|
(match* ((car p) (cdr p))
|
||||||
[(a (expression (== ite) a x _)) (cons a x)]
|
[(a (expression (== ite) a x _)) (cons a x)]
|
||||||
[(a (expression (== ite) (expression (== @!) a) _ x)) (cons a x)]
|
[(a (expression (== ite) (expression (== @!) a) _ x)) (cons a x)]
|
||||||
[((and (expression (== @!) a) !a) (expression (== ite) a _ x)) (cons !a x)]
|
[((expression (== @!) a) (expression (== ite) a _ x)) (cons a x)]
|
||||||
[(_ _) p]))
|
[(_ _) p]))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,7 @@
|
||||||
; These IDs are never reused, and they are used to impose an ordering on the children
|
; These IDs are never reused, and they are used to impose an ordering on the children
|
||||||
; of expressions with commutative operators.
|
; 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))
|
(define current-index (make-parameter 0))
|
||||||
|
|
||||||
; Clears the entire term cache if invoked with #f (default), or
|
; Clears the entire term cache if invoked with #f (default), or
|
||||||
|
|
@ -82,23 +77,17 @@
|
||||||
; restores (terms) to its old value. If terms-expr is not given, it defaults to
|
; 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).
|
; (terms), so (with-terms expr) is equivalent to (with-terms (terms) expr).
|
||||||
(define-syntax (with-terms stx)
|
(define-syntax (with-terms stx)
|
||||||
;; Parameterize with #f so that the hash table cooperates with garbage collector.
|
|
||||||
;; See #247
|
|
||||||
(syntax-parse stx
|
(syntax-parse stx
|
||||||
[(_ expr)
|
[(_ expr)
|
||||||
#'(let ([orig-terms (current-terms)])
|
#'(parameterize ([current-terms (hash-copy (current-terms))])
|
||||||
(parameterize ([current-terms #f])
|
expr)]
|
||||||
(current-terms (hash-copy orig-terms))
|
|
||||||
expr))]
|
|
||||||
[(_ terms-expr expr)
|
[(_ terms-expr expr)
|
||||||
#'(let ([orig-terms (current-terms)])
|
#'(parameterize ([current-terms (hash-copy-clear (current-terms))])
|
||||||
(parameterize ([current-terms #f])
|
|
||||||
(current-terms (hash-copy-clear orig-terms))
|
|
||||||
(let ([ts terms-expr]
|
(let ([ts terms-expr]
|
||||||
[cache (current-terms)])
|
[cache (current-terms)])
|
||||||
(for ([t ts])
|
(for ([t ts])
|
||||||
(hash-set! cache (term-val t) t))
|
(hash-set! cache (term-val t) t))
|
||||||
expr)))]))
|
expr))]))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -132,21 +121,14 @@
|
||||||
(define (term<? s1 s2) (< (term-ord s1) (term-ord s2)))
|
(define (term<? s1 s2) (< (term-ord s1) (term-ord s2)))
|
||||||
|
|
||||||
(define-syntax-rule (make-term term-constructor args type rest ...)
|
(define-syntax-rule (make-term term-constructor args type rest ...)
|
||||||
(let ([val args]
|
(let ([val args])
|
||||||
[ty type])
|
(or (hash-ref (current-terms) val #f)
|
||||||
(define cached (hash-ref (current-terms) val #f))
|
(let* ([ord (current-index)]
|
||||||
(cond
|
[out (term-constructor val type ord rest ...)])
|
||||||
[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-index (add1 ord))
|
||||||
((current-reporter) 'new-term out)
|
((current-reporter) 'new-term out)
|
||||||
(hash-set! (current-terms) val out)
|
(hash-set! (current-terms) val out)
|
||||||
out])))
|
out))))
|
||||||
|
|
||||||
(define (make-const id t)
|
(define (make-const id t)
|
||||||
(unless (and (type? t) (solvable? t))
|
(unless (and (type? t) (solvable? t))
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@
|
||||||
[type-cast type val [caller]] ; (-> type? any/c symbol? any/c)
|
[type-cast type val [caller]] ; (-> type? any/c symbol? any/c)
|
||||||
[type-name type] ; (-> type? symbol?)
|
[type-name type] ; (-> type? symbol?)
|
||||||
[type-applicable? type] ; (-> type? boolean?)
|
[type-applicable? type] ; (-> type? boolean?)
|
||||||
[type-eq? 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-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-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-construct type vals] ; (-> type? (listof any/c) any/c)
|
||||||
[type-deconstruct type val]) ; (-> type? any/c (listof any/c))
|
[type-deconstruct type val]) ; (-> type? any/c (listof any/c))
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ equality (@racket[bveq]) and signed / unsigned versions of
|
||||||
[(bvor [x (bitvector n)] ...+) (bitvector n)]
|
[(bvor [x (bitvector n)] ...+) (bitvector n)]
|
||||||
[(bvxor [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
|
@examples[#:eval rosette-eval
|
||||||
(bvand (bv -1 4) (bv 2 4))
|
(bvand (bv -1 4) (bv 2 4))
|
||||||
|
|
@ -434,7 +434,7 @@ leads to faster solving times.
|
||||||
|
|
||||||
@(rosette-eval '(clear-vc!))
|
@(rosette-eval '(clear-vc!))
|
||||||
|
|
||||||
@defproc[(bitvector->bits [x (bitvector n)]) (listof (bitvector 1))]{
|
@defproc[(bitvector->bits [x (bitvector n)]) (listof (bitvector n))]{
|
||||||
|
|
||||||
Returns the bits of @racket[x] as a list, i.e., @racket[(list (bit 0 x) ... (bit (- n 1) x))].
|
Returns the bits of @racket[x] as a list, i.e., @racket[(list (bit 0 x) ... (bit (- n 1) x))].
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,7 @@
|
||||||
@(require (for-label
|
@(require (for-label
|
||||||
rosette/solver/solver rosette/solver/solution
|
rosette/solver/solver rosette/solver/solution
|
||||||
rosette/solver/smt/z3 rosette/solver/smt/cvc4
|
rosette/solver/smt/z3 rosette/solver/smt/cvc4
|
||||||
rosette/solver/smt/boolector
|
rosette/solver/smt/boolector rosette/solver/smt/yices
|
||||||
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/form/define rosette/query/query
|
||||||
rosette/base/core/term (only-in rosette/base/base bv?)
|
rosette/base/core/term (only-in rosette/base/base bv?)
|
||||||
(only-in rosette/base/base assert)
|
(only-in rosette/base/base assert)
|
||||||
|
|
@ -25,11 +21,8 @@
|
||||||
rosette/solver/solution
|
rosette/solver/solution
|
||||||
rosette/solver/smt/z3
|
rosette/solver/smt/z3
|
||||||
rosette/solver/smt/cvc4
|
rosette/solver/smt/cvc4
|
||||||
rosette/solver/smt/boolector
|
|
||||||
rosette/solver/smt/bitwuzla
|
|
||||||
rosette/solver/smt/cvc5
|
|
||||||
rosette/solver/smt/stp
|
|
||||||
rosette/solver/smt/yices
|
rosette/solver/smt/yices
|
||||||
|
rosette/solver/smt/boolector
|
||||||
#:use-sources
|
#:use-sources
|
||||||
(rosette/query/finitize
|
(rosette/query/finitize
|
||||||
rosette/query/query
|
rosette/query/query
|
||||||
|
|
@ -37,11 +30,8 @@
|
||||||
rosette/solver/solution
|
rosette/solver/solution
|
||||||
rosette/solver/smt/z3
|
rosette/solver/smt/z3
|
||||||
rosette/solver/smt/cvc4
|
rosette/solver/smt/cvc4
|
||||||
rosette/solver/smt/boolector
|
rosette/solver/smt/yices
|
||||||
rosette/solver/smt/bitwuzla
|
rosette/solver/smt/boolector)]
|
||||||
rosette/solver/smt/cvc5
|
|
||||||
rosette/solver/smt/stp
|
|
||||||
rosette/solver/smt/yices)]
|
|
||||||
|
|
||||||
A @deftech{solver} is an automatic reasoning engine, used to answer
|
A @deftech{solver} is an automatic reasoning engine, used to answer
|
||||||
@seclink["sec:queries"]{queries} about Rosette programs. The result of
|
@seclink["sec:queries"]{queries} about Rosette programs. The result of
|
||||||
|
|
@ -291,146 +281,37 @@ 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
|
If this returns @racket[#f], @racket[(boolector)] will not succeed
|
||||||
without its optional @racket[path] argument.}
|
without its optional @racket[path] argument.}
|
||||||
|
|
||||||
@subsection{Bitwuzla}
|
|
||||||
|
|
||||||
@defmodule[rosette/solver/smt/bitwuzla #:no-declare]
|
@subsection{Yices}
|
||||||
|
|
||||||
@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]
|
@defmodule[rosette/solver/smt/yices #:no-declare]
|
||||||
|
|
||||||
@defproc*[([(yices [#:path path (or/c path-string? #f) #f]
|
@defproc*[([(yices [#:path path (or/c path-string? #f) #f]
|
||||||
[#:logic logic (or/c symbol? #f) 'QF_BV]
|
[#:logic logic symbol? 'ALL]
|
||||||
[#:options options (hash/c symbol? any/c) (hash)]) solver?]
|
[#:options options (hash/c symbol? any/c) (hash)]) solver?]
|
||||||
[(yices? [v any/c]) boolean?])]{
|
[(yices? [v any/c]) boolean?])]{
|
||||||
|
|
||||||
Returns a @racket[solver?] wrapper for the @hyperlink["https://yices.csl.sri.com/"]{Yices2} solver.
|
Returns a @racket[solver?] wrapper for the @hyperlink["http://yices.csl.sri.com/"]{Yices} solver from SRI.
|
||||||
|
|
||||||
To use this solver, download prebuilt Yices2 or build it yourself,
|
To use this solver, download and install Yices (version 2.6.0 or later),
|
||||||
and ensure the executable is on your @tt{PATH} or pass the path to the
|
and either add the @tt{yices-smt2} executable to your @tt{PATH}
|
||||||
executable as the optional @racket[path] argument.
|
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]).
|
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
|
Specifying a logic can improve solving performance, but Rosette makes no effort to check that
|
||||||
emitted constraints fall within the chosen logic. Yices2 expects a logic to be
|
emitted constraints fall within the chosen logic. The default is @racket['ALL].
|
||||||
set; Rosette defaults to @racket['QF_BV].
|
|
||||||
|
|
||||||
The @racket[options] argument provides additional options that are sent to Yices2
|
The @racket[options] argument provides additional options that are sent to Yices
|
||||||
via the @tt{set-option} SMT command.
|
via the @tt{set-option} SMT command.
|
||||||
For example, setting @racket[options] to @racket[(hash ':seed 5)]
|
For example, setting @racket[options] to @racket[(hash ':random-seed 5)]
|
||||||
will send the command @tt{(set-option :seed 5)} to Yices2 prior to solving.
|
will send the command @tt{(set-option :random-seed 5)} to Yices prior to solving.
|
||||||
}
|
}
|
||||||
|
|
||||||
@defproc[(yices-available?) boolean?]{
|
@defproc[(yices-available?) boolean?]{
|
||||||
Returns true if the Yices2 solver is available for use (i.e., Rosette can locate a @tt{yices-smt2} binary).
|
Returns true if the Yices 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
|
If this returns @racket[#f], @racket[(yices)] will not succeed
|
||||||
without its optional @racket[path] argument.}
|
without its optional @racket[path] argument.}
|
||||||
|
|
||||||
|
|
||||||
@section{Solutions}
|
@section{Solutions}
|
||||||
|
|
||||||
A solution to a set of formulas may be satisfiable (@racket[sat?]), unsatisfiable (@racket[unsat?]),
|
A solution to a set of formulas may be satisfiable (@racket[sat?]), unsatisfiable (@racket[unsat?]),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
@(require (for-label
|
@(require (for-label
|
||||||
rosette/base/form/define rosette/query/query
|
rosette/base/form/define rosette/query/query
|
||||||
rosette/base/core/term
|
rosette/base/core/term
|
||||||
rosette/solver/solution
|
|
||||||
(only-in rosette/base/base assert define-symbolic union?
|
(only-in rosette/base/base assert define-symbolic union?
|
||||||
vc clear-vc! bitvector bitvector? bv?
|
vc clear-vc! bitvector bitvector? bv?
|
||||||
bitvector->natural integer->bitvector
|
bitvector->natural integer->bitvector
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,19 @@
|
||||||
#lang scribble/manual
|
#lang scribble/manual
|
||||||
|
|
||||||
@(require (for-label
|
@(require (for-label racket (only-in racket/sandbox with-deep-time-limit))
|
||||||
racket
|
(for-label
|
||||||
(only-in racket/sandbox with-deep-time-limit)
|
|
||||||
rosette/base/form/define
|
rosette/base/form/define
|
||||||
|
(only-in rosette/base/base assert assume vc vc-asserts vc-assumes clear-vc!)
|
||||||
rosette/query/query
|
rosette/query/query
|
||||||
rosette/solver/solution
|
(only-in rosette/base/base bv? bitvector
|
||||||
(only-in rosette/base/base
|
|
||||||
assert assume vc vc-asserts vc-assumes clear-vc!
|
|
||||||
bv? bitvector
|
|
||||||
bvsdiv bvadd bvsle bvsub bvand
|
bvsdiv bvadd bvsle bvsub bvand
|
||||||
bvor bvxor bvshl bvlshr bvashr
|
bvor bvxor bvshl bvlshr bvashr
|
||||||
bvnot bvneg)
|
bvnot bvneg)
|
||||||
rosette/lib/synthax))
|
rosette/lib/synthax))
|
||||||
|
|
||||||
@(require racket/sandbox racket/runtime-path scribble/core scribble/racket
|
@(require racket/sandbox racket/runtime-path scribble/core scribble/racket
|
||||||
scribble/example scribble/html-properties scriblib/footnote)
|
scribble/example scribble/html-properties scriblib/footnote
|
||||||
|
(only-in racket [unsyntax racket/unsyntax]))
|
||||||
|
|
||||||
@(require (only-in "../refs.scrbl" ~cite rosette:onward13 rosette:pldi14)
|
@(require (only-in "../refs.scrbl" ~cite rosette:onward13 rosette:pldi14)
|
||||||
"../util/lifted.rkt")
|
"../util/lifted.rkt")
|
||||||
|
|
@ -142,7 +140,7 @@ Assumptions behave analogously to assertions on both concrete and symbolic value
|
||||||
|
|
||||||
@section[#:tag "sec:queries"]{Solver-Aided Queries}
|
@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
|
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],
|
procedure @racket[bvmid] that takes as input two non-negative 32-bit integers, @racket[lo] ≤ @racket[hi],
|
||||||
|
|
@ -323,7 +321,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.
|
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
|
@examples[#:eval rosette-eval #:label #f
|
||||||
(define (bvmid-fast lo hi)
|
(define (bvmid-fast lo hi)
|
||||||
(bvlshr (bvadd hi lo) (bv #x00000001 32)))
|
(bvlshr (bvadd hi lo) (bv #x00000001 32)))
|
||||||
|
|
@ -482,7 +480,7 @@ n2
|
||||||
n3]
|
n3]
|
||||||
In general, recursion terminates under symbolic evaluation only when the stopping condition is reached with concrete values.
|
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[bvsqrt] 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[sqrt] on all inputs:
|
||||||
@(rosette-eval '(clear-vc!))
|
@(rosette-eval '(clear-vc!))
|
||||||
@(rosette-eval '(require (only-in racket make-parameter parameterize)))
|
@(rosette-eval '(require (only-in racket make-parameter parameterize)))
|
||||||
@examples[#:eval rosette-eval #:label #f #:no-prompt
|
@examples[#:eval rosette-eval #:label #f #:no-prompt
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
@title[#:tag "ch:syntactic-forms" #:style 'toc]{Syntactic Forms}
|
@title[#:tag "ch:syntactic-forms" #:style 'toc]{Syntactic Forms}
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
@[table-of-contents]
|
@[table-of-contents]
|
||||||
@include-section["racket-forms.scrbl"]
|
@include-section["racket-forms.scrbl"]
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
@title[#:tag "ch:libraries" #:style 'toc]{Libraries}
|
@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 @racketmodname[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 @racket[rosette/safe], as well as Rosette libraries that provide additional facilities for solver-aided development.
|
||||||
|
|
||||||
@[table-of-contents]
|
@[table-of-contents]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,4 +17,5 @@ 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.
|
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 @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.
|
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.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -367,7 +367,7 @@ sol
|
||||||
generated for programs that have been saved to disk.
|
generated for programs that have been saved to disk.
|
||||||
|
|
||||||
This procedure cooperates with the constructs in the
|
This procedure cooperates with the constructs in the
|
||||||
@racketmodname[rosette/lib/synthax] library to turn solutions into
|
@racket[rosette/lib/synthax] library to turn solutions into
|
||||||
code. It works by scanning program files for
|
code. It works by scanning program files for
|
||||||
@racketlink[??]{constant}, @racketlink[choose]{choice}, and
|
@racketlink[??]{constant}, @racketlink[choose]{choice}, and
|
||||||
@racketlink[define-grammar]{grammar} holes, and replacing
|
@racketlink[define-grammar]{grammar} holes, and replacing
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ integers and reals (while being correct under the
|
||||||
finite-precision semantics). For example, this program
|
finite-precision semantics). For example, this program
|
||||||
incorrectly says that no integer greater than 15 exists,
|
incorrectly says that no integer greater than 15 exists,
|
||||||
because the setting of @racket[current-bitwidth] causes it
|
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.
|
represented as a 5-bit bitvector.
|
||||||
|
|
||||||
@examples[#:eval rosette-eval #:label #f
|
@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}
|
couple of seconds when @tt{N} = 5 to over a minute when @tt{N}
|
||||||
= 20. To identify the source of this performance issue, we
|
= 20. To identify the source of this performance issue, we
|
||||||
can invoke the @tech{symbolic profiler} on the verifier,
|
can invoke the @tech{symbolic profiler} on the verifier,
|
||||||
producing the output below (after selecting the ``Collapse
|
producing the output below (after selecting the "Collapse
|
||||||
solver time'' checkbox):
|
solver time" checkbox):
|
||||||
|
|
||||||
@(image profile-xform.png #:scale 0.425)
|
@(image profile-xform.png #:scale 0.425)
|
||||||
|
|
||||||
The symbolic profiler identifies @tt{list-set} as the
|
The symbolic profiler identifies @tt{list-set} as the
|
||||||
bottleneck in this program. The output shows that @tt{list-set}
|
bottleneck in this program. The output shows that @tt{list-set}
|
||||||
creates many symbolic terms, and performs many symbolic
|
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}
|
The core issue here is an @tech{algorithmic mismatch}: @tt{list-set}
|
||||||
makes a recursive call guarded by a short-circuiting
|
makes a recursive call guarded by a short-circuiting
|
||||||
|
|
|
||||||
|
|
@ -241,8 +241,8 @@ as well as for tuning the performance of symbolic
|
||||||
evaluation.
|
evaluation.
|
||||||
|
|
||||||
|
|
||||||
@declare-exporting[rosette/base/core/forall
|
@declare-exporting[rosette/base/core/forall rosette/lib/lift
|
||||||
#:use-sources (rosette/base/core/forall)]
|
#:use-sources (rosette/base/core/forall rosette/lib/lift)]
|
||||||
|
|
||||||
@defform[(for/all ([id val-expr maybe-exhaustive]) body ...+)
|
@defform[(for/all ([id val-expr maybe-exhaustive]) body ...+)
|
||||||
#:grammar [(maybe-exhaustive (code:line) #:exhaustive)]]{
|
#:grammar [(maybe-exhaustive (code:line) #:exhaustive)]]{
|
||||||
|
|
|
||||||
|
|
@ -9,28 +9,21 @@
|
||||||
|
|
||||||
@(define rosette:onward13
|
@(define rosette:onward13
|
||||||
(make-bib
|
(make-bib
|
||||||
#:title @hyperlink["http://dl.acm.org/citation.cfm?id=2509586"]{Growing Solver-Aided Languages with Rosette}
|
#:title @hyperlink["http://homes.cs.washington.edu/~emina/pubs/rosette.onward13.pdf"]{Growing Solver-Aided Languages with Rosette}
|
||||||
#:author (authors "Emina Torlak" "Rastislav Bodik")
|
#:author (authors "Emina Torlak" "Rastislav Bodik")
|
||||||
#:date 2013
|
#:date 2013
|
||||||
#:location "New Ideas, New Paradigms, and Reflections on Programming and Software (Onward!)"))
|
#:location "New Ideas, New Paradigms, and Reflections on Programming and Software (Onward!)"))
|
||||||
|
|
||||||
@(define rosette:pldi14
|
@(define rosette:pldi14
|
||||||
(make-bib
|
(make-bib
|
||||||
#:title @hyperlink["http://dl.acm.org/citation.cfm?id=2594340"]{A Lightweight Symbolic Virtual Machine for Solver-Aided Host Languages}
|
#:title @hyperlink["http://homes.cs.washington.edu/~emina/pubs/rosette.pldi14.pdf"]{A Lightweight Symbolic Virtual Machine for Solver-Aided Host Languages}
|
||||||
#:author (authors "Emina Torlak" "Rastislav Bodik")
|
#:author (authors "Emina Torlak" "Rastislav Bodik")
|
||||||
#:date 2014
|
#:date 2014
|
||||||
#:location "Programming Language Design and Implementation (PLDI)"))
|
#:location "Programming Language Design and Implementation (PLDI)"))
|
||||||
|
|
||||||
@(define sympro:oopsla18
|
@(define sympro:oopsla18
|
||||||
(make-bib
|
(make-bib
|
||||||
#:title @hyperlink["https://dl.acm.org/citation.cfm?id=3276519"]{Finding Code That Explodes Under Symbolic Evaluation}
|
#:title @hyperlink["https://unsat.cs.washington.edu/papers/bornholt-sympro.pdf"]{Finding Code That Explodes Under Symbolic Evaluation}
|
||||||
#:author (authors "James Bornholt" "Emina Torlak")
|
#:author (authors "James Bornholt" "Emina Torlak")
|
||||||
#:date 2018
|
#:date 2018
|
||||||
#:location "Object Oriented Programming, Systems, Languages, and Applications (OOPSLA)"))
|
#:location "Object Oriented Programming, Systems, Languages, and Applications (OOPSLA)"))
|
||||||
|
|
||||||
@(define rosette:popl22
|
|
||||||
(make-bib
|
|
||||||
#:title @hyperlink["https://doi.org/10.1145/3498709"]{A Formal Foundation for Symbolic Evaluation with Merging}
|
|
||||||
#:author (authors "Sorawee Porncharoenwase" "Luke Nelson" "Xi Wang" "Emina Torlak")
|
|
||||||
#:date 2022
|
|
||||||
#:location "Principles of Programming Languages (POPL)"))
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
@(require (for-label rosette/base/form/define rosette/query/query rosette/solver/solution
|
@(require (for-label rosette/base/form/define rosette/query/query rosette/solver/solution
|
||||||
(only-in rosette/base/base assert vc-true? vc) )
|
(only-in rosette/base/base assert vc-true? vc) )
|
||||||
racket/runtime-path racket/sandbox)
|
racket/runtime-path racket/sandbox)
|
||||||
@(require (only-in "../refs.scrbl" ~cite rosette:pldi14 rosette:popl22))
|
@(require (only-in "../refs.scrbl" ~cite rosette:pldi14))
|
||||||
@(require "../util/lifted.rkt")
|
@(require "../util/lifted.rkt")
|
||||||
|
|
||||||
@(define-runtime-path root ".")
|
@(define-runtime-path root ".")
|
||||||
|
|
@ -13,20 +13,20 @@
|
||||||
@title[#:tag "ch:unsafe"]{Unsafe Operations}
|
@title[#:tag "ch:unsafe"]{Unsafe Operations}
|
||||||
|
|
||||||
Throughout this guide, we have assumed that Rosette programs are
|
Throughout this guide, we have assumed that Rosette programs are
|
||||||
written in the @racketmodname[rosette/safe] dialect of the full language.
|
written in the @racket[rosette/safe] dialect of the full language.
|
||||||
This dialect extends a core subset of Racket with @seclink["ch:essentials"]{solver-aided
|
This dialect extends a core subset of Racket with @seclink["ch:essentials"]{solver-aided
|
||||||
functionality}. In this chapter, we briefly discuss the @racketmodname[rosette]
|
functionality}. In this chapter, we briefly discuss the @racket[rosette]
|
||||||
dialect of the language, which exports all of Racket.
|
dialect of the language, which exports all of Racket.
|
||||||
|
|
||||||
Safe use of the full @racketmodname[rosette] language requires a basic understanding
|
Safe use of the full @racket[rosette] language requires a basic understanding
|
||||||
of how Rosette's Symbolic Virtual Machine (SVM) works @~cite[rosette:pldi14 rosette:popl22].
|
of how Rosette's Symbolic Virtual Machine (SVM) works @~cite[rosette:pldi14].
|
||||||
Briefly, the SVM hijacks the normal Racket execution for all procedures and
|
Briefly, the SVM hijacks the normal Racket execution for all procedures and
|
||||||
constructs that are exported by @racketmodname[rosette/safe]. Any programs that are
|
constructs that are exported by @racket[rosette/safe]. Any programs that are
|
||||||
implemented exclusively in the @racketmodname[rosette/safe] language are therefore
|
implemented exclusively in the @racket[rosette/safe] language are therefore
|
||||||
fully under the SVM's control. This means that the SVM can correctly interpret
|
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
|
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
|
can correctly handle any side-effects (in particular, writes to memory) performed
|
||||||
by @racketmodname[rosette/safe] code.
|
by @racket[rosette/safe] code.
|
||||||
|
|
||||||
The following snippet demonstrates the non-standard execution that the SVM needs to
|
The following snippet demonstrates the non-standard execution that the SVM needs to
|
||||||
perform in order to assign the expected meaning to Rosette code:
|
perform in order to assign the expected meaning to Rosette code:
|
||||||
|
|
@ -53,17 +53,17 @@ y
|
||||||
(define sol2 (solve (assert (not b))))
|
(define sol2 (solve (assert (not b))))
|
||||||
(evaluate y sol2)]
|
(evaluate y sol2)]
|
||||||
|
|
||||||
Because the SVM controls only the execution of @racketmodname[rosette/safe] code,
|
Because the SVM controls only the execution of @racket[rosette/safe] code,
|
||||||
it cannot, in general, guarantee the safety or correctness of arbitrary @racketmodname[rosette] programs.
|
it cannot, in general, guarantee the safety or correctness of arbitrary @racket[rosette] programs.
|
||||||
As soon as a @racketmodname[rosette] program calls an @tech[#:key "lifted construct"]{unlifted} Racket construct
|
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 @racketmodname[rosette/safe] language),
|
(that is, a procedure or a macro not implemented in or provided by the @racket[rosette/safe] language),
|
||||||
the execution escapes back to the Racket interpreter. The SVM has no control over the side-effects
|
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
|
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
|
in the presence of symbolic values. As a result, the programmer is responsible for ensuring that
|
||||||
a @racketmodname[rosette] program continues to behave correctly after the execution returns from the Racket interpreter.
|
a @racket[rosette] program continues to behave correctly after the execution returns from the Racket interpreter.
|
||||||
|
|
||||||
As an example of incorrect behavior, consider the following @racketmodname[rosette] snippet.
|
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 @racketmodname[rosette/safe].
|
The procedures @racket[make-hash], @racket[hash-ref], and @racket[hash-clear!] are not in @racket[rosette/safe].
|
||||||
Whenever they are invoked, the execution escapes to the Racket interpreter.
|
Whenever they are invoked, the execution escapes to the Racket interpreter.
|
||||||
|
|
||||||
@(rosette-eval '(require (only-in racket make-hash hash-clear! hash-ref)))
|
@(rosette-eval '(require (only-in racket make-hash hash-clear! hash-ref)))
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ Rosette is a @emph{solver-aided} programming system with two components:
|
||||||
compiles them to logical constraints. The SVM enables Rosette
|
compiles them to logical constraints. The SVM enables Rosette
|
||||||
to use the solver to automatically reason about program behaviors.}]
|
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}
|
@section[#:tag "sec:get"]{Installing Rosette}
|
||||||
|
|
||||||
To install Rosette, you will need to
|
To install Rosette, you will need to
|
||||||
|
|
||||||
@itemlist[@item{Download and install @hyperlink["http://racket-lang.org"]{Racket} (version 8.1 or later).}
|
@itemlist[@item{Download and install @hyperlink["http://racket-lang.org"]{Racket} (version 8.0 or later).}
|
||||||
@item{Use Racket's @tt{raco} tool to install Rosette:
|
@item{Use Racket's @tt{raco} tool to install Rosette:
|
||||||
@nested{
|
@nested{
|
||||||
@verbatim|{> raco pkg install rosette}|}}]
|
@verbatim|{> raco pkg install rosette}|}}]
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,10 @@
|
||||||
(experimental))))
|
(experimental))))
|
||||||
;; Documentation category. On Racket 6.3+ this can be any string.
|
;; Documentation category. On Racket 6.3+ this can be any string.
|
||||||
|
|
||||||
(define compile-omit-files '("lib/trace/report/node_modules"))
|
;; 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 raco-commands
|
(define raco-commands
|
||||||
'(("symprofile"
|
'(("symprofile"
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,10 @@
|
||||||
|
|
||||||
(define-simple-macro (destruct val [pat:clause-pattern e:expr ...+] ...)
|
(define-simple-macro (destruct val [pat:clause-pattern e:expr ...+] ...)
|
||||||
#:do [(for-each check-duplicate-identifier! (attribute pat.id-set))]
|
#:do [(for-each check-duplicate-identifier! (attribute pat.id-set))]
|
||||||
#:with match-expr (syntax/loc this-syntax (match var [pat (begin e ...)] ...))
|
|
||||||
#:with result
|
#:with result
|
||||||
(syntax/loc this-syntax
|
(syntax/loc this-syntax
|
||||||
(for/all ([var val]);(guarded-values val)])
|
(for/all ([var val]);(guarded-values val)])
|
||||||
match-expr))
|
(match var [pat (begin e ...)] ...)))
|
||||||
result)
|
result)
|
||||||
|
|
||||||
(define-simple-macro (destruct* (val ...) [(pat:clause-pattern ...) e:expr ...+] ...)
|
(define-simple-macro (destruct* (val ...) [(pat:clause-pattern ...) e:expr ...+] ...)
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
"Only install the compile handler; do not run the profiler"
|
"Only install the compile handler; do not run the profiler"
|
||||||
(run-profiler? #f)]
|
(run-profiler? #f)]
|
||||||
[("-m" "--module") name
|
[("-m" "--module") name
|
||||||
"Run submodule <name> (defaults to 'main')"
|
"Run submodule <name> (defaults to 'main)"
|
||||||
(module-name (string->symbol name))]
|
(module-name (string->symbol name))]
|
||||||
[("-r" "--racket")
|
[("-r" "--racket")
|
||||||
"Instrument code in any language, not just `#lang rosette`"
|
"Instrument code in any language, not just `#lang rosette`"
|
||||||
|
|
|
||||||
|
|
@ -78,13 +78,8 @@
|
||||||
; all events from the box. if that happened then the ENTER we're trying
|
; 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
|
; to delete has already been published, and so we need to retain the
|
||||||
; corresponding EXIT.
|
; corresponding EXIT.
|
||||||
(let loop ()
|
|
||||||
(unless (box-cas! the-box evts (cdr evts))
|
(unless (box-cas! the-box evts (cdr evts))
|
||||||
(if (eq? evts (unbox the-box))
|
(do-record-exit! out))]))))))
|
||||||
; 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
|
; Default version just uses the current-profile/current-reporter params
|
||||||
(define default-record-exit
|
(define default-record-exit
|
||||||
|
|
|
||||||
|
|
@ -296,4 +296,4 @@
|
||||||
(define (print-forms sol)
|
(define (print-forms sol)
|
||||||
(for ([f (generate-forms sol)])
|
(for ([f (generate-forms sol)])
|
||||||
(printf "~a:~a:~a\n" (syntax-source f) (syntax-line f) (syntax-column f))
|
(printf "~a:~a:~a\n" (syntax-source f) (syntax-line f) (syntax-column f))
|
||||||
(pretty-write (syntax->datum f))))
|
(pretty-print (syntax->datum f))))
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
;; SymPro options
|
;; SymPro options
|
||||||
[("-m" "--module") name
|
[("-m" "--module") name
|
||||||
"Run submodule <name> (defaults to 'main')"
|
"Run submodule <name> (defaults to 'main)"
|
||||||
(module-name (string->symbol name))]
|
(module-name (string->symbol name))]
|
||||||
[("-r" "--racket")
|
[("-r" "--racket")
|
||||||
"Instrument code in any language, not just `#lang rosette`"
|
"Instrument code in any language, not just `#lang rosette`"
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,6 @@
|
||||||
(string-prefix? (path->string (resolve-path a))
|
(string-prefix? (path->string (resolve-path a))
|
||||||
(path->string (resolve-path b))))
|
(path->string (resolve-path b))))
|
||||||
|
|
||||||
(define pkg-cache (make-hash))
|
|
||||||
|
|
||||||
(define (make-rosette-load/use-compiled pkgs-to-instrument)
|
(define (make-rosette-load/use-compiled pkgs-to-instrument)
|
||||||
(make-custom-load/use-compiled
|
(make-custom-load/use-compiled
|
||||||
#:blacklist
|
#:blacklist
|
||||||
|
|
@ -30,6 +28,6 @@
|
||||||
(cond
|
(cond
|
||||||
[(path-prefix? path (find-collects-dir)) #f]
|
[(path-prefix? path (find-collects-dir)) #f]
|
||||||
[else
|
[else
|
||||||
(match (path->pkg path #:cache pkg-cache)
|
(match (path->pkg path)
|
||||||
[#f #t]
|
[#f #t]
|
||||||
[pkg-name (member pkg-name pkgs-to-instrument)])]))))
|
[pkg-name (member pkg-name pkgs-to-instrument)])]))))
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@
|
||||||
; the procedure for handling connections
|
; the procedure for handling connections
|
||||||
(define (ws-connection conn _state)
|
(define (ws-connection conn _state)
|
||||||
; only one client may connect
|
; only one client may connect
|
||||||
(let loop ()
|
|
||||||
(cond
|
(cond
|
||||||
[(box-cas! connected? #f #t) ; we won the race to connect
|
[(box-cas! connected? #f #t) ; we won the race to connect
|
||||||
; tell the main thread we're connected
|
; tell the main thread we're connected
|
||||||
|
|
@ -43,11 +42,9 @@
|
||||||
(unless (eq? sync-result 'finish)
|
(unless (eq? sync-result 'finish)
|
||||||
(channel-get channel))
|
(channel-get channel))
|
||||||
(channel-put channel 'finish)]))))]
|
(channel-put channel 'finish)]))))]
|
||||||
[(unbox connected?)
|
[else
|
||||||
;; it's already connected
|
|
||||||
(channel-put channel "another client is already connected")
|
(channel-put channel "another client is already connected")
|
||||||
(ws-close! conn)]
|
(ws-close! conn)]))
|
||||||
[else (loop)])))
|
|
||||||
|
|
||||||
; start the server
|
; start the server
|
||||||
(define conf-channel (make-async-channel))
|
(define conf-channel (make-async-channel))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
#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])))
|
||||||
|
|
@ -150,12 +150,12 @@
|
||||||
; ∃H. (∀I. assumes => asserts) ∧ (∃I. assumes).
|
; ∃H. (∀I. assumes => asserts) ∧ (∃I. assumes).
|
||||||
(define (cegis inputs assumes asserts guesser checker)
|
(define (cegis inputs assumes asserts guesser checker)
|
||||||
|
|
||||||
(define φ `(,(=> (apply && assumes) (apply && asserts))))
|
(define φ (append assumes asserts))
|
||||||
|
|
||||||
(define ¬φ `(,@assumes ,(apply || (map ! asserts))))
|
(define ¬φ `(,@assumes ,(apply || (map ! asserts))))
|
||||||
|
|
||||||
(define (guess ψ)
|
(define (guess sol)
|
||||||
(solver-assert guesser ψ)
|
(solver-assert guesser (evaluate φ sol))
|
||||||
(match (solver-check guesser)
|
(match (solver-check guesser)
|
||||||
[(model m) (sat (for/hash ([(c v) m] #:unless (member c inputs)) (values c v)))]
|
[(model m) (sat (for/hash ([(c v) m] #:unless (member c inputs)) (values c v)))]
|
||||||
[other other]))
|
[other other]))
|
||||||
|
|
@ -171,14 +171,14 @@
|
||||||
v)))))]
|
v)))))]
|
||||||
[other other]))
|
[other other]))
|
||||||
|
|
||||||
(let loop ([candidate (guess (append assumes asserts))])
|
(let loop ([candidate (begin0 (guess (sat)) (solver-clear guesser))])
|
||||||
(cond
|
(cond
|
||||||
[(unsat? candidate) candidate]
|
[(unsat? candidate) candidate]
|
||||||
[else
|
[else
|
||||||
(let ([cex (check candidate)])
|
(let ([cex (check candidate)])
|
||||||
(cond
|
(cond
|
||||||
[(unsat? cex) candidate]
|
[(unsat? cex) candidate]
|
||||||
[else (loop (guess (evaluate φ cex)))]))])))
|
[else (loop (guess cex))]))])))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,7 @@
|
||||||
[(cons x y)
|
[(cons x y)
|
||||||
(cons (eval-rec x sol cache) (eval-rec y sol cache))]
|
(cons (eval-rec x sol cache) (eval-rec y sol cache))]
|
||||||
[(? vector?)
|
[(? vector?)
|
||||||
(let ([v (for/vector #:length (vector-length expr) ([e expr]) (eval-rec e sol cache))])
|
(for/vector #:length (vector-length expr) ([e expr]) (eval-rec e sol cache))]
|
||||||
(if (immutable? expr)
|
|
||||||
(vector->immutable-vector v)
|
|
||||||
v))]
|
|
||||||
[(? box?)
|
[(? box?)
|
||||||
((if (immutable? expr) box-immutable box) (eval-rec (unbox expr) sol cache))]
|
((if (immutable? expr) box-immutable box) (eval-rec (unbox expr) sol cache))]
|
||||||
[(? typed?)
|
[(? typed?)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
#lang racket
|
#lang racket
|
||||||
|
|
||||||
(require syntax/parse/define
|
(require "core.rkt"
|
||||||
"core.rkt"
|
|
||||||
(only-in "../base/core/reflect.rkt" symbolics)
|
(only-in "../base/core/reflect.rkt" symbolics)
|
||||||
(only-in "../base/core/result.rkt" result-state)
|
(only-in "../base/core/result.rkt" result-state)
|
||||||
(only-in "../base/core/bool.rkt" ! vc with-vc vc-assumes vc-asserts vc-true))
|
(only-in "../base/core/bool.rkt" ! vc with-vc vc-assumes vc-asserts vc-true))
|
||||||
|
|
@ -71,15 +70,14 @@
|
||||||
; generate any assumptions or assertions, these are reflected in the (vc) after
|
; generate any assumptions or assertions, these are reflected in the (vc) after
|
||||||
; the optimize query returns. The assumptions and assertions generated by expr
|
; the optimize query returns. The assumptions and assertions generated by expr
|
||||||
; are not added to (vc) after optimize returns.
|
; are not added to (vc) after optimize returns.
|
||||||
(define-syntax-parser optimize
|
(define-syntax optimize
|
||||||
[(_ {~and kw {~or* #:minimize #:maximize}} opt #:guarantee expr)
|
(syntax-rules ()
|
||||||
#'(let ([obj opt] ; evaluate objective first to add its spec to (vc)
|
[(_ kw opt #:guarantee expr)
|
||||||
|
(let ([obj opt] ; evaluate objective first to add its spec to (vc)
|
||||||
[post (query-vc expr)])
|
[post (query-vc expr)])
|
||||||
(∃-solve `(,@(pre) ,(vc-assumes post) ,(vc-asserts post)) kw obj))]
|
(∃-solve `(,@(pre) ,(vc-assumes post) ,(vc-asserts post)) kw obj))]
|
||||||
[(_ {~and kw1 {~or* #:minimize #:maximize}} opt1
|
[(_ kw1 opt1 kw2 opt2 #:guarantee expr)
|
||||||
{~and kw2 {~or* #:minimize #:maximize}} opt2
|
(let ([obj1 opt1] ; evaluate objectives first to add their spec to (vc)
|
||||||
#:guarantee expr)
|
|
||||||
#'(let ([obj1 opt1] ; evaluate objectives first to add their spec to (vc)
|
|
||||||
[obj2 opt2]
|
[obj2 opt2]
|
||||||
[post (query-vc expr)])
|
[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))]))
|
||||||
|
|
@ -12,8 +12,6 @@
|
||||||
|
|
||||||
(provide (all-defined-out))
|
(provide (all-defined-out))
|
||||||
|
|
||||||
(define (unique/reverse xs)
|
|
||||||
(reverse (unique xs)))
|
|
||||||
|
|
||||||
(define (find-solver binary base-path [user-path #f])
|
(define (find-solver binary base-path [user-path #f])
|
||||||
(cond
|
(cond
|
||||||
|
|
@ -44,15 +42,14 @@
|
||||||
(unless (list? bools)
|
(unless (list? bools)
|
||||||
(raise-argument-error 'solver-assert "(listof boolean?)" bools))
|
(raise-argument-error 'solver-assert "(listof boolean?)" bools))
|
||||||
(define wfcheck-cache (mutable-set))
|
(define wfcheck-cache (mutable-set))
|
||||||
(set-solver-asserts!
|
(set-solver-asserts! self
|
||||||
self
|
(append (solver-asserts self)
|
||||||
(append (for/list ([b bools] #:unless (equal? b #t))
|
(for/list ([b bools] #:unless (equal? b #t))
|
||||||
(unless (or (boolean? b) (and (term? b) (equal? @boolean? (term-type b))))
|
(unless (or (boolean? b) (and (term? b) (equal? @boolean? (term-type b))))
|
||||||
(error 'assert "expected a boolean value, given ~s" b))
|
(error 'assert "expected a boolean value, given ~s" b))
|
||||||
(when wfcheck
|
(when wfcheck
|
||||||
(wfcheck b wfcheck-cache))
|
(wfcheck b wfcheck-cache))
|
||||||
b)
|
b))))
|
||||||
(solver-asserts self))))
|
|
||||||
|
|
||||||
(define (solver-minimize self nums)
|
(define (solver-minimize self nums)
|
||||||
(unless (null? nums)
|
(unless (null? nums)
|
||||||
|
|
@ -71,7 +68,7 @@
|
||||||
(server-shutdown (solver-server self)))
|
(server-shutdown (solver-server self)))
|
||||||
|
|
||||||
(define (solver-push self)
|
(define (solver-push self)
|
||||||
(match-define (solver server _ (app unique asserts) (app unique/reverse mins) (app unique/reverse maxs) env level) self)
|
(match-define (solver server _ (app unique asserts) (app unique mins) (app unique maxs) env level) self)
|
||||||
(server-write
|
(server-write
|
||||||
server
|
server
|
||||||
(begin
|
(begin
|
||||||
|
|
@ -93,7 +90,7 @@
|
||||||
(set-solver-level! self (drop level k)))
|
(set-solver-level! self (drop level k)))
|
||||||
|
|
||||||
(define (solver-check self [read-solution read-solution])
|
(define (solver-check self [read-solution read-solution])
|
||||||
(match-define (solver server _ (app unique asserts) (app unique/reverse mins) (app unique/reverse maxs) env _) self)
|
(match-define (solver server _ (app unique asserts) (app unique mins) (app unique maxs) env _) self)
|
||||||
(cond [(ormap false? asserts) (unsat)]
|
(cond [(ormap false? asserts) (unsat)]
|
||||||
[else (server-write
|
[else (server-write
|
||||||
server
|
server
|
||||||
|
|
@ -134,9 +131,7 @@
|
||||||
; core was extracted); #f (if the solution is
|
; core was extracted); #f (if the solution is
|
||||||
; 'unsat and no core was extracted); or 'unknown otherwise.
|
; 'unsat and no core was extracted); or 'unknown otherwise.
|
||||||
(define (read-solution server env #:unsat-core? [unsat-core? #f])
|
(define (read-solution server env #:unsat-core? [unsat-core? #f])
|
||||||
(decode (parse-solution server #:unsat-core? unsat-core?) env))
|
(decode
|
||||||
|
|
||||||
(define (parse-solution server #:unsat-core? [unsat-core? #f])
|
|
||||||
(parameterize ([current-readtable (make-readtable #f #\# #\a #f)]) ; read BV literals as symbols
|
(parameterize ([current-readtable (make-readtable #f #\# #\a #f)]) ; read BV literals as symbols
|
||||||
(match (server-read server (read))
|
(match (server-read server (read))
|
||||||
[(== 'sat)
|
[(== 'sat)
|
||||||
|
|
@ -144,11 +139,7 @@
|
||||||
(let loop ()
|
(let loop ()
|
||||||
(match (server-read server (read))
|
(match (server-read server (read))
|
||||||
[(list (== 'objectives) _ ...) (loop)]
|
[(list (== 'objectives) _ ...) (loop)]
|
||||||
; The SMT-LIB spec says that a model should be just a list of
|
[(list (== 'model) def ...)
|
||||||
; `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)))
|
(for/hash ([d def] #:when (and (pair? d) (equal? (car d) 'define-fun)))
|
||||||
(values (cadr d) d))]
|
(values (cadr d) d))]
|
||||||
[other (error 'read-solution "expected model, given ~a" other)]))]
|
[other (error 'read-solution "expected model, given ~a" other)]))]
|
||||||
|
|
@ -161,4 +152,5 @@
|
||||||
[other (error 'read-solution "expected unsat core, given ~a" other)]))
|
[other (error 'read-solution "expected unsat core, given ~a" other)]))
|
||||||
'unsat)]
|
'unsat)]
|
||||||
[(== 'unknown) 'unknown]
|
[(== 'unknown) 'unknown]
|
||||||
[other (error 'read-solution "unrecognized solver output: ~a" other)])))
|
[other (error 'read-solution "unrecognized solver output: ~a" other)]))
|
||||||
|
env))
|
||||||
|
|
|
||||||
|
|
@ -1,106 +0,0 @@
|
||||||
;;; 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))])))
|
|
||||||
|
|
@ -107,10 +107,28 @@
|
||||||
|
|
||||||
|
|
||||||
; Reads the SMT solution from the server.
|
; Reads the SMT solution from the server.
|
||||||
; This is the same as `base/read-solution` except that it applies some fixups
|
; The solution consists of 'sat or 'unsat, followed by
|
||||||
; for quirks in how various versions of Boolector have emitted models.
|
; 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.
|
||||||
(define (boolector-read-solution server env)
|
(define (boolector-read-solution server env)
|
||||||
(define raw-model (base/parse-solution server))
|
(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)])))
|
||||||
; First, we need to fix up the model's shadowing of incremental variables
|
; 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))
|
(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
|
; Now decode in an environment with fake types for UFs
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
#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)
|
|
||||||
|
|
@ -14,8 +14,7 @@
|
||||||
@bvslt @bvsle @bvult @bvule
|
@bvslt @bvsle @bvult @bvule
|
||||||
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
|
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
|
||||||
@bvneg @bvadd @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
|
@bvneg @bvadd @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
|
||||||
@z3_ext_rotate_left @z3_ext_rotate_right
|
@concat @extract))
|
||||||
@concat @extract @sign-extend @zero-extend))
|
|
||||||
|
|
||||||
|
|
||||||
(provide decode-model)
|
(provide decode-model)
|
||||||
|
|
@ -117,6 +116,7 @@
|
||||||
(hash-ref ~env id)]
|
(hash-ref ~env id)]
|
||||||
[(== true) #t]
|
[(== true) #t]
|
||||||
[(== false) #f]
|
[(== false) #f]
|
||||||
|
[(? integer?) (inexact->exact expr)]
|
||||||
[(? real?) expr]
|
[(? real?) expr]
|
||||||
[(? symbol?)
|
[(? symbol?)
|
||||||
(cond
|
(cond
|
||||||
|
|
@ -132,10 +132,6 @@
|
||||||
(bv n (bitvector len))]
|
(bv n (bitvector len))]
|
||||||
[(list (list (== '_) (== 'extract) i j) s)
|
[(list (list (== '_) (== 'extract) i j) s)
|
||||||
`(, @extract ,(inline i sol ~env) ,(inline j sol ~env) ,(inline s sol ~env))]
|
`(, @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)
|
[(list (== 'let) binds body)
|
||||||
(substitute (inline body sol ~env)
|
(substitute (inline body sol ~env)
|
||||||
(for/hash ([id:expr binds])
|
(for/hash ([id:expr binds])
|
||||||
|
|
@ -166,7 +162,6 @@
|
||||||
'bvslt @bvslt 'bvsle @bvsle 'bvult @bvult 'bvule @bvule
|
'bvslt @bvslt 'bvsle @bvsle 'bvult @bvult 'bvule @bvule
|
||||||
'bvnot @bvnot 'bvor @bvor 'bvand @bvand 'bvxor @bvxor
|
'bvnot @bvnot 'bvor @bvor 'bvand @bvand 'bvxor @bvxor
|
||||||
'bvshl @bvshl 'bvlshr @bvlshr 'bvashr @bvashr
|
'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
|
'bvneg @bvneg 'bvadd @bvadd 'bvmul @bvmul
|
||||||
'bvudiv @bvudiv 'bvsdiv @bvsdiv
|
'bvudiv @bvudiv 'bvsdiv @bvsdiv
|
||||||
'bvurem @bvurem 'bvsrem @bvsrem
|
'bvurem @bvurem 'bvsrem @bvsrem
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
|
@bvnot @bvor @bvand @bvxor @bvshl @bvlshr @bvashr
|
||||||
@bvneg @bvadd @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
|
@bvneg @bvadd @bvmul @bvudiv @bvsdiv @bvurem @bvsrem @bvsmod
|
||||||
@concat @extract @zero-extend @sign-extend
|
@concat @extract @zero-extend @sign-extend
|
||||||
@z3_ext_rotate_left @z3_ext_rotate_right
|
|
||||||
@integer->bitvector @bitvector->integer @bitvector->natural))
|
@integer->bitvector @bitvector->integer @bitvector->natural))
|
||||||
|
|
||||||
(provide enc)
|
(provide enc)
|
||||||
|
|
@ -109,7 +108,6 @@
|
||||||
[@bveq $=] [@bvslt $bvslt] [@bvsle $bvsle] [@bvult $bvult] [@bvule $bvule]
|
[@bveq $=] [@bvslt $bvslt] [@bvsle $bvsle] [@bvult $bvult] [@bvule $bvule]
|
||||||
[@bvnot $bvnot] [@bvor $bvor] [@bvand $bvand] [@bvxor $bvxor]
|
[@bvnot $bvnot] [@bvor $bvor] [@bvand $bvand] [@bvxor $bvxor]
|
||||||
[@bvshl $bvshl] [@bvlshr $bvlshr] [@bvashr $bvashr]
|
[@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]
|
[@bvneg $bvneg] [@bvadd $bvadd] [@bvmul $bvmul] [@bvudiv $bvudiv] [@bvsdiv $bvsdiv]
|
||||||
[@bvurem $bvurem] [@bvsrem $bvsrem] [@bvsmod $bvsmod] [@concat $concat])
|
[@bvurem $bvurem] [@bvsrem $bvsrem] [@bvsmod $bvsmod] [@concat $concat])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,8 +68,7 @@
|
||||||
bvnot bvand bvor bvxor
|
bvnot bvand bvor bvxor
|
||||||
bvule bvult bvuge bvugt bvsle bvslt bvsge bvsgt
|
bvule bvult bvuge bvugt bvsle bvslt bvsge bvsgt
|
||||||
bvneg bvadd bvsub bvmul bvsdiv bvudiv bvurem bvsrem bvsmod
|
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)
|
(define (extract i j s)
|
||||||
`((_ extract ,i ,j) ,s))
|
`((_ extract ,i ,j) ,s))
|
||||||
|
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
#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)
|
|
||||||
|
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
#lang racket
|
#lang racket
|
||||||
|
|
||||||
(require racket/runtime-path
|
(require racket/runtime-path
|
||||||
"server.rkt" "env.rkt"
|
"server.rkt" "env.rkt" "cmd.rkt"
|
||||||
"../solver.rkt"
|
"../solver.rkt"
|
||||||
(prefix-in base/ "base-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))
|
||||||
|
|
||||||
(provide (rename-out [make-yices yices]) yices? yices-available?)
|
(provide (rename-out [make-yices yices]) yices? yices-available?)
|
||||||
|
|
||||||
|
|
@ -11,17 +15,17 @@
|
||||||
(define yices-opts '("--incremental"))
|
(define yices-opts '("--incremental"))
|
||||||
|
|
||||||
(define (yices-available?)
|
(define (yices-available?)
|
||||||
(not (false? (base/find-solver "yices-smt2" yices-path #f))))
|
(not (false? (base/find-solver "yices" 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 (make-yices [solver #f] #:options [options (hash)] #:logic [logic 'ALL] #:path [path #f])
|
||||||
(define config
|
(define config
|
||||||
(cond
|
(cond
|
||||||
[(yices? solver)
|
[(yices? solver)
|
||||||
(base/solver-config solver)]
|
(base/solver-config solver)]
|
||||||
[else
|
[else
|
||||||
(define real-yices-path (base/find-solver "yices-smt2" yices-path path))
|
(define real-yices-path (base/find-solver "yices" yices-path path))
|
||||||
(when (and (false? real-yices-path) (not (getenv "PLT_PKG_BUILD_SERVICE")))
|
(when (and (false? real-yices-path) (not (getenv "PLT_PKG_BUILD_SERVICE")))
|
||||||
(error 'yices "yices-smt2 binary is not available (expected to be at ~a); try passing the #:path argument to (yices)" (path->string (simplify-path yices-path))))
|
(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))))
|
||||||
(base/config options real-yices-path logic)]))
|
(base/config options real-yices-path logic)]))
|
||||||
(yices (server (base/config-path config) yices-opts (base/make-send-options config)) config '() '() '() (env) '()))
|
(yices (server (base/config-path config) yices-opts (base/make-send-options config)) config '() '() '() (env) '()))
|
||||||
|
|
||||||
|
|
@ -32,13 +36,13 @@
|
||||||
#:methods gen:solver
|
#:methods gen:solver
|
||||||
[
|
[
|
||||||
(define (solver-features self)
|
(define (solver-features self)
|
||||||
'(qf_bv))
|
'(qf_bv qf_uf qf_lia qf_lra))
|
||||||
|
|
||||||
(define (solver-options self)
|
(define (solver-options self)
|
||||||
(base/solver-options self))
|
(base/solver-options self))
|
||||||
|
|
||||||
(define (solver-assert self bools)
|
(define (solver-assert self bools)
|
||||||
(base/solver-assert self bools))
|
(base/solver-assert self bools yices-wfcheck))
|
||||||
|
|
||||||
(define (solver-minimize self nums)
|
(define (solver-minimize self nums)
|
||||||
(base/solver-minimize self nums))
|
(base/solver-minimize self nums))
|
||||||
|
|
@ -59,11 +63,85 @@
|
||||||
(base/solver-pop self k))
|
(base/solver-pop self k))
|
||||||
|
|
||||||
(define (solver-check self)
|
(define (solver-check self)
|
||||||
(base/solver-check self))
|
(base/solver-check self yices-read-solution))
|
||||||
|
|
||||||
(define (solver-debug self)
|
(define (solver-debug self)
|
||||||
(base/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))
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,7 @@
|
||||||
[else
|
[else
|
||||||
(define real-z3-path (base/find-solver "z3" z3-path path))
|
(define real-z3-path (base/find-solver "z3" z3-path path))
|
||||||
(when (and (false? real-z3-path) (not (getenv "PLT_PKG_BUILD_SERVICE")))
|
(when (and (false? real-z3-path) (not (getenv "PLT_PKG_BUILD_SERVICE")))
|
||||||
(fprintf (current-error-port)
|
(printf "warning: could not find z3 executable at ~a\n" (path->string (simplify-path z3-path))))
|
||||||
"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)))
|
(define opts (hash-union default-options options #:combine (lambda (a b) b)))
|
||||||
(base/config opts real-z3-path logic)]))
|
(base/config opts real-z3-path logic)]))
|
||||||
(z3 (server (base/config-path config) z3-opts (base/make-send-options config)) config '() '() '() (env) '()))
|
(z3 (server (base/config-path config) z3-opts (base/make-send-options config)) config '() '() '() (env) '()))
|
||||||
|
|
@ -54,10 +52,10 @@
|
||||||
(base/solver-assert self bools))
|
(base/solver-assert self bools))
|
||||||
|
|
||||||
(define (solver-minimize self nums)
|
(define (solver-minimize self nums)
|
||||||
(base/set-solver-mins! self (append (reverse (numeric-terms nums 'solver-minimize)) (base/solver-mins self))))
|
(base/set-solver-mins! self (append (base/solver-mins self) (numeric-terms nums 'solver-minimize))))
|
||||||
|
|
||||||
(define (solver-maximize self nums)
|
(define (solver-maximize self nums)
|
||||||
(base/set-solver-maxs! self (append (reverse (numeric-terms nums 'solver-maximize)) (base/solver-maxs self))))
|
(base/set-solver-maxs! self (append (base/solver-maxs self) (numeric-terms nums 'solver-maximize))))
|
||||||
|
|
||||||
(define (solver-clear self)
|
(define (solver-clear self)
|
||||||
(base/solver-clear-stacks! self)
|
(base/solver-clear-stacks! self)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#lang rosette
|
#lang rosette
|
||||||
|
|
||||||
(require
|
(require
|
||||||
|
rosette/lib/lift
|
||||||
(prefix-in racket/ (only-in racket string-append symbol->string regexp-match?)))
|
(prefix-in racket/ (only-in racket string-append symbol->string regexp-match?)))
|
||||||
|
|
||||||
(provide (all-defined-out))
|
(provide (all-defined-out))
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,7 @@
|
||||||
(require (only-in rosette solver-features current-solver) "base/solver.rkt"
|
(require (only-in rosette solver-features current-solver) "base/solver.rkt"
|
||||||
rosette/lib/roseunit
|
rosette/lib/roseunit
|
||||||
rosette/solver/smt/z3 rosette/solver/smt/cvc4
|
rosette/solver/smt/z3 rosette/solver/smt/cvc4
|
||||||
rosette/solver/smt/boolector
|
rosette/solver/smt/boolector rosette/solver/smt/yices
|
||||||
rosette/solver/smt/cvc5
|
|
||||||
rosette/solver/smt/bitwuzla
|
|
||||||
rosette/solver/smt/stp
|
|
||||||
rosette/solver/smt/yices
|
|
||||||
"config.rkt")
|
"config.rkt")
|
||||||
|
|
||||||
(error-print-width default-error-print-width)
|
(error-print-width default-error-print-width)
|
||||||
|
|
@ -42,7 +38,6 @@
|
||||||
"base/distinct.rkt"
|
"base/distinct.rkt"
|
||||||
"base/generics.rkt"
|
"base/generics.rkt"
|
||||||
"base/push-pop.rkt"
|
"base/push-pop.rkt"
|
||||||
"base/optimize-order.rkt"
|
|
||||||
"base/reflect.rkt"
|
"base/reflect.rkt"
|
||||||
"base/decode.rkt"
|
"base/decode.rkt"
|
||||||
"query/solve.rkt"
|
"query/solve.rkt"
|
||||||
|
|
@ -86,20 +81,8 @@
|
||||||
(printf "===== Running Boolector tests =====\n")
|
(printf "===== Running Boolector tests =====\n")
|
||||||
(run-tests-with-solver boolector))
|
(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?)
|
(when (yices-available?)
|
||||||
(printf "===== Running Yices2 tests =====\n")
|
(printf "===== Running Yices tests =====\n")
|
||||||
(run-tests-with-solver yices))
|
(run-tests-with-solver yices))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -272,13 +272,13 @@
|
||||||
(define tests:rotate-left
|
(define tests:rotate-left
|
||||||
(test-suite+
|
(test-suite+
|
||||||
"Tests for rotate-left in rosette/base/bvlib.rkt"
|
"Tests for rotate-left in rosette/base/bvlib.rkt"
|
||||||
#:features '(qf_lia int2bv qf_bv)
|
#:features '(qf_lia qf_bv)
|
||||||
(check-rotate rotate-left rotate-right bvrol)))
|
(check-rotate rotate-left rotate-right bvrol)))
|
||||||
|
|
||||||
(define tests:rotate-right
|
(define tests:rotate-right
|
||||||
(test-suite+
|
(test-suite+
|
||||||
"Tests for rotate-right in rosette/base/bvlib.rkt"
|
"Tests for rotate-right in rosette/base/bvlib.rkt"
|
||||||
#:features '(qf_lia int2bv qf_bv)
|
#:features '(qf_lia qf_bv)
|
||||||
(check-rotate rotate-right rotate-left bvror)))
|
(check-rotate rotate-right rotate-left bvror)))
|
||||||
|
|
||||||
(module+ test
|
(module+ test
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
#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)))
|
|
||||||
|
|
@ -14,10 +14,6 @@
|
||||||
(define-symbolic b @boolean?)
|
(define-symbolic b @boolean?)
|
||||||
(define-symbolic c @boolean?)
|
(define-symbolic c @boolean?)
|
||||||
|
|
||||||
(define (f type)
|
|
||||||
(define-symbolic x type)
|
|
||||||
x)
|
|
||||||
|
|
||||||
(define (check-ordered v1 v2)
|
(define (check-ordered v1 v2)
|
||||||
(check-true (and (or (term<? v1 v2) (term<? v2 v1))
|
(check-true (and (or (term<? v1 v2) (term<? v2 v1))
|
||||||
(not (and (term<? v1 v2) (term<? v2 v1))))))
|
(not (and (term<? v1 v2) (term<? v2 v1))))))
|
||||||
|
|
@ -53,47 +49,7 @@
|
||||||
(check-cached @/ x y)
|
(check-cached @/ x y)
|
||||||
(check-cached @remainder x y)
|
(check-cached @remainder x y)
|
||||||
(check-cached @= 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
|
(module+ test
|
||||||
(time (run-tests value-tests))
|
(time (run-tests value-tests)))
|
||||||
(time (run-tests clear-terms!+gc-terms!-tests)))
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue