Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8a93aae
add: File horizon that implements the horizon extraction when the str…
danielkocher Jan 9, 2023
c3cd965
add: Stride option
danielkocher Jan 9, 2023
f70de50
feat: Exponential search when the stride option is enabled (up to a m…
danielkocher Jan 9, 2023
1cf0b8c
fix: Remove Clone from Node type
danielkocher Jan 12, 2023
29efb58
fix: Use absolute depth during unrolling and simplify print_reasoning…
danielkocher Jan 12, 2023
127d2a9
feat: adds --one-query flag
Jan 20, 2023
a20b44a
feat: --one-query flag implemented for sat solvers
Jan 20, 2023
cdc6d11
fix: tiny fix sat_solvers
Jan 20, 2023
66fd804
feat: --one-query implemented for smt solvers
Jan 20, 2023
9ebe416
fix: add Node::or handle for smt solvers
Jan 20, 2023
5f7d495
fix: Node::Bad is now reachable in solvers
Jan 20, 2023
53e5203
fix: --one-query does not checks on bad states sequential
smml1996 Jan 22, 2023
c0757df
refactor: cargo fmt
smml1996 Jan 22, 2023
920c499
chore: add assertion for minimize when --one-query flag is used
smml1996 Jan 22, 2023
f892b6e
chore: Merge feat-one-query into feat/exp-search WIP
danielkocher Jan 23, 2023
3088960
chore: Resolve merge conflict
danielkocher Jan 23, 2023
9d798de
chore: Resolve merge conflict
danielkocher Jan 24, 2023
8c23cf0
chore: Resolve merge conflict
danielkocher Jan 24, 2023
fa39d57
feat: Draft of reasoning horizon for a give time budget in ms (exp. s…
danielkocher Jan 24, 2023
992b02b
fix: Quick fix that respect the stride option when the SMT solver is …
danielkocher Jan 24, 2023
ab2ef8f
iter: Fix reasoning horizon functionality (deal with updated order of…
danielkocher Mar 27, 2023
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
7 changes: 7 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,13 @@ pub fn args() -> Command {
.allow_hyphen_values(true)
.num_args(1..)
)
.arg(
Arg::new("stride")
.help("Find unroll level where SMT solver times out")
.short('l')
.long("stride")
.num_args(0)
)
)
.subcommand(
Command::new("qubot")
Expand Down
76 changes: 52 additions & 24 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::unicorn::sat_solver::solve_bad_states;
use crate::unicorn::smt_solver::*;
use crate::unicorn::unroller::{prune_model, renumber_model, unroll_model};
use crate::unicorn::write_model;
use crate::unicorn::horizon::print_reasoning_horizon;

use ::unicorn::disassemble::disassemble;
use ::unicorn::emulate::EmulatorState;
Expand All @@ -33,6 +34,7 @@ use std::{
path::PathBuf,
str::FromStr,
time::Duration,
cmp::min
};

fn main() -> Result<()> {
Expand Down Expand Up @@ -85,6 +87,7 @@ fn main() -> Result<()> {
let input_is_dimacs = !is_beator && args.get_flag("from-dimacs");
let compile_model = is_beator && args.get_flag("compile");
let emulate_model = is_beator && args.get_flag("emulate");
let stride = args.get_flag("stride");
let arg0 = expect_arg::<String>(args, "input-file")?;
let extras = collect_arg_values(args, "extras");

Expand Down Expand Up @@ -112,32 +115,57 @@ fn main() -> Result<()> {
} else {
vec![]
};
for n in 0..unroll_depth {
unroll_model(&mut model, n);
if has_concrete_inputs {
optimize_model_with_input(&mut model, &mut input_values)
}
}
if prune {
prune_model(&mut model);
}

let timeout = solver_timeout.map(|&ms| Duration::from_millis(ms));
match smt_solver {
#[rustfmt::skip]
SmtType::Generic => {
optimize_model_with_solver::<none_impl::NoneSolver>(&mut model, timeout, minimize)
},
#[rustfmt::skip]
#[cfg(feature = "boolector")]
SmtType::Boolector => {
optimize_model_with_solver::<boolector_impl::BoolectorSolver>(&mut model, timeout, minimize)
},
#[rustfmt::skip]
#[cfg(feature = "z3")]
SmtType::Z3 => {
optimize_model_with_solver::<z3solver_impl::Z3SolverWrapper>(&mut model, timeout, minimize)
},

let mut n: usize = if stride { 1 } else { unroll_depth };
loop {
// TODO: Maybe we can get rid of this clone for each
// iteration, which is basically required if pruning is
// enabled. However, it is much faster this way than
// without pruning and not cloning the model.
let mut model_copy = model.clone();

for m in 0..n {
unroll_model(&mut model_copy, m);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second parameter to unroll_model (i.e. the m) is only used to construct the names of bad-state nodes and input nodes in the current unrolling step. Would it make the algorithm simpler if we were to pass the correct absolute depth at this point already? I think this could make print_reasoning_horizon simpler.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good pointer, thanks.
I adapted the implementation accordingly and print_reasoning_horizon did simplify significantly (as expected).


if has_concrete_inputs {
optimize_model_with_input(&mut model_copy, &mut input_values)
}
}

if prune {
prune_model(&mut model_copy);
}

match smt_solver {
#[rustfmt::skip]
SmtType::Generic => {
optimize_model_with_solver::<none_impl::NoneSolver>(&mut model_copy, timeout, minimize)
},
#[rustfmt::skip]
#[cfg(feature = "boolector")]
SmtType::Boolector => {
optimize_model_with_solver::<boolector_impl::BoolectorSolver>(&mut model_copy, timeout, minimize)
},
#[rustfmt::skip]
#[cfg(feature = "z3")]
SmtType::Z3 => {
optimize_model_with_solver::<z3solver_impl::Z3SolverWrapper>(&mut model_copy, timeout, minimize)
},
}

if !stride || !model_copy.bad_states_initial.is_empty() {
if !model_copy.bad_states_initial.is_empty() {
print_reasoning_horizon(&mut model_copy, n, stride);
}

break;
}

n = min(2 * n, unroll_depth);
}

if renumber {
renumber_model(&mut model);
}
Expand Down
26 changes: 26 additions & 0 deletions src/unicorn/horizon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use crate::unicorn::{Node, Model};
use log::warn;

//
// Public Interface
//

pub fn print_reasoning_horizon(model: &mut Model, depth: usize, stride: bool) {
let v: Option<String>;
v = match &*model.bad_states_initial[0].borrow() {
Node::Bad { name, ..} => name.clone(),
_ => None
};

let ss = v.as_ref().expect("Bad state must have an unrolling depth");
if let (Some(start), Some(end)) = (ss.find("[n="), ss.find("]")) {
if let (reason, Ok(remainder)) = (ss[..start].to_string(), ss[start+"[n=".len()..end].to_string().parse::<usize>()) {
warn!(
"(Initial) Bad state '{}[n={:#?}]' is satisfiable.",
reason,
if stride { (depth - 1) + remainder } else { remainder }
);
}

}
}
5 changes: 3 additions & 2 deletions src/unicorn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,12 @@ pub mod qubot;
pub mod sat_solver;
pub mod smt_solver;
pub mod unroller;
pub mod horizon;

pub type Nid = u64;
pub type NodeRef = Rc<RefCell<Node>>;

#[derive(Debug)]
#[derive(Clone,Debug)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that we need to clone Model for now. But from what I can tell we are not cloning Node objects. I might very well be missing something. Could you double-check whether deriving Clone on Node is still necessary here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, this is a leftover that I will fix - thanks!

pub enum Node {
Const {
nid: Nid,
Expand Down Expand Up @@ -176,7 +177,7 @@ pub fn get_nodetype(n: usize) -> NodeType {
}
}

#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Model {
pub lines: Vec<NodeRef>,
pub sequentials: Vec<NodeRef>,
Expand Down