Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limited functions #54

Open
wants to merge 45 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
6a0eb63
ignore .idea
ole-thoeb Oct 14, 2024
86636f0
generation working?
ole-thoeb Oct 15, 2024
edea5f6
stop z3 from being too smart.
ole-thoeb Oct 15, 2024
f32b61f
Always add the "fuel synonym axiom" for function that have a fuel par…
ole-thoeb Oct 16, 2024
694edfd
Cleanup fuel code
ole-thoeb Oct 17, 2024
e049f54
Use `OnceCell<T>` over `RefCell<Option<T>>` for lazy initialisation
ole-thoeb Oct 20, 2024
722f145
`Lit`-wrap constants without propagation
ole-thoeb Oct 22, 2024
180403d
rustfmt
ole-thoeb Oct 23, 2024
ac29f5a
clippy
ole-thoeb Oct 23, 2024
fc14dca
bundle flags for `SmtCtx` in `SmtCtxOptions` struct
ole-thoeb Nov 4, 2024
40cb672
Address most of the PR feedback
ole-thoeb Nov 4, 2024
ea7b6c9
propagate const information and cleanup axiom generation
ole-thoeb Nov 5, 2024
5ea3ba3
Correctly construct `SmtCtx` in test
ole-thoeb Nov 5, 2024
0858fa1
Change quantifier translation a bit, again
ole-thoeb Nov 6, 2024
710cdb8
update/improve comments
ole-thoeb Nov 6, 2024
634df49
Redo parts of code generation for fuel encoding + more examples
ole-thoeb Nov 10, 2024
fe24531
All caps TODO breaks test runner??!
ole-thoeb Nov 10, 2024
79a853f
Fix run command
ole-thoeb Nov 11, 2024
1df7670
don't try to compile example type given in docs
ole-thoeb Nov 11, 2024
63bfd4e
Make rust type provided for intuition actually compile
ole-thoeb Nov 11, 2024
9bed56d
Ensure new types/function can not clash with user defined code
ole-thoeb Nov 11, 2024
6ec2096
Only encode non-zero fuel condition in trigger
ole-thoeb Nov 12, 2024
09dc2c3
More examples
ole-thoeb Nov 25, 2024
9b701c6
Closely mimic encoding from paper
ole-thoeb Nov 27, 2024
d0e7b15
Revert back to the Dafny way of fuel.
ole-thoeb Dec 5, 2024
e807772
Fix lit wrapping
ole-thoeb Dec 5, 2024
0c16039
Add quantifier ids and weight to foralls
ole-thoeb Dec 5, 2024
6f8b365
Adjust integration tests
ole-thoeb Dec 5, 2024
4a82860
rust fmt
ole-thoeb Dec 5, 2024
0a53472
Consider less function calls as constant
ole-thoeb Dec 13, 2024
1f0fe09
Make test less flaky by adding `@trigger`
ole-thoeb Dec 13, 2024
def8c85
Enable datatype specific lit wrapping
ole-thoeb Dec 23, 2024
fc6d452
Fixes after rebasing
ole-thoeb Dec 23, 2024
8ba5a71
Rename ConstantExpr... to LiteralExpr... and use builder style for co…
ole-thoeb Dec 24, 2024
631b728
Add tracing to literal value collecting
ole-thoeb Dec 26, 2024
f944bea
Do not lit-wrap if we can not profit from it
ole-thoeb Jan 3, 2025
971fdfd
clone prover when slicing instead of using push/pop
ole-thoeb Jan 9, 2025
669d70c
Fighting in vain with z3 params
ole-thoeb Jan 11, 2025
5b8fdaa
Revert "Fighting in vain with z3 params"
ole-thoeb Jan 31, 2025
de430c5
set parameters via `set_global_param`
ole-thoeb Jan 31, 2025
932eedb
Removed superfluous parameter setting
ole-thoeb Feb 6, 2025
68c1680
Add plain version of fuel, not using datatype
ole-thoeb Feb 7, 2025
5ffd375
Add `--static-fuel` flag
ole-thoeb Feb 10, 2025
0d7232e
Also generate computation axioms for static fuel
ole-thoeb Feb 11, 2025
d3ed935
Rename different encodings and consolidate fuel encodings
ole-thoeb Feb 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
target
.idea
.DS_Store
benchmark-results.csv
vscode-ext/node_modules/
Expand Down
16 changes: 4 additions & 12 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ edition = "2021"
build = "build.rs" # LALRPOP preprocessing

