ask-dracula-rs/src/main.rs

192 lines
5.6 KiB
Rust
Raw Normal View History

2019-11-06 19:52:08 +01:00
fn find_conjecture<'a>(project: &'a ask_dracula::Project,
2019-11-07 05:42:42 +01:00
proof_direction: ask_dracula::project::ProofDirection)
2019-11-06 19:52:08 +01:00
-> Option<&'a ask_dracula::project::Statement>
{
for block in &project.blocks
{
if let ask_dracula::project::Block::Statement(ref statement) = block
{
2019-11-07 04:20:06 +01:00
if ask_dracula::format_tptp::is_statement_kind_conjecture(&statement.kind, proof_direction)
{
return Some(statement)
}
}
}
None
}
2019-11-06 19:52:08 +01:00
fn find_conjecture_mut<'a>(project: &'a mut ask_dracula::Project,
2019-11-07 05:42:42 +01:00
proof_direction: ask_dracula::project::ProofDirection)
2019-11-06 19:52:08 +01:00
-> Option<&'a mut ask_dracula::project::Statement>
{
for block in &mut project.blocks
{
if let ask_dracula::project::Block::Statement(ref mut statement) = block
{
2019-11-07 04:20:06 +01:00
if ask_dracula::format_tptp::is_statement_kind_conjecture(&statement.kind, proof_direction)
{
return Some(statement)
}
}
}
None
}
enum ProofResult
{
ProofNotFound,
Refutation,
Satisfiable,
}
fn run_vampire<I, S>(input: &str, arguments: Option<I>)
2019-11-07 02:05:15 +01:00
-> Result<(ProofResult, Option<f32>), ask_dracula::Error>
where I: IntoIterator<Item = S>, S: AsRef<std::ffi::OsStr>
{
let mut vampire = std::process::Command::new("vampire");
let vampire = match arguments
{
Some(arguments) => vampire.args(arguments),
None => &mut vampire,
};
//eprintln!("{}", input);
let mut vampire = vampire
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.map_err(|error| ask_dracula::Error::new_run_vampire(error))?;
{
use std::io::Write;
let vampire_stdin = vampire.stdin.as_mut().unwrap();
vampire_stdin.write_all(input.as_bytes())
.map_err(|error| ask_dracula::Error::new_run_vampire(error))?;
}
let output = vampire.wait_with_output()
.map_err(|error| ask_dracula::Error::new_run_vampire(error))?;
let stdout = std::str::from_utf8(&output.stdout)
.map_err(|error| ask_dracula::Error::new_run_vampire(error))?;
let stderr = std::str::from_utf8(&output.stderr)
.map_err(|error| ask_dracula::Error::new_run_vampire(error))?;
if !output.status.success()
{
let proof_not_found_regex = regex::Regex::new(r"% \(\d+\)Proof not found in time").unwrap();
if proof_not_found_regex.is_match(stdout)
{
2019-11-07 02:05:15 +01:00
return Ok((ProofResult::ProofNotFound, None));
}
return Err(ask_dracula::Error::new_run_vampire(
2019-11-02 07:54:39 +01:00
format!("Vampire returned unsuccessful exit code ({})\n\n======== stdout ========\n{}\n\n======== stderr ========\n{}", output.status, std::str::from_utf8(&output.stdout).unwrap_or("(not valid UTF-8)").trim(), std::str::from_utf8(&output.stderr).unwrap_or("(not valid UTF-8)").trim())));
}
2019-11-07 02:05:15 +01:00
let proof_time_regex = regex::Regex::new(r"% \(\d+\)Success in time (\d+(?:\.\d+)?) s").unwrap();
let proof_time = proof_time_regex.captures(stdout)
.map(|captures| captures.get(1).unwrap().as_str().parse::<f32>().ok())
.unwrap_or(None);
let refutation_regex = regex::Regex::new(r"% \(\d+\)Termination reason: Refutation").unwrap();
if refutation_regex.is_match(stdout)
{
2019-11-07 02:05:15 +01:00
return Ok((ProofResult::Refutation, proof_time));
}
Err(ask_dracula::Error::new_interpret_vampire_output(stdout.to_string(), stderr.to_string()))
}
2019-11-02 02:13:45 +01:00
fn main() -> Result<(), Box<dyn std::error::Error>>
{
let matches = clap::App::new("Ask Dracula: Using Vampire as an interactive theorem prover")
.arg(clap::Arg::with_name("file").takes_value(true).required(true))
2019-11-06 19:52:08 +01:00
.arg(clap::Arg::with_name("proof-direction").long("proof-direction").takes_value(true).default_value("forward"))
.arg(clap::Arg::with_name("vampire_arguments").multiple(true))
.after_help("example: ask_dracula <project file> -- --mode casc --cores 8")
2019-11-02 02:13:45 +01:00
.get_matches();
let file = matches.value_of("file").unwrap().to_string();
let file_path = std::path::Path::new(&file);
let file_content = std::fs::read_to_string(&file_path)?;
let (_, mut project) = ask_dracula::parse::project(&file_content)
2019-11-02 02:13:45 +01:00
.map_err(|_| "couldnt parse input file")?;
2019-11-06 19:52:08 +01:00
let proof_directions = match matches.value_of("proof-direction").unwrap()
{
2019-11-07 05:42:42 +01:00
"forward" => vec![ask_dracula::project::ProofDirection::Forward],
"backward" => vec![ask_dracula::project::ProofDirection::Backward],
"both" => vec![ask_dracula::project::ProofDirection::Forward, ask_dracula::project::ProofDirection::Backward],
2019-11-06 19:52:08 +01:00
proof_direction => panic!("unrecognized proof direction “{}", proof_direction),
};
2019-11-06 19:52:08 +01:00
for proof_direction in proof_directions
{
loop
{
2019-11-06 19:52:08 +01:00
let conjecture = find_conjecture(&project, proof_direction);
2019-11-07 02:05:15 +01:00
let (vampire_result, proof_time) = match conjecture
{
2019-11-06 19:52:08 +01:00
None =>
{
eprintln!("nothing to prove, exiting");
return Ok(());
},
Some(ref conjecture) =>
{
2019-11-07 05:43:22 +01:00
eprintln!("verifying {}: {}", &conjecture.kind, conjecture.formula);
2019-11-06 19:52:08 +01:00
let tptp_content = format!("{}", ask_dracula::format_tptp::display_project_with_conjecture_tptp(&project, conjecture, proof_direction));
2019-11-06 19:52:08 +01:00
run_vampire(&tptp_content, matches.values_of("vampire_arguments").map(|value| value))?
},
};
2019-11-06 19:52:08 +01:00
let conjecture = find_conjecture_mut(&mut project, proof_direction).unwrap();
2019-11-06 19:52:08 +01:00
match vampire_result
{
2019-11-06 19:52:08 +01:00
ProofResult::ProofNotFound =>
{
println!("proof not found");
return Ok(());
},
ProofResult::Refutation =>
{
2019-11-07 02:05:15 +01:00
if let Some(proof_time) = proof_time
{
2019-11-07 05:43:22 +01:00
println!("{} proven in {} seconds", &conjecture.kind, proof_time);
2019-11-07 02:05:15 +01:00
}
else
{
println!("assertion proven");
}
2019-11-06 19:52:08 +01:00
conjecture.kind = ask_dracula::project::StatementKind::Axiom;
conjecture.original_text = replace_statement_kind_regex.replace(&conjecture.original_text, "axiom").to_string();
},
ProofResult::Satisfiable =>
{
println!("assertion disproven");
return Ok(());
},
}
}
}
2019-11-06 19:52:08 +01:00
Ok(())
2019-11-02 02:13:45 +01:00
}