use crate::ir_utils;
use crate::prover::types::{
AssertionSemantics, EquivParallelism, EquivReport, EquivResult, ParamDomains, ProverFn,
};
use crate::prover::{SolverChoice, SolverLimits, prover_for_choice_with_limits};
use std::borrow::Cow;
use std::collections::HashMap;
use std::path::Path;
use std::time::Instant;
#[derive(Clone)]
pub struct IrModule<'a> {
pub source: &'a str,
pub path: Option<&'a Path>,
pub top: Option<&'a str>,
pub param_domains: Option<&'a ParamDomains>,
pub uf_map: Cow<'a, HashMap<String, String>>,
pub fixed_implicit_activation: bool,
}
impl<'a> IrModule<'a> {
pub fn new(source: &'a str) -> Self {
Self {
source,
path: None,
top: None,
param_domains: None,
uf_map: Cow::Owned(HashMap::new()),
fixed_implicit_activation: false,
}
}
pub fn with_top(mut self, top: Option<&'a str>) -> Self {
self.top = top;
self
}
pub fn with_param_domains(mut self, domains: Option<&'a ParamDomains>) -> Self {
self.param_domains = domains;
self
}
pub fn with_uf_map(mut self, uf_map: &'a HashMap<String, String>) -> Self {
self.uf_map = Cow::Borrowed(uf_map);
self
}
pub fn with_owned_uf_map(mut self, uf_map: HashMap<String, String>) -> Self {
self.uf_map = Cow::Owned(uf_map);
self
}
pub fn with_path(mut self, path: Option<&'a Path>) -> Self {
self.path = path;
self
}
pub fn with_fixed_implicit_activation(mut self, fixed: bool) -> Self {
self.fixed_implicit_activation = fixed;
self
}
}
#[derive(Clone)]
pub struct IrEquivRequest<'a> {
pub lhs: IrModule<'a>,
pub rhs: IrModule<'a>,
pub drop_params: &'a [String],
pub flatten_aggregates: bool,
pub parallelism: EquivParallelism,
pub assertion_semantics: AssertionSemantics,
pub assert_label_filter: Option<&'a str>,
pub solver: Option<SolverChoice>,
pub solver_limits: SolverLimits,
pub tool_path: Option<&'a Path>,
}
impl<'a> IrEquivRequest<'a> {
pub fn new(lhs: IrModule<'a>, rhs: IrModule<'a>) -> Self {
Self {
lhs,
rhs,
drop_params: &[],
flatten_aggregates: false,
parallelism: EquivParallelism::SingleThreaded,
assertion_semantics: AssertionSemantics::Ignore,
assert_label_filter: None,
solver: None,
solver_limits: SolverLimits::default(),
tool_path: None,
}
}
pub fn with_drop_params(mut self, drop_params: &'a [String]) -> Self {
self.drop_params = drop_params;
self
}
pub fn with_flatten_aggregates(mut self, flatten: bool) -> Self {
self.flatten_aggregates = flatten;
self
}
pub fn with_parallelism(mut self, parallelism: EquivParallelism) -> Self {
self.parallelism = parallelism;
self
}
pub fn with_assertion_semantics(mut self, semantics: AssertionSemantics) -> Self {
self.assertion_semantics = semantics;
self
}
pub fn with_assert_label_filter(mut self, filter: Option<&'a str>) -> Self {
self.assert_label_filter = filter;
self
}
pub fn with_solver(mut self, solver: Option<SolverChoice>) -> Self {
self.solver = solver;
self
}
pub fn with_solver_limits(mut self, solver_limits: SolverLimits) -> Self {
self.solver_limits = solver_limits;
self
}
pub fn with_tool_path(mut self, tool_path: Option<&'a Path>) -> Self {
self.tool_path = tool_path;
self
}
}
pub fn run_ir_equiv(request: &IrEquivRequest<'_>) -> Result<EquivReport, String> {
let choice = request.solver.unwrap_or(SolverChoice::Bitwuzla);
let prover = prover_for_choice_with_limits(choice, request.tool_path, request.solver_limits);
let (lhs_pkg, lhs_fn_dropped) = ir_utils::parse_package_and_drop_params(
request.lhs.source,
request.lhs.top,
request.drop_params,
)?;
let (rhs_pkg, rhs_fn_dropped) = ir_utils::parse_package_and_drop_params(
request.rhs.source,
request.rhs.top,
request.drop_params,
)?;
let assert_label_filter = request.assert_label_filter;
let lhs_side = ProverFn::new(&lhs_fn_dropped, Some(&lhs_pkg))
.with_fixed_implicit_activation(request.lhs.fixed_implicit_activation)
.with_domains(request.lhs.param_domains.map(|d| d.clone()))
.with_uf_map(request.lhs.uf_map.clone().into_owned());
let rhs_side = ProverFn::new(&rhs_fn_dropped, Some(&rhs_pkg))
.with_fixed_implicit_activation(request.rhs.fixed_implicit_activation)
.with_domains(request.rhs.param_domains.map(|d| d.clone()))
.with_uf_map(request.rhs.uf_map.clone().into_owned());
let start_time = Instant::now();
let result = prover.prove_ir_equiv(
&lhs_side,
&rhs_side,
request.parallelism,
request.assertion_semantics,
assert_label_filter,
request.flatten_aggregates,
);
let duration = start_time.elapsed();
match result {
EquivResult::Error(msg) => Err(msg),
other => Ok(EquivReport {
duration,
result: other,
}),
}
}