[features]
default = ["static-link-z3"]
default = ["static-link-z3", "datatype-fuel"]
datatype-eureal = ["z3rro/datatype-eureal"]
datatype-eureal-funcs = ["z3rro/datatype-eureal-funcs"]
datatype-fuel=["z3rro/datatype-fuel"]
static-link-z3 = ["z3/static-link-z3"]
# Emit log messages to stderr without timing information. This is useful to diff logs.
log-print-timeless = []
Expand Down Expand Up @@ -80,8 +81,8 @@ harness = false
opt-level = 3

[patch.crates-io]
z3 = { git = 'https://github.com/Philipp15b/z3.rs.git', rev = 'bdd501ca1e50785365b875b3438a0cf953cffbfc' }
z3-sys = { git = 'https://github.com/Philipp15b/z3.rs.git', rev = 'bdd501ca1e50785365b875b3438a0cf953cffbfc' }
z3 = { git = 'https://github.com/prove-rs/z3.rs.git', rev = '60001b36fc8a7ab1d4f22595e80a3b6f7adc1bcf' }
z3-sys = { git = 'https://github.com/prove-rs/z3.rs.git', rev = '60001b36fc8a7ab1d4f22595e80a3b6f7adc1bcf' }
# to work on z3.rs locally, clone it into the main directory and use the following directive instead:
# z3 = { path = 'z3.rs/z3' }

Expand Down
9 changes: 9 additions & 0 deletions src/ast/decl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,15 @@ pub struct DomainDecl {
pub span: Span,
}

impl DomainDecl {
pub fn function_decls(&self) -> impl Iterator<Item = &DeclRef<FuncDecl>> {
self.body.iter().filter_map(|spec| match spec {
DomainSpec::Function(func_ref) => Some(func_ref),
_ => None,
})
}
}

impl SimplePretty for DomainDecl {
fn pretty(&self) -> Doc {
Doc::text("domain")
Expand Down
15 changes: 15 additions & 0 deletions src/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,21 @@ pub enum ExprKind {
Lit(Lit),
}

impl Expr {
pub fn children_mut(&mut self) -> Vec<&mut Expr> {
match &mut self.kind {
ExprKind::Var(_) | ExprKind::Lit(_) => vec![],
ExprKind::Call(_, args) => args.iter_mut().collect(),
ExprKind::Ite(cond, branch1, branch2) => vec![cond, branch1, branch2],
ExprKind::Binary(_, lhs, rhs) => vec![lhs, rhs],
ExprKind::Unary(_, operand) => vec![operand],
ExprKind::Cast(operand) => vec![operand],
ExprKind::Quant(_, _, _, expr) => vec![expr],
ExprKind::Subst(_, subst, expr) => vec![subst, expr],
}
}
}

impl SimplePretty for Expr {
fn pretty(&self) -> Doc {
let res = match &self.kind {
Expand Down
48 changes: 48 additions & 0 deletions src/ast/shared.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
use ref_cast::RefCast;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::{
fmt,
ops::{Deref, DerefMut},
Expand Down Expand Up @@ -72,3 +75,48 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Shared<T> {
fmt::Debug::fmt(&**self, f)
}
}

/// [Shared] wrapper that provides pointer based [Eq] and [Hash] implementations.
#[repr(transparent)]
#[derive(RefCast, Clone)]
pub struct PointerHashShared<T>(Shared<T>);

impl<T> PointerHashShared<T> {
pub fn new(shared: Shared<T>) -> Self {
Self(shared)
}

pub fn into_shared(self) -> Shared<T> {
self.0
}

pub fn as_shared(&self) -> &Shared<T> {
&self.0
}
}

impl<T> PartialEq for PointerHashShared<T> {
fn eq(&self, other: &Self) -> bool {
Shared::as_ptr(&self.0) == Shared::as_ptr(&other.0)
}
}

impl<T> Eq for PointerHashShared<T> {}

impl<T> Ord for PointerHashShared<T> {
fn cmp(&self, other: &Self) -> Ordering {
Shared::as_ptr(&self.0).cmp(&Shared::as_ptr(&other.0))
}
}

impl<T> PartialOrd for PointerHashShared<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(Shared::as_ptr(&self.0).cmp(&Shared::as_ptr(&other.0)))
}
}

impl<T> Hash for PointerHashShared<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
Shared::as_ptr(&self.0).hash(state)
}
}
20 changes: 16 additions & 4 deletions src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ use z3rro::{
util::{PrefixWriter, ReasonUnknown},
};

use crate::smt::{LiteralExprCollector, SmtCtxOptions};
use tracing::{info_span, instrument, trace};

/// Human-readable name for a source unit. Used for debugging and error messages.
Expand Down Expand Up @@ -535,7 +536,7 @@ impl QuantVcUnit {
let _entered = span.enter();
if !options.opt_options.strict {
let ctx = Context::new(&Config::default());
let smt_ctx = SmtCtx::new(&ctx, tcx);
let smt_ctx = SmtCtx::new(&ctx, tcx, SmtCtxOptions::default());
let mut unfolder = Unfolder::new(limits_ref.clone(), &smt_ctx);
unfolder.visit_expr(&mut self.expr)
} else {
Expand Down Expand Up @@ -633,14 +634,23 @@ impl BoolVcUnit {

/// Translate to SMT.
pub fn into_smt_vc<'smt, 'ctx>(
self,
mut self,
translate: &mut TranslateExprs<'smt, 'ctx>,
) -> SmtVcUnit<'ctx> {
let span = info_span!("translation to Z3");
let _entered = span.enter();

translate.set_literal_exprs(
LiteralExprCollector::new()
.with_functions_with_def(translate.ctx.functions_with_def().as_slice())
.collect(&mut self.vc),
);
let bool_vc = translate.t_bool(&self.vc);
translate.clear_literal_exprs();

SmtVcUnit {
quant_vc: self.quant_vc,
vc: translate.t_bool(&self.vc),
vc: bool_vc,
}
}
}
Expand Down Expand Up @@ -689,7 +699,7 @@ impl<'ctx> SmtVcUnit<'ctx> {
});
}

