Pastry is an academic prototype for deciding (positive) almost-sure termination ((P)AST) of essentially 1-dimensional probabilistic counter programs (PCPs). For more technical details, please refer to our CAV'25 paper:
Sergei Novozhilov, Mingqi Yang, Mingshuai Chen, Zhiyang Li, Jianwei Yin: On the Almost-Sure Termination of Probabilistic Counter Programs. In Proc. of CAV 2025.
- Project Structure
- Requirements
- Setup (Docker)
- Smoke test (Docker)
- Setup (Poetry)
- Smoke test (Poetry)
- Replicate the results from the paper
- Write your own example
- Run your own example
- Becnhmarks
- Build Artifacts
- One-Click Table Generation
- Install Docker (https://www.docker.com/get-started/) in case you do not have it yet.
- Experiments in the paper are conducted on a 3.22 GHz Apple M1 Pro processor with 16GB RAM running macOS Sonoma. Make sure to have similar specs when comparing timing results and consider differences running in a sandbox (docker).
We provide two possilbe ways of project setup:
- Building a docker container
- Using Poetry package manager
To create a docker container from the provided tar file:
docker build -t pastry:latest .For a quick test to see if everything works:
docker run --rm pastry:latest pastry/batch_test.sh --input \
test/ast.txt \
test/past.txt \
test/none.txtExpected output is:
Running: test/ast.txt
AST : True
PAST : False
Time : 0.097s
Running: test/past.txt
AST : True
PAST : True
Time : 0.013s
Running: test/none.txt
AST : False
PAST : False
Time : 0.01s
poetry installTo test the correctness of the setup, run:
cd poetry && poetry run python pastry.py --input \
./test/ast.txt \
./test/past.txt \
./test/none.txtExpected output is:
Running: ./test/ast.txt
AST : True
PAST : False
Time : 0.053s
Running: ./test/past.txt
AST : True
PAST : True
Time : 0.017s
Running: ./test/none.txt
AST : False
PAST : False
Time : 0.011s
To run the benchmark suite, run:
docker run --rm -v $(pwd)/outputs:/home/artifact/pastry/outputs -v $(pwd)/result:/home/artifact/result --entrypoint bash pastry:latest pastry/benchmark.shThe detailed logs will be available in the ./outputs/logs folder
This section describes the input language used by Pastry and explains how users can write and annotate their own probabilistic counter programs. Example programs are provided to illustrate the format.
start: declarations instructions
declarations: declaration* -> declarations
declaration: "int" var "=" INT
instructions: instruction* -> instructions
instruction: "skip" -> skip
| "while" "(" guard ")" block -> while
| "if" "(" guard ")" block "else" block -> if
| block "[" PROB "]" block -> choice
| var ":=" var "+" NAT -> inc_assign
| var ":=" var "-" NAT -> dec_assign
block: "{" instruction* "}"
expression: var -> var
| INT -> int
| expression "+" expression -> add
| expression "-" expression -> sub
| expression "*" expression -> mul
| expression "**" NAT -> pow
| "MOD" "(" expression "," POSINT ")" -> mod
| "DIV" "(" expression "," POSINT ")" -> div
guard: "true" -> true
| "false" -> false
| expression ">" expression -> gt
| expression "<" expression -> lt
| expression ">=" expression -> ge
| expression "<=" expression -> le
| "Eq" "(" expression "," expression ")" -> eq
| "Ne" "(" expression "," expression ")" -> neq
| "(" guard ")" "&" "(" guard ")" -> and
| "(" guard ")" "|" "(" guard ")" -> or
| "Not" "(" guard ")" -> not
literal: INT -> int
| NAT -> nat
| POSINT -> pos_int
| PROB -> prob
var: CNAME
Note: Non-counting assignments like var := c are not allowed. Instead, use two consecutive counter-style loops to simulate it as
while (var < c) { var := var + 1 }
while (var > c) { var := var - 1 }
In addition to 1-d PCPs, Pastry admits four classes of
- For All But One Counters are Bounded PCPs, users need to annotate the unbounded variable and the bounds (in the form of closed intervals) for the other variables at the top of the program using the following format:
/*@Bounded, <unbounded_var>, <var1>,[<lower>,<upper>], <var2>, [<lower>,<upper>], ...@*/. If all variable are bounded,<unbounded_var>can be omitted from the annotation. - For Conditionally Bounded PCPs, users need to provide valid constants (see Section 5 of the paper) at the top of the program using the following format:
/*@CondBounded, y, x1[A1,B1,C1,D1], x2[A2,B2,C2,D2], ...@*/
An example of
# this is a comment
int x = 10
while(x**5 - 4*x**2 + x >= 0){
if(x <= 1000){
{x := x - 2}[1/2]{x := x + 1}
}else{
{x := x - 1}[1/2]{x := x + 2}
}
}
An example of All But One Counters are Bounded PCP:
# this is a comment
/*@Bounded,i,[0,1],j,[0,2]@*/
int i = 0
int j = 0
while(i < 1){
if(j < 2){
i := i + 1
}else{
j := j - 2
}
}
An example of Monotone PCP:
# this is a comment
int x = -3
int y = 0
while(x < 0){
{x := x + 1}[1/10]{skip}
while(y >= 1){
{y := y - 1}[2/3]{y := y - 2}
}
y := y + 1
}
An example of Conditionally Bounded PCP:
# this is a comment
/*@CondBounded,y,x[1,1,0,1]@*/
int x = 1
int y = 1
while(x + y >= 0){
{x := x + 1; y := y + 1}[0.5]{x := x - 1; y := y - 1}
if(Eq(x, y)){
{y := y + 1}[0.5]{y := y - 1}
}else{
}
}
An example of Constant PCP:
# this is a comment
int T = 0
int H = 0
while(T - H > -1){
{T := T + 1}[9/10]{H := H + 1}
}
More examples can be found in the benchmarks folder.
Suppose you saved your example in a file named xxx.txt in the path /home/artifact/benchmarks/pastry. Then the tool can be run as:
./run.sh pastry xxxPastry accepts a list of program files, printing the termination status for each of the file, for example
poetry run python pastry.py --input \
benchmarks/src01/2d_bounded_rw.txt \
benchmarks/src01/biased_rw1.txtThe expected output (time measurments will vary from system to system):
Running: benchmarks/src01/2d_bounded_rw.txt
AST : True
PAST : True
Time : 1.58s
Running: benchmarks/src01/biased_rw1.txt
AST : False
PAST : False
Time : 0.02s
To run on the benchmark suite:
find benchmarks -name "*.txt" -type f | sort | xargs -I{} poetry run python pastry.py --input {}Docker image can be envoked either using a wrapper:
bash run.sh program.txtoptionally, it can be done by mounting a directory containing the target intput. Suppose, the target program is located at /host/location/program.txt, then docker image can be invoked as
docker run --rm -v /host/location/:/data pastry:latest --input /data/program.txtTo run on the benchmark suite, run:
docker run --rm -v $(pwd)/outputs:/app/outputs --entrypoint bash pastry:latest benchmark.sh To build a docker image, run:
docker build -t pastry:latest .To run the docker image on a file located at the host's path /path/to/data/input.txt, run
docker run --rm -v /path/to/data:/data pastry:latest --input /data/input.txtTo generate csv file for pastry:
bash gen_csv.sh