2020-05-11 03:46:11 +02:00
|
|
|
|
mod proof_direction;
|
2020-05-11 03:11:10 +02:00
|
|
|
|
mod section_kind;
|
2020-05-13 03:16:51 +02:00
|
|
|
|
mod statement;
|
2020-05-11 03:11:10 +02:00
|
|
|
|
|
2020-05-11 03:46:11 +02:00
|
|
|
|
pub use proof_direction::ProofDirection;
|
2020-05-13 03:16:51 +02:00
|
|
|
|
pub(crate) use section_kind::SectionKind;
|
|
|
|
|
pub(crate) use statement::{ProofStatus, Statement, StatementKind};
|
2020-05-05 19:40:57 +02:00
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
use foliage::flavor::{FunctionDeclaration as _, PredicateDeclaration as _};
|
|
|
|
|
|
2020-05-06 21:38:48 +02:00
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
2020-05-05 19:40:57 +02:00
|
|
|
|
pub enum ProofResult
|
|
|
|
|
{
|
|
|
|
|
Proven,
|
|
|
|
|
NotProven,
|
|
|
|
|
Disproven,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Problem
|
|
|
|
|
{
|
2020-05-22 02:25:00 +02:00
|
|
|
|
function_declarations: std::cell::RefCell<crate::FunctionDeclarations>,
|
|
|
|
|
pub predicate_declarations: std::cell::RefCell<crate::PredicateDeclarations>,
|
2020-05-05 19:40:57 +02:00
|
|
|
|
|
|
|
|
|
statements: std::cell::RefCell<std::collections::BTreeMap<SectionKind, Vec<Statement>>>,
|
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
shell: std::cell::RefCell<crate::output::Shell>,
|
2020-05-05 19:40:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Problem
|
|
|
|
|
{
|
2020-05-22 19:33:06 +02:00
|
|
|
|
pub fn new(color_choice: crate::output::ColorChoice) -> Self
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
|
|
|
|
Self
|
|
|
|
|
{
|
2020-05-22 02:25:00 +02:00
|
|
|
|
function_declarations: std::cell::RefCell::new(crate::FunctionDeclarations::new()),
|
|
|
|
|
predicate_declarations: std::cell::RefCell::new(crate::PredicateDeclarations::new()),
|
2020-05-05 19:40:57 +02:00
|
|
|
|
|
|
|
|
|
statements: std::cell::RefCell::new(std::collections::BTreeMap::new()),
|
|
|
|
|
|
2020-05-22 19:33:06 +02:00
|
|
|
|
shell: std::cell::RefCell::new(crate::output::Shell::from_stdout(color_choice)),
|
2020-05-05 19:40:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 18:14:56 +02:00
|
|
|
|
pub(crate) fn add_statement(&self, section_kind: SectionKind, statement: Statement)
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
|
|
|
|
let mut statements = self.statements.borrow_mut();
|
|
|
|
|
let section = statements.entry(section_kind).or_insert(vec![]);
|
|
|
|
|
|
|
|
|
|
section.push(statement);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 04:54:42 +02:00
|
|
|
|
pub(crate) fn check_consistency(&self, proof_direction: ProofDirection)
|
2020-05-18 02:17:30 +02:00
|
|
|
|
-> Result<(), crate::Error>
|
|
|
|
|
{
|
2020-05-29 17:42:05 +02:00
|
|
|
|
for (_, statements) in self.statements.borrow().iter()
|
|
|
|
|
{
|
|
|
|
|
for statement in statements
|
|
|
|
|
{
|
|
|
|
|
match statement.kind
|
|
|
|
|
{
|
|
|
|
|
crate::problem::StatementKind::Assumption => (),
|
|
|
|
|
_ => continue,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(predicate_declaration) =
|
|
|
|
|
crate::fold_predicates(&statement.formula, None,
|
|
|
|
|
&mut |accumulator, predicate: &crate::Predicate|
|
|
|
|
|
{
|
|
|
|
|
match accumulator
|
|
|
|
|
{
|
|
|
|
|
None if !*predicate.declaration.is_input.borrow() =>
|
|
|
|
|
Some(std::rc::Rc::clone(&predicate.declaration)),
|
|
|
|
|
_ => accumulator,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
return Err(crate::Error::new_noninput_predicate_in_assumption(
|
|
|
|
|
predicate_declaration));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 07:06:01 +02:00
|
|
|
|
for predicate_declaration in self.predicate_declarations.borrow().iter()
|
2020-05-18 02:17:30 +02:00
|
|
|
|
{
|
2020-05-28 04:54:42 +02:00
|
|
|
|
if predicate_declaration.is_built_in()
|
2020-05-18 02:17:30 +02:00
|
|
|
|
{
|
2020-05-28 04:54:42 +02:00
|
|
|
|
log::warn!("specification uses built-in predicate {}",
|
|
|
|
|
predicate_declaration.declaration);
|
2020-05-18 02:17:30 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-28 06:29:57 +02:00
|
|
|
|
if *predicate_declaration.is_input.borrow()
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-29 14:57:00 +02:00
|
|
|
|
// For a backward proof, the program must be tight and free of negative recursion
|
2020-05-28 18:37:34 +02:00
|
|
|
|
if proof_direction.requires_backward_proof()
|
2020-05-28 04:54:42 +02:00
|
|
|
|
{
|
2020-05-29 14:57:00 +02:00
|
|
|
|
if predicate_declaration.has_positive_dependency_cycle()
|
|
|
|
|
{
|
|
|
|
|
return Err(crate::Error::new_program_not_tight(
|
|
|
|
|
std::rc::Rc::clone(&predicate_declaration)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if predicate_declaration.has_private_dependency_cycle()
|
|
|
|
|
{
|
|
|
|
|
return Err(crate::Error::new_private_predicate_cycle(
|
|
|
|
|
std::rc::Rc::clone(&predicate_declaration)));
|
|
|
|
|
}
|
2020-05-28 04:54:42 +02:00
|
|
|
|
}
|
2020-05-28 07:27:29 +02:00
|
|
|
|
|
|
|
|
|
if predicate_declaration.is_public()
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (_, statements) in self.statements.borrow().iter()
|
|
|
|
|
{
|
|
|
|
|
for statement in statements
|
|
|
|
|
{
|
|
|
|
|
match statement.kind
|
|
|
|
|
{
|
2020-05-28 18:37:56 +02:00
|
|
|
|
crate::problem::StatementKind::Spec => (),
|
|
|
|
|
_ => continue,
|
2020-05-28 07:27:29 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if crate::formula_contains_predicate(&statement.formula, predicate_declaration)
|
|
|
|
|
{
|
|
|
|
|
return Err(crate::Error::new_private_predicate_in_specification(
|
|
|
|
|
std::rc::Rc::clone(predicate_declaration)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-13 07:41:01 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 18:14:56 +02:00
|
|
|
|
pub fn simplify(&mut self) -> Result<(), crate::Error>
|
|
|
|
|
{
|
|
|
|
|
let mut statements = self.statements.borrow_mut();
|
|
|
|
|
|
|
|
|
|
for (_, statements) in statements.iter_mut()
|
|
|
|
|
{
|
|
|
|
|
for statement in statements.iter_mut()
|
|
|
|
|
{
|
|
|
|
|
match statement.kind
|
|
|
|
|
{
|
|
|
|
|
// Only simplify generated formulas
|
|
|
|
|
| StatementKind::CompletedDefinition(_)
|
|
|
|
|
| StatementKind::IntegrityConstraint =>
|
|
|
|
|
crate::simplify(&mut statement.formula)?,
|
|
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
fn print_step_title(&self, step_title: &str, color: &termcolor::ColorSpec)
|
2020-05-19 13:10:31 +02:00
|
|
|
|
-> Result<(), crate::Error>
|
2020-05-12 04:25:49 +02:00
|
|
|
|
{
|
|
|
|
|
let longest_possible_key = " Finished";
|
|
|
|
|
|
|
|
|
|
self.shell.borrow_mut().print(
|
|
|
|
|
&format!("{:>step_title_width$} ", step_title,
|
|
|
|
|
step_title_width = longest_possible_key.chars().count()),
|
2020-05-19 13:10:31 +02:00
|
|
|
|
color)?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
2020-05-12 04:25:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-11 03:46:11 +02:00
|
|
|
|
pub fn prove(&self, proof_direction: ProofDirection) -> Result<(), crate::Error>
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
2020-05-28 04:54:42 +02:00
|
|
|
|
if proof_direction.requires_forward_proof()
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
2020-05-12 04:25:49 +02:00
|
|
|
|
self.print_step_title("Started",
|
2020-05-19 13:10:31 +02:00
|
|
|
|
termcolor::ColorSpec::new().set_bold(true).set_fg(Some(termcolor::Color::Green)))?;
|
2020-05-22 18:34:59 +02:00
|
|
|
|
self.shell.borrow_mut().println(
|
|
|
|
|
&"verification of specification from translated program",
|
2020-05-19 13:10:31 +02:00
|
|
|
|
&termcolor::ColorSpec::new())?;
|
2020-05-05 19:40:57 +02:00
|
|
|
|
|
|
|
|
|
let mut statements = self.statements.borrow_mut();
|
|
|
|
|
|
|
|
|
|
// Initially reset all proof statuses
|
2020-05-11 03:11:10 +02:00
|
|
|
|
for (_, statements) in statements.iter_mut()
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
|
|
|
|
for statement in statements.iter_mut()
|
|
|
|
|
{
|
|
|
|
|
match statement.kind
|
|
|
|
|
{
|
|
|
|
|
StatementKind::Axiom
|
|
|
|
|
| StatementKind::Assumption
|
2020-05-13 02:24:13 +02:00
|
|
|
|
| StatementKind::CompletedDefinition(_)
|
|
|
|
|
| StatementKind::IntegrityConstraint =>
|
2020-05-11 03:11:10 +02:00
|
|
|
|
statement.proof_status = ProofStatus::AssumedProven,
|
2020-05-11 03:46:11 +02:00
|
|
|
|
StatementKind::Lemma(ProofDirection::Backward) =>
|
2020-05-07 17:19:42 +02:00
|
|
|
|
statement.proof_status = ProofStatus::Ignored,
|
2020-05-06 21:38:48 +02:00
|
|
|
|
_ => statement.proof_status = ProofStatus::ToProveLater,
|
2020-05-05 19:40:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drop(statements);
|
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
let proof_result = self.prove_unproven_statements()?;
|
2020-05-05 19:40:57 +02:00
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
let mut step_title_color = termcolor::ColorSpec::new();
|
|
|
|
|
step_title_color.set_bold(true);
|
|
|
|
|
|
|
|
|
|
match proof_result
|
|
|
|
|
{
|
|
|
|
|
ProofResult::Proven => step_title_color.set_fg(Some(termcolor::Color::Green)),
|
|
|
|
|
ProofResult::NotProven => step_title_color.set_fg(Some(termcolor::Color::Yellow)),
|
|
|
|
|
ProofResult::Disproven => step_title_color.set_fg(Some(termcolor::Color::Red)),
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-19 13:10:31 +02:00
|
|
|
|
self.print_step_title("Finished", &step_title_color)?;
|
2020-05-22 18:34:59 +02:00
|
|
|
|
println!("verification of specification from translated program");
|
2020-05-11 05:03:59 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if proof_direction == ProofDirection::Both
|
|
|
|
|
{
|
|
|
|
|
println!("");
|
2020-05-05 19:40:57 +02:00
|
|
|
|
}
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-28 04:54:42 +02:00
|
|
|
|
if proof_direction.requires_backward_proof()
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
2020-05-12 04:25:49 +02:00
|
|
|
|
self.print_step_title("Started",
|
2020-05-19 13:10:31 +02:00
|
|
|
|
termcolor::ColorSpec::new().set_bold(true).set_fg(Some(termcolor::Color::Green)))?;
|
2020-05-22 18:34:59 +02:00
|
|
|
|
self.shell.borrow_mut().println(
|
|
|
|
|
&"verification of translated program from specification",
|
2020-05-19 13:10:31 +02:00
|
|
|
|
&termcolor::ColorSpec::new())?;
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
|
|
|
|
let mut statements = self.statements.borrow_mut();
|
|
|
|
|
|
|
|
|
|
// Initially reset all proof statuses
|
2020-05-11 03:11:10 +02:00
|
|
|
|
for (_, statements) in statements.iter_mut()
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
|
|
|
|
for statement in statements.iter_mut()
|
|
|
|
|
{
|
|
|
|
|
match statement.kind
|
|
|
|
|
{
|
|
|
|
|
StatementKind::Axiom
|
2020-05-07 02:53:48 +02:00
|
|
|
|
| StatementKind::Assumption
|
2020-05-22 18:34:59 +02:00
|
|
|
|
| StatementKind::Spec =>
|
2020-05-11 03:11:10 +02:00
|
|
|
|
statement.proof_status = ProofStatus::AssumedProven,
|
2020-05-11 03:46:11 +02:00
|
|
|
|
StatementKind::Lemma(ProofDirection::Forward) =>
|
2020-05-07 17:19:42 +02:00
|
|
|
|
statement.proof_status = ProofStatus::Ignored,
|
2020-05-28 06:30:35 +02:00
|
|
|
|
StatementKind::CompletedDefinition(ref predicate_declaration)
|
|
|
|
|
if !predicate_declaration.is_public() =>
|
|
|
|
|
statement.proof_status = ProofStatus::AssumedProven,
|
2020-05-06 21:38:48 +02:00
|
|
|
|
_ => statement.proof_status = ProofStatus::ToProveLater,
|
2020-05-06 00:13:43 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drop(statements);
|
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
let proof_result = self.prove_unproven_statements()?;
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
let mut step_title_color = termcolor::ColorSpec::new();
|
|
|
|
|
step_title_color.set_bold(true);
|
|
|
|
|
|
|
|
|
|
match proof_result
|
|
|
|
|
{
|
|
|
|
|
ProofResult::Proven => step_title_color.set_fg(Some(termcolor::Color::Green)),
|
|
|
|
|
ProofResult::NotProven => step_title_color.set_fg(Some(termcolor::Color::Yellow)),
|
|
|
|
|
ProofResult::Disproven => step_title_color.set_fg(Some(termcolor::Color::Red)),
|
|
|
|
|
};
|
|
|
|
|
|
2020-05-19 13:10:31 +02:00
|
|
|
|
self.print_step_title("Finished", &step_title_color)?;
|
2020-05-22 18:34:59 +02:00
|
|
|
|
println!("verification of translated program from specification");
|
2020-05-06 00:13:43 +02:00
|
|
|
|
}
|
2020-05-06 21:38:48 +02:00
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn next_unproven_statement_do_mut<F, G>(&self, mut functor: F) -> Option<G>
|
|
|
|
|
where
|
2020-05-13 03:16:51 +02:00
|
|
|
|
F: FnMut(&mut Statement) -> G,
|
2020-05-06 21:38:48 +02:00
|
|
|
|
{
|
2020-05-19 12:56:21 +02:00
|
|
|
|
// TODO: properly ensure that statements are proven in the right order
|
2020-05-06 21:38:48 +02:00
|
|
|
|
for section in self.statements.borrow_mut().iter_mut()
|
|
|
|
|
{
|
|
|
|
|
for statement in section.1.iter_mut()
|
|
|
|
|
{
|
|
|
|
|
if statement.proof_status == ProofStatus::ToProveNow
|
|
|
|
|
|| statement.proof_status == ProofStatus::ToProveLater
|
|
|
|
|
{
|
2020-05-13 03:16:51 +02:00
|
|
|
|
return Some(functor(statement));
|
2020-05-06 21:38:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
None
|
2020-05-06 00:13:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
fn prove_unproven_statements(&self) -> Result<ProofResult, crate::Error>
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
2020-05-22 02:42:38 +02:00
|
|
|
|
let display_statement = |statement: &mut Statement| -> Result<(), crate::Error>
|
2020-05-11 03:11:10 +02:00
|
|
|
|
{
|
2020-05-11 05:03:59 +02:00
|
|
|
|
let step_title = match statement.proof_status
|
2020-05-11 03:11:10 +02:00
|
|
|
|
{
|
2020-05-18 01:19:00 +02:00
|
|
|
|
ProofStatus::AssumedProven => format!("Added"),
|
2020-05-12 04:25:49 +02:00
|
|
|
|
ProofStatus::Proven => format!("Verified"),
|
|
|
|
|
ProofStatus::NotProven
|
|
|
|
|
| ProofStatus::Disproven
|
|
|
|
|
| ProofStatus::ToProveNow => format!("Verifying"),
|
|
|
|
|
ProofStatus::ToProveLater => format!("Skipped"),
|
|
|
|
|
ProofStatus::Ignored => format!("Ignored"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut step_title_color = termcolor::ColorSpec::new();
|
|
|
|
|
step_title_color.set_bold(true);
|
|
|
|
|
|
|
|
|
|
match statement.proof_status
|
|
|
|
|
{
|
|
|
|
|
ProofStatus::AssumedProven
|
|
|
|
|
| ProofStatus::Proven => step_title_color.set_fg(Some(termcolor::Color::Green)),
|
|
|
|
|
ProofStatus::NotProven => step_title_color.set_fg(Some(termcolor::Color::Yellow)),
|
|
|
|
|
ProofStatus::Disproven => step_title_color.set_fg(Some(termcolor::Color::Red)),
|
|
|
|
|
_ => step_title_color.set_fg(Some(termcolor::Color::Cyan)),
|
2020-05-11 03:11:10 +02:00
|
|
|
|
};
|
|
|
|
|
|
2020-05-19 13:10:31 +02:00
|
|
|
|
self.print_step_title(&step_title, &step_title_color)?;
|
2020-05-12 04:25:49 +02:00
|
|
|
|
|
2020-05-13 03:16:51 +02:00
|
|
|
|
self.shell.borrow_mut().print(&format!("{}: ", statement.kind),
|
2020-05-19 13:10:31 +02:00
|
|
|
|
&termcolor::ColorSpec::new())?;
|
2020-05-11 05:03:59 +02:00
|
|
|
|
|
2020-05-22 18:14:56 +02:00
|
|
|
|
// TODO: only perform autonaming when necessary
|
|
|
|
|
crate::autoname_variables(&mut statement.formula);
|
2020-05-22 02:42:38 +02:00
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
print!("{}", statement.formula);
|
2020-05-19 13:10:31 +02:00
|
|
|
|
|
|
|
|
|
Ok(())
|
2020-05-11 03:11:10 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Show all statements that are assumed to be proven
|
2020-05-13 03:16:51 +02:00
|
|
|
|
for (_, statements) in self.statements.borrow_mut().iter_mut()
|
2020-05-11 03:11:10 +02:00
|
|
|
|
{
|
|
|
|
|
for statement in statements.iter_mut()
|
|
|
|
|
.filter(|statement| statement.proof_status == ProofStatus::AssumedProven)
|
|
|
|
|
{
|
2020-05-19 13:10:31 +02:00
|
|
|
|
display_statement(statement)?;
|
2020-05-12 04:25:49 +02:00
|
|
|
|
println!("");
|
2020-05-11 03:11:10 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 21:38:48 +02:00
|
|
|
|
loop
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
2020-05-06 21:38:48 +02:00
|
|
|
|
match self.next_unproven_statement_do_mut(
|
2020-05-19 13:10:31 +02:00
|
|
|
|
|statement| -> Result<(), crate::Error>
|
2020-05-06 21:38:48 +02:00
|
|
|
|
{
|
|
|
|
|
statement.proof_status = ProofStatus::ToProveNow;
|
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
print!("\x1b[s");
|
2020-05-19 13:10:31 +02:00
|
|
|
|
display_statement(statement)?;
|
2020-05-12 04:25:49 +02:00
|
|
|
|
print!("\x1b[u");
|
|
|
|
|
|
|
|
|
|
use std::io::Write as _;
|
2020-05-19 13:10:31 +02:00
|
|
|
|
std::io::stdout().flush()?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
2020-05-06 21:38:48 +02:00
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
Some(_) => (),
|
2020-05-11 03:11:10 +02:00
|
|
|
|
// If there are no more unproven statements left, we’re done
|
2020-05-06 21:38:48 +02:00
|
|
|
|
None => break,
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
let tptp_problem_to_prove_next_statement = format!("{}", self.display_tptp());
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-07 17:19:42 +02:00
|
|
|
|
log::trace!("TPTP program:\n{}", &tptp_problem_to_prove_next_statement);
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-06 21:38:48 +02:00
|
|
|
|
// TODO: make configurable again
|
|
|
|
|
let (proof_result, proof_time_seconds) =
|
|
|
|
|
run_vampire(&tptp_problem_to_prove_next_statement,
|
2020-05-28 18:41:47 +02:00
|
|
|
|
Some(&["--mode", "casc", "--cores", "4", "--time_limit", "300"]))?;
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
match self.next_unproven_statement_do_mut(
|
2020-05-19 13:10:31 +02:00
|
|
|
|
|statement| -> Result<(), crate::Error>
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
2020-05-12 04:25:49 +02:00
|
|
|
|
statement.proof_status = match proof_result
|
|
|
|
|
{
|
|
|
|
|
ProofResult::Proven => ProofStatus::Proven,
|
|
|
|
|
ProofResult::NotProven => ProofStatus::NotProven,
|
|
|
|
|
ProofResult::Disproven => ProofStatus::Disproven,
|
|
|
|
|
};
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
self.shell.borrow_mut().erase_line();
|
2020-05-06 21:38:48 +02:00
|
|
|
|
|
2020-05-19 13:10:31 +02:00
|
|
|
|
display_statement(statement)?;
|
2020-05-06 21:38:48 +02:00
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
match proof_result
|
|
|
|
|
{
|
|
|
|
|
ProofResult::Proven => (),
|
|
|
|
|
ProofResult::NotProven => print!(" (not proven)"),
|
|
|
|
|
ProofResult::Disproven => print!(" (disproven)"),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(proof_time_seconds) = proof_time_seconds
|
|
|
|
|
{
|
|
|
|
|
self.shell.borrow_mut().print(&format!(" in {} seconds", proof_time_seconds),
|
2020-05-19 13:10:31 +02:00
|
|
|
|
termcolor::ColorSpec::new().set_fg(Some(termcolor::Color::Black)).set_intense(true))?;
|
2020-05-12 04:25:49 +02:00
|
|
|
|
}
|
2020-05-19 13:10:31 +02:00
|
|
|
|
|
|
|
|
|
Ok(())
|
2020-05-12 04:25:49 +02:00
|
|
|
|
})
|
2020-05-06 21:38:48 +02:00
|
|
|
|
{
|
|
|
|
|
Some(_) => (),
|
2020-05-12 04:25:49 +02:00
|
|
|
|
None => unreachable!(),
|
2020-05-06 00:13:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-19 13:10:31 +02:00
|
|
|
|
self.shell.borrow_mut().println(&"", &termcolor::ColorSpec::new())?;
|
2020-05-12 04:25:49 +02:00
|
|
|
|
|
|
|
|
|
if proof_result != ProofResult::Proven
|
2020-05-06 21:38:48 +02:00
|
|
|
|
{
|
2020-05-12 04:25:49 +02:00
|
|
|
|
return Ok(proof_result);
|
2020-05-06 21:38:48 +02:00
|
|
|
|
}
|
2020-05-06 00:13:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 04:25:49 +02:00
|
|
|
|
Ok(ProofResult::Proven)
|
2020-05-05 19:40:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
fn display_tptp(&self) -> ProblemTPTPDisplay
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
2020-05-22 02:25:00 +02:00
|
|
|
|
ProblemTPTPDisplay(self)
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
struct ProblemTPTPDisplay<'p>(&'p Problem);
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
impl<'p> std::fmt::Display for ProblemTPTPDisplay<'p>
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result
|
|
|
|
|
{
|
|
|
|
|
let write_title = |formatter: &mut dyn std::fmt::Write, title, section_separator|
|
|
|
|
|
-> std::fmt::Result
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
|
|
|
|
write!(formatter, "{}{}", section_separator, "%".repeat(72))?;
|
|
|
|
|
write!(formatter, "\n% {}", title)?;
|
|
|
|
|
writeln!(formatter, "\n{}", "%".repeat(72))
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut section_separator = "";
|
|
|
|
|
|
|
|
|
|
write_title(formatter, "anthem types", section_separator)?;
|
|
|
|
|
section_separator = "\n";
|
|
|
|
|
|
|
|
|
|
let tptp_preamble_anthem_types
|
|
|
|
|
= include_str!("output/tptp/preamble_types.tptp").trim_end();
|
|
|
|
|
writeln!(formatter, "{}", tptp_preamble_anthem_types)?;
|
|
|
|
|
|
|
|
|
|
write_title(formatter, "anthem axioms", section_separator)?;
|
|
|
|
|
|
|
|
|
|
let tptp_preamble_anthem_types
|
|
|
|
|
= include_str!("output/tptp/preamble_axioms.tptp").trim_end();
|
|
|
|
|
writeln!(formatter, "{}", tptp_preamble_anthem_types)?;
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
if !self.0.predicate_declarations.borrow().is_empty()
|
|
|
|
|
|| !self.0.function_declarations.borrow().is_empty()
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
|
|
|
|
write_title(formatter, "types", section_separator)?;
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
if !self.0.predicate_declarations.borrow().is_empty()
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
|
|
|
|
writeln!(formatter, "% predicate types")?;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
for predicate_declaration in self.0.predicate_declarations.borrow().iter()
|
|
|
|
|
.filter(|x| !x.is_built_in())
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
|
|
|
|
writeln!(formatter, "tff(type, type, {}).",
|
|
|
|
|
crate::output::tptp::display_predicate_declaration(predicate_declaration))?;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
if !self.0.function_declarations.borrow().is_empty()
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
|
|
|
|
writeln!(formatter, "% function types")?;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
for function_declaration in self.0.function_declarations.borrow().iter()
|
|
|
|
|
.filter(|x| !x.is_built_in())
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
|
|
|
|
writeln!(formatter, "tff(type, type, {}).",
|
2020-05-22 02:25:00 +02:00
|
|
|
|
crate::output::tptp::display_function_declaration(function_declaration))?;
|
2020-05-06 00:13:43 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
let function_declarations = self.0.function_declarations.borrow();
|
|
|
|
|
let symbolic_constants = function_declarations.iter().filter(|x| !*x.is_input.borrow());
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
let mut last_symbolic_constant: Option<std::rc::Rc<crate::FunctionDeclaration>> = None;
|
2020-05-06 00:13:43 +02:00
|
|
|
|
|
2020-05-13 01:28:25 +02:00
|
|
|
|
// TODO: put in axioms section
|
2020-05-06 00:13:43 +02:00
|
|
|
|
for (i, symbolic_constant) in symbolic_constants.enumerate()
|
|
|
|
|
{
|
|
|
|
|
// Order axioms are only necessary with two or more symbolic constants
|
|
|
|
|
if i == 1
|
|
|
|
|
{
|
|
|
|
|
writeln!(formatter, "% axioms for order of symbolic constants")?;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
if symbolic_constant.arity() > 0
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
|
|
|
|
// TODO: refactor
|
|
|
|
|
unimplemented!("n-ary function declarations aren’t supported");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(last_symbolic_constant) = last_symbolic_constant
|
|
|
|
|
{
|
2020-05-22 02:25:00 +02:00
|
|
|
|
write!(formatter, "tff(symbolic_constant_order, axiom, p__less__(")?;
|
|
|
|
|
last_symbolic_constant.display_name(formatter)?;
|
|
|
|
|
write!(formatter, ", ")?;
|
|
|
|
|
symbolic_constant.display_name(formatter)?;
|
|
|
|
|
writeln!(formatter, ")).")?;
|
2020-05-06 00:13:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
last_symbolic_constant = Some(std::rc::Rc::clone(symbolic_constant));
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:42:38 +02:00
|
|
|
|
for (section_kind, statements) in self.0.statements.borrow_mut().iter_mut()
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
|
|
|
|
if statements.is_empty()
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 18:34:59 +02:00
|
|
|
|
// TODO: refactor
|
2020-05-06 00:13:43 +02:00
|
|
|
|
let title = match section_kind
|
|
|
|
|
{
|
|
|
|
|
SectionKind::CompletedDefinitions => "completed definitions",
|
|
|
|
|
SectionKind::IntegrityConstraints => "integrity constraints",
|
|
|
|
|
SectionKind::Axioms => "axioms",
|
|
|
|
|
SectionKind::Assumptions => "assumptions",
|
|
|
|
|
SectionKind::Lemmas => "lemmas",
|
2020-05-22 18:34:59 +02:00
|
|
|
|
SectionKind::Specs => "specs",
|
2020-05-06 00:13:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
write_title(formatter, title, section_separator)?;
|
|
|
|
|
section_separator = "\n";
|
|
|
|
|
|
|
|
|
|
let mut i = 0;
|
|
|
|
|
|
2020-05-22 02:42:38 +02:00
|
|
|
|
for statement in statements.iter_mut()
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
2020-05-13 03:16:51 +02:00
|
|
|
|
if let StatementKind::CompletedDefinition(_) = statement.kind
|
2020-05-06 00:13:43 +02:00
|
|
|
|
{
|
2020-05-13 03:16:51 +02:00
|
|
|
|
writeln!(formatter, "% {}", statement.kind)?;
|
2020-05-06 00:13:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let name = match &statement.name
|
|
|
|
|
{
|
|
|
|
|
// TODO: refactor
|
|
|
|
|
Some(name) => name.clone(),
|
|
|
|
|
None =>
|
|
|
|
|
{
|
|
|
|
|
i += 1;
|
|
|
|
|
format!("statement_{}", i)
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let statement_type = match statement.proof_status
|
|
|
|
|
{
|
2020-05-12 04:25:49 +02:00
|
|
|
|
ProofStatus::AssumedProven
|
|
|
|
|
| ProofStatus::Proven => "axiom",
|
|
|
|
|
ProofStatus::NotProven
|
|
|
|
|
| ProofStatus::Disproven => unreachable!(),
|
2020-05-06 21:38:48 +02:00
|
|
|
|
ProofStatus::ToProveNow => "conjecture",
|
|
|
|
|
// Skip statements that will be proven later
|
|
|
|
|
ProofStatus::ToProveLater => continue,
|
|
|
|
|
// Skip statements that are not part of this proof
|
|
|
|
|
ProofStatus::Ignored => continue,
|
2020-05-06 00:13:43 +02:00
|
|
|
|
};
|
|
|
|
|
|
2020-05-22 02:42:38 +02:00
|
|
|
|
// TODO: avoid doing this twice
|
|
|
|
|
match statement.kind
|
|
|
|
|
{
|
|
|
|
|
StatementKind::CompletedDefinition(_)
|
|
|
|
|
| StatementKind::IntegrityConstraint =>
|
|
|
|
|
crate::autoname_variables(&mut statement.formula),
|
|
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 00:13:43 +02:00
|
|
|
|
// TODO: add proper statement type
|
|
|
|
|
writeln!(formatter, "tff({}, {}, {}).", name, statement_type,
|
2020-05-22 02:25:00 +02:00
|
|
|
|
crate::output::tptp::display_formula(&statement.formula))?;
|
2020-05-06 00:13:43 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2020-05-05 19:40:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
impl foliage::FindOrCreateFunctionDeclaration<crate::FoliageFlavor> for Problem
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
|
|
|
|
fn find_or_create_function_declaration(&self, name: &str, arity: usize)
|
2020-05-22 02:25:00 +02:00
|
|
|
|
-> std::rc::Rc<crate::FunctionDeclaration>
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
|
|
|
|
let mut function_declarations = self.function_declarations.borrow_mut();
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
match function_declarations.iter().find(|x| x.matches_signature(name, arity))
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
|
|
|
|
Some(declaration) => std::rc::Rc::clone(&declaration),
|
|
|
|
|
None =>
|
|
|
|
|
{
|
2020-05-22 02:25:00 +02:00
|
|
|
|
let declaration = crate::FunctionDeclaration::new(name.to_string(), arity);
|
2020-05-05 19:40:57 +02:00
|
|
|
|
let declaration = std::rc::Rc::new(declaration);
|
|
|
|
|
|
|
|
|
|
function_declarations.insert(std::rc::Rc::clone(&declaration));
|
|
|
|
|
|
|
|
|
|
log::debug!("new function declaration: {}/{}", name, arity);
|
|
|
|
|
|
|
|
|
|
declaration
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
impl foliage::FindOrCreatePredicateDeclaration<crate::FoliageFlavor> for Problem
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
|
|
|
|
fn find_or_create_predicate_declaration(&self, name: &str, arity: usize)
|
2020-05-22 02:25:00 +02:00
|
|
|
|
-> std::rc::Rc<crate::PredicateDeclaration>
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
|
|
|
|
let mut predicate_declarations = self.predicate_declarations.borrow_mut();
|
|
|
|
|
|
2020-05-22 02:25:00 +02:00
|
|
|
|
match predicate_declarations.iter().find(|x| x.matches_signature(name, arity))
|
2020-05-05 19:40:57 +02:00
|
|
|
|
{
|
|
|
|
|
Some(declaration) => std::rc::Rc::clone(&declaration),
|
|
|
|
|
None =>
|
|
|
|
|
{
|
2020-05-22 02:25:00 +02:00
|
|
|
|
let declaration = crate::PredicateDeclaration::new(name.to_string(), arity);
|
2020-05-05 19:40:57 +02:00
|
|
|
|
let declaration = std::rc::Rc::new(declaration);
|
|
|
|
|
|
|
|
|
|
predicate_declarations.insert(std::rc::Rc::clone(&declaration));
|
|
|
|
|
|
|
|
|
|
log::debug!("new predicate declaration: {}/{}", name, arity);
|
|
|
|
|
|
|
|
|
|
declaration
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-06 21:38:48 +02:00
|
|
|
|
fn run_vampire<I, S>(input: &str, arguments: Option<I>)
|
|
|
|
|
-> Result<(ProofResult, Option<f32>), crate::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,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let mut vampire = vampire
|
|
|
|
|
.stdin(std::process::Stdio::piped())
|
|
|
|
|
.stdout(std::process::Stdio::piped())
|
|
|
|
|
.stderr(std::process::Stdio::piped())
|
|
|
|
|
.spawn()
|
|
|
|
|
.map_err(|error| crate::Error::new_run_vampire(error))?;
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
use std::io::Write as _;
|
|
|
|
|
|
|
|
|
|
let vampire_stdin = vampire.stdin.as_mut().unwrap();
|
|
|
|
|
vampire_stdin.write_all(input.as_bytes())
|
|
|
|
|
.map_err(|error| crate::Error::new_run_vampire(error))?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let output = vampire.wait_with_output()
|
|
|
|
|
.map_err(|error| crate::Error::new_run_vampire(error))?;
|
|
|
|
|
|
|
|
|
|
let stdout = std::str::from_utf8(&output.stdout)
|
|
|
|
|
.map_err(|error| crate::Error::new_run_vampire(error))?;
|
|
|
|
|
|
|
|
|
|
let stderr = std::str::from_utf8(&output.stderr)
|
|
|
|
|
.map_err(|error| crate::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)
|
|
|
|
|
{
|
|
|
|
|
return Ok((ProofResult::NotProven, None));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Err(crate::Error::new_prove_program(output.status.code(), stdout.to_string(),
|
|
|
|
|
stderr.to_string()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
return Ok((ProofResult::Proven, proof_time));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: support disproven result
|
|
|
|
|
|
|
|
|
|
Err(crate::Error::new_parse_vampire_output(stdout.to_string(), stderr.to_string()))
|
|
|
|
|
}
|