Skip to content

Commit

Permalink
add split conjunction heper function
Browse files Browse the repository at this point in the history
  • Loading branch information
ekiwi committed Aug 19, 2024
1 parent d6c2b31 commit 77c8ae3
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 15 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ edition = "2021"
[dependencies]
patronus = "0.18.0"
clap = { version = "4.5.14", features = ["derive"] }
smallvec = { version = "1.13.2", features = ["union"] }
110 changes: 95 additions & 15 deletions src/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
//
// Random testing strategy to finding counter examples.

use patronus::ir::{
cone_of_influence, cone_of_influence_comb, cone_of_influence_init, Context, ExprRef, GetNode,
SerializableIrNode, TransitionSystem, TypeCheck,
};
use patronus::sim;
use patronus::ir::*;
use patronus::mc::Simulator;
use patronus::sim::interpreter::{InitKind, Interpreter};
use smallvec::{smallvec, SmallVec};

#[derive(Debug, Copy, Clone)]
pub struct RandomOptions {
Expand All @@ -29,7 +28,10 @@ pub fn random_testing(
opts: RandomOptions,
) -> RandomResult {
let sim_ctx = ctx.clone();
let mut sim = sim::interpreter::Interpreter::new(&sim_ctx, &sys);
let mut sim = Interpreter::new(&sim_ctx, &sys);

// we initialize all states to zero, since most bugs are not reset initialization bugs
sim.init(InitKind::Zero);

// // show all inputs
// let inputs = sys.get_signals(|s| s.is_input());
Expand Down Expand Up @@ -58,6 +60,8 @@ pub fn random_testing(
RandomResult::None
}

/// randomize all inputs
struct Constraints {
/// Single input constraints can be checked when we are sampling the input.
/// The tuple is (constraint ref, input ref)
Expand All @@ -68,16 +72,23 @@ struct Constraints {
others: Vec<ExprRef>,
}

type ExprRefVec = SmallVec<[ExprRef; 4]>;

/// A number of constraints that connect several inputs/states together.
#[derive(Debug, Clone)]
struct Constraint {
expr: ExprRef,
inputs: Vec<ExprRef>,
states: Vec<ExprRef>,
struct ConstraintCluster {
exprs: ExprRefVec,
inputs: ExprRefVec,
states: ExprRefVec,
}

/// Check to see which constraints we can fulfill
fn analyze_constraints(ctx: &Context, sys: &TransitionSystem, init: bool) -> Vec<Constraint> {
let states = sys.state_map();
fn analyze_constraints(
ctx: &Context,
sys: &TransitionSystem,
init: bool,
) -> Vec<ConstraintCluster> {
let state_map = sys.state_map();
let mut out = Vec::new();
// we want to see which constraints depends on which inputs
for (expr_ref, info) in sys.constraints() {
Expand All @@ -87,13 +98,82 @@ fn analyze_constraints(ctx: &Context, sys: &TransitionSystem, init: bool) -> Vec
} else {
cone_of_influence_comb(ctx, sys, expr_ref)
};
let (states, inputs) = cone.iter().partition(|e| states.contains_key(e));
let constraint = Constraint {
expr: expr_ref,
let (states, inputs) = cone.into_iter().partition(|e| state_map.contains_key(e));
let constraint = ConstraintCluster {
exprs: smallvec![expr_ref],
inputs,
states,
};
out.push(constraint);
}
out
}

fn split_conjunction(ctx: &mut Context, e: ExprRef) -> ExprRefVec {
let mut out = smallvec![];
let mut todo: ExprRefVec = smallvec![e];
while let Some(e) = todo.pop() {
match ctx.get(e) {
Expr::BVAnd(a, b, 1) => {
todo.push(*b);
todo.push(*a);
}
Expr::BVNot(e2, 1) => match *ctx.get(*e2) {
Expr::BVOr(a, b, 1) => {
todo.push(ctx.not(b));
todo.push(ctx.not(a));
}
_ => out.push(e),
},
_ => out.push(e),
}
}
out
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn type_size() {
// one ExprRef is 1/2 a pointer, thus 4 ExprRef fit into two pointer sized memory slots
assert_eq!(std::mem::size_of::<ExprRef>(), 4);
// we scale the ExprRefVec to be the same size on stack as a Vec<ExprRef>
assert_eq!(
std::mem::size_of::<ExprRefVec>(),
std::mem::size_of::<Vec<ExprRef>>()
);
}

#[test]
fn test_split_conjunction() {
let mut ctx = Context::default();
let a = ctx.bv_symbol("a", 1);
let b = ctx.bv_symbol("b", 1);
let c = ctx.bv_symbol("b", 1);
assert_eq!(split_conjunction(&mut ctx, a), [a].into());
let a_and_b = ctx.and(a, b);
assert_eq!(split_conjunction(&mut ctx, a_and_b), [a, b].into());
let a_and_b_and_c_1 = ctx.and(a_and_b, c);
assert_eq!(
split_conjunction(&mut ctx, a_and_b_and_c_1),
[a, b, c].into()
);
let b_and_c = ctx.and(b, c);
let a_and_b_and_c_2 = ctx.and(a, b_and_c);
assert_eq!(
split_conjunction(&mut ctx, a_and_b_and_c_2),
[a, b, c].into()
);
let a_or_b = ctx.or(a, b);
assert_eq!(split_conjunction(&mut ctx, a_or_b), [a_or_b].into());
let not_a_or_b = ctx.not(a_or_b);
let not_a = ctx.not(a);
let not_b = ctx.not(b);
assert_eq!(
split_conjunction(&mut ctx, not_a_or_b),
[not_a, not_b].into()
);
}
}

0 comments on commit 77c8ae3

Please sign in to comment.