let mut slice_solver = SliceSolver::new(slice_vars.clone(), translate, prover);
let slice_solver = SliceSolver::new(slice_vars.clone(), translate, prover);
let failing_slice_options = SliceSolveOptions {
globally_optimal: !options.slice_options.slice_error_first,
continue_on_unknown: false,
Expand Down Expand Up @@ -769,6 +779,8 @@ fn mk_valid_query_prover<'smt, 'ctx>(
prover.set_timeout(remaining);
}

// add the definition of all used Lit marker functions
smt_translate.ctx.add_lit_axioms_to_prover(&mut prover);
// add assumptions (from axioms and locals) to the prover
smt_translate
.ctx
Expand Down
57 changes: 55 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use std::{
time::{Duration, Instant},
};

use crate::smt::SmtCtxOptions;
use crate::{
ast::TyKind,
driver::mk_z3_ctx,
Expand All @@ -35,7 +36,6 @@ use thiserror::Error;
use timing::DispatchBuilder;
use tokio::task::JoinError;
use tracing::{error, info, warn};

use vc::explain::VcExplanation;
use z3rro::{prover::ProveResult, util::ReasonUnknown};

Expand Down Expand Up @@ -158,6 +158,25 @@ pub struct OptimizationOptions {
/// the current solver state.
#[arg(long)]
pub no_simplify: bool,

/// Limit the number of times a function declaration can be recursively instantiated.
/// Requires that MBQI is disabled with `force-ematching`.
#[arg(long)]
pub limited_functions: bool,

/// Force the SMT solver to only use emaching for quantifier instantiation, disabling mbqi.
#[arg(long)]
pub force_ematching: bool,

/// Do not count applications to constant values towards the instantiation count
/// when using `limited-functions`.
#[arg(long)]
pub lit_wrap: bool,

/// For each function f Generate multiple function f_n (f_2, f_1, f_0) that each respectively
/// can only be instantiated n times. Requires `limited-functions`
#[arg(long)]
pub static_fuel: bool,
}

#[derive(Debug, Default, Args)]
Expand Down Expand Up @@ -232,6 +251,10 @@ pub struct DebugOptions {
/// Enable Z3 tracing for the final SAT check.
#[arg(long)]
pub z3_trace: bool,

/// An explicit seed used by Z3 for the final SAT check.
#[arg(long)]
pub z3_seed: Option<u32>,
}

#[derive(Debug, Default, Args)]
Expand Down Expand Up @@ -634,6 +657,9 @@ fn verify_files_main(
warn!("Z3 tracing is enabled with multiple verification units. Intermediate tracing results will be overwritten.");
}

// set requested global z3 options
set_global_z3_options(options, &limits_ref);

let mut num_proven: usize = 0;
let mut num_failures: usize = 0;

Expand Down Expand Up @@ -698,7 +724,15 @@ fn verify_files_main(

// 11. Translate to Z3
let ctx = mk_z3_ctx(options);
let smt_ctx = SmtCtx::new(&ctx, &tcx);
let smt_ctx = SmtCtx::new(
&ctx,
&tcx,
SmtCtxOptions {
use_limited_functions: options.opt_options.limited_functions,
lit_wrap: options.opt_options.lit_wrap,
static_fuel: options.opt_options.static_fuel,
},
);
let mut translate = TranslateExprs::new(&smt_ctx);
let mut vc_is_valid = vc_is_valid.into_smt_vc(&mut translate);

Expand Down Expand Up @@ -773,3 +807,22 @@ fn print_timings() {
.collect();
eprintln!("Timings: {:?}", timings);
}

fn set_global_z3_options(options: &Options, limits_ref: &LimitsRef) {
// the parameters are set as globals since params set via (Solver::set_params) sometimes get ignored.

// default
z3::set_global_param("smt.qi.eager_threshold", "100");
z3::set_global_param("smt.qi.lazy_threshold", "1000");
if options.opt_options.force_ematching {
// z3::set_global_param("auto-config", "false");
// z3::set_global_param("smt.mbqi", "false");
z3::set_global_param("smt.mbqi.id", "mbqi");
}
if let Some(seed) = options.debug_options.z3_seed {
z3::set_global_param("smt.random_seed", &seed.to_string());
}
if let Some(timeout) = limits_ref.time_left() {
z3::set_global_param("timeout", &timeout.as_millis().to_string())
}
}
3 changes: 2 additions & 1 deletion src/opt/fuzz_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use proptest::{
};
use z3rro::prover::{ProveResult, Prover};

use crate::smt::SmtCtxOptions;
use crate::{
ast::{
BinOpKind, DeclKind, DeclRef, Expr, ExprBuilder, ExprData, ExprKind, Ident, LitKind,
Expand Down Expand Up @@ -198,7 +199,7 @@ fn prove_equiv(expr: Expr, optimized: Expr, tcx: &TyCtx) -> TestCaseResult {
optimized.clone(),
);
let ctx = z3::Context::new(&z3::Config::new());
let smt_ctx = SmtCtx::new(&ctx, tcx);
let smt_ctx = SmtCtx::new(&ctx, tcx, SmtCtxOptions::default());
let mut translate = TranslateExprs::new(&smt_ctx);
let eq_expr_z3 = translate.t_bool(&eq_expr);
let mut prover = Prover::new(&ctx);
Expand Down
3 changes: 2 additions & 1 deletion src/opt/unfolder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ fn negate_expr(expr: Expr) -> Expr {
#[cfg(test)]
mod test {
use super::Unfolder;
use crate::smt::SmtCtxOptions;
use crate::{
ast::visit::VisitorMut, fuzz_expr_opt_test, opt::fuzz_test, resource_limits::LimitsRef,
smt::SmtCtx,
Expand All @@ -285,7 +286,7 @@ mod test {
fuzz_expr_opt_test!(|mut expr| {
let tcx = fuzz_test::mk_tcx();
let z3_ctx = z3::Context::new(&z3::Config::default());
let smt_ctx = SmtCtx::new(&z3_ctx, &tcx);
let smt_ctx = SmtCtx::new(&z3_ctx, &tcx, SmtCtxOptions::default());
let limits_ref = LimitsRef::new(None);
let mut unfolder = Unfolder::new(limits_ref, &smt_ctx);
unfolder.visit_expr(&mut expr).unwrap();
Expand Down
Loading