anthem-rs/src/translate/verify_properties.rs

301 lines
8.6 KiB
Rust
Raw Normal View History

mod head_type;
mod translate_body;
use head_type::*;
use translate_body::*;
use foliage::flavor::{PredicateDeclaration as _};
2020-01-25 12:55:23 +01:00
2020-05-05 19:40:57 +02:00
struct PredicateDefinitions
2020-02-02 02:53:04 +01:00
{
pub parameters: std::rc::Rc<crate::VariableDeclarations>,
pub definitions: Vec<crate::OpenFormula>,
2020-02-02 02:53:04 +01:00
}
2020-05-05 19:40:57 +02:00
type Definitions =
std::collections::BTreeMap::<std::rc::Rc<crate::PredicateDeclaration>, PredicateDefinitions>;
2020-05-05 19:40:57 +02:00
pub(crate) struct Translator<'p>
{
2020-05-11 04:00:51 +02:00
problem: &'p mut crate::Problem,
2020-05-05 19:40:57 +02:00
definitions: Definitions,
}
struct Logger;
impl clingo::Logger for Logger
2020-02-02 02:53:04 +01:00
{
2020-05-05 19:40:57 +02:00
fn log(&mut self, code: clingo::Warning, message: &str)
2020-02-02 02:53:04 +01:00
{
2020-05-05 19:40:57 +02:00
log::warn!("clingo warning ({:?}): {}", code, message);
2020-02-02 02:53:04 +01:00
}
}
2020-05-05 19:40:57 +02:00
impl<'p> clingo::StatementHandler for Translator<'p>
2020-02-02 02:53:04 +01:00
{
fn on_statement(&mut self, statement: &clingo::ast::Statement) -> bool
{
match statement.statement_type()
{
clingo::ast::StatementType::Rule(ref rule) =>
{
2020-05-05 19:40:57 +02:00
if let Err(error) = self.read_rule(rule)
2020-02-02 02:53:04 +01:00
{
log::error!("could not translate input program: {}", error);
return false;
}
},
_ => log::debug!("read statement (other kind)"),
}
true
}
}
2020-02-01 21:59:36 +01:00
2020-05-05 19:40:57 +02:00
impl<'p> Translator<'p>
2020-02-02 02:53:04 +01:00
{
2020-05-05 19:40:57 +02:00
pub fn new(problem: &'p mut crate::Problem) -> Self
2020-02-05 19:40:21 +01:00
{
2020-05-05 19:40:57 +02:00
Self
{
problem,
definitions: Definitions::new(),
}
2020-02-05 19:40:21 +01:00
}
2020-02-05 01:10:33 +01:00
2020-05-05 19:40:57 +02:00
pub fn translate<P>(&mut self, program_path: P) -> Result<(), crate::Error>
where
2020-05-13 01:40:44 +02:00
P: AsRef<std::path::Path>,
2020-02-02 19:20:16 +01:00
{
2020-05-05 19:40:57 +02:00
// Read input program
2020-02-02 19:20:16 +01:00
let program = std::fs::read_to_string(program_path.as_ref())
2020-05-05 19:40:57 +02:00
.map_err(
|error| crate::Error::new_read_file(program_path.as_ref().to_path_buf(), error))?;
2020-02-02 19:20:16 +01:00
2020-05-05 19:40:57 +02:00
clingo::parse_program_with_logger(&program, self, &mut Logger, std::u32::MAX)
2020-02-02 19:20:16 +01:00
.map_err(|error| crate::Error::new_translate(error))?;
2020-02-05 01:10:33 +01:00
log::info!("read input program “{}”", program_path.as_ref().display());
2020-02-02 17:57:27 +01:00
let completed_definition = |predicate_declaration, definitions: &mut Definitions|
2020-02-02 17:57:27 +01:00
{
2020-05-05 19:40:57 +02:00
match definitions.remove(predicate_declaration)
2020-02-02 17:57:27 +01:00
{
2020-05-05 19:40:57 +02:00
// This predicate symbol has at least one definition, so build the disjunction of those
Some(predicate_definitions) =>
2020-02-02 17:57:27 +01:00
{
2020-05-05 19:40:57 +02:00
let or_arguments = predicate_definitions.definitions.into_iter()
.map(|x| crate::existential_closure(x))
.collect::<Vec<_>>();
let or = crate::Formula::or(or_arguments);
2020-02-02 17:57:27 +01:00
2020-05-05 19:40:57 +02:00
let head_arguments = predicate_definitions.parameters.iter()
.map(|x| crate::Term::variable(std::rc::Rc::clone(x)))
2020-05-05 19:40:57 +02:00
.collect::<Vec<_>>();
2020-02-02 17:57:27 +01:00
let head_predicate = crate::Formula::predicate(
2020-05-05 19:40:57 +02:00
std::rc::Rc::clone(predicate_declaration), head_arguments);
2020-02-02 17:57:27 +01:00
2020-05-05 19:40:57 +02:00
let completed_definition =
crate::Formula::if_and_only_if(vec![head_predicate, or]);
2020-02-02 17:57:27 +01:00
let open_formula = crate::OpenFormula
2020-05-05 19:40:57 +02:00
{
free_variable_declarations: predicate_definitions.parameters,
formula: completed_definition,
};
2020-05-11 03:58:30 +02:00
crate::universal_closure(open_formula)
2020-05-05 19:40:57 +02:00
},
// This predicate has no definitions, so universally falsify it
None =>
2020-02-02 17:57:27 +01:00
{
let parameters = std::rc::Rc::new((0..predicate_declaration.arity()).map(
|_| std::rc::Rc::new(crate::VariableDeclaration::new_generated(
crate::Domain::Program)))
2020-05-05 19:40:57 +02:00
.collect::<Vec<_>>());
let head_arguments = parameters.iter()
.map(|x| crate::Term::variable(std::rc::Rc::clone(x)))
2020-05-05 19:40:57 +02:00
.collect();
let head_predicate = crate::Formula::predicate(
2020-05-05 19:40:57 +02:00
std::rc::Rc::clone(predicate_declaration), head_arguments);
let not = crate::Formula::not(Box::new(head_predicate));
2020-05-05 19:40:57 +02:00
let open_formula = crate::OpenFormula
2020-05-05 19:40:57 +02:00
{
free_variable_declarations: parameters,
formula: not,
};
2020-05-11 03:58:30 +02:00
crate::universal_closure(open_formula)
2020-05-05 19:40:57 +02:00
},
}
2020-05-05 19:40:57 +02:00
};
for predicate_declaration in self.problem.predicate_declarations.borrow().iter()
2020-02-05 01:10:33 +01:00
{
// Dont perform completion for input predicates and built-in predicates
if *predicate_declaration.is_input.borrow() || predicate_declaration.is_built_in()
2020-05-07 17:19:42 +02:00
{
continue;
2020-05-07 17:19:42 +02:00
}
2020-05-13 02:24:13 +02:00
let statement_kind = crate::problem::StatementKind::CompletedDefinition(
std::rc::Rc::clone(&predicate_declaration));
2020-05-05 19:40:57 +02:00
2020-05-22 18:14:56 +02:00
let completed_definition = completed_definition(predicate_declaration,
&mut self.definitions);
let statement_name =
format!("completed_definition_{}", predicate_declaration.tptp_statement_name());
2020-05-13 02:24:13 +02:00
let statement = crate::problem::Statement::new(statement_kind, completed_definition)
.with_name(statement_name);
2020-05-05 19:40:57 +02:00
self.problem.add_statement(crate::problem::SectionKind::CompletedDefinitions,
statement);
2020-02-05 01:10:33 +01:00
}
2020-02-04 00:27:04 +01:00
2020-05-05 19:40:57 +02:00
Ok(())
2020-02-05 01:10:33 +01:00
}
2020-05-05 19:40:57 +02:00
fn read_rule(&mut self, rule: &clingo::ast::Rule)
-> Result<(), crate::Error>
2020-02-05 01:10:33 +01:00
{
2020-05-05 19:40:57 +02:00
let head_type = determine_head_type(rule.head(), self.problem)?;
2020-02-05 01:10:33 +01:00
2020-05-05 19:40:57 +02:00
match &head_type
2020-02-05 01:10:33 +01:00
{
2020-05-05 19:40:57 +02:00
HeadType::SingleAtom(head_atom)
| HeadType::ChoiceWithSingleAtom(head_atom) =>
{
if !self.definitions.contains_key(&head_atom.predicate_declaration)
{
let parameters = std::rc::Rc::new((0..head_atom.predicate_declaration.arity())
.map(
|_| std::rc::Rc::new(crate::VariableDeclaration::new_generated(
crate::Domain::Program)))
2020-05-05 19:40:57 +02:00
.collect());
self.definitions.insert(
std::rc::Rc::clone(&head_atom.predicate_declaration),
PredicateDefinitions
{
parameters,
definitions: vec![],
});
}
2020-05-05 19:40:57 +02:00
// TODO: refactor
let predicate_definitions =
self.definitions.get_mut(&head_atom.predicate_declaration).unwrap();
2020-02-01 19:20:46 +01:00
2020-05-05 19:40:57 +02:00
let parameters = std::rc::Rc::clone(&predicate_definitions.parameters);
let free_variable_declarations = std::cell::RefCell::new(vec![]);
let free_layer =
crate::VariableDeclarationStackLayer::Free(free_variable_declarations);
2020-05-05 19:40:57 +02:00
let parameters_layer =
crate::VariableDeclarationStackLayer::bound(&free_layer, parameters);
2020-02-01 19:20:46 +01:00
2020-05-05 19:40:57 +02:00
let mut definition_arguments =
translate_body(rule.body(), self.problem, &parameters_layer)?;
2020-02-01 21:59:36 +01:00
2020-05-05 19:40:57 +02:00
// TODO: refactor
assert_eq!(predicate_definitions.parameters.len(), head_atom.arguments.len());
2020-02-01 21:59:36 +01:00
2020-05-05 19:40:57 +02:00
if let HeadType::ChoiceWithSingleAtom(_) = head_type
{
let head_arguments = predicate_definitions.parameters.iter()
.map(|x| crate::Term::variable(std::rc::Rc::clone(x)))
2020-05-05 19:40:57 +02:00
.collect::<Vec<_>>();
2020-02-02 02:32:32 +01:00
let head_predicate = crate::Formula::predicate(
2020-05-05 19:40:57 +02:00
std::rc::Rc::clone(&head_atom.predicate_declaration), head_arguments);
2020-02-02 02:32:32 +01:00
2020-05-05 19:40:57 +02:00
definition_arguments.push(head_predicate);
}
2020-05-05 19:40:57 +02:00
let mut head_atom_arguments_iterator = head_atom.arguments.iter();
2020-05-05 19:40:57 +02:00
for parameter in predicate_definitions.parameters.iter()
{
let head_atom_argument = head_atom_arguments_iterator.next().unwrap();
2020-05-05 19:40:57 +02:00
let translated_head_term = crate::translate::common::choose_value_in_term(
head_atom_argument, std::rc::Rc::clone(parameter), self.problem,
&parameters_layer)?;
2020-02-02 02:32:32 +01:00
2020-05-05 19:40:57 +02:00
definition_arguments.push(translated_head_term);
}
2020-02-02 02:32:32 +01:00
2020-05-05 19:40:57 +02:00
// TODO: refactor
let free_variable_declarations = match free_layer
{
crate::VariableDeclarationStackLayer::Free(free_variable_declarations)
2020-05-05 19:40:57 +02:00
=> free_variable_declarations.into_inner(),
_ => unreachable!(),
};
2020-02-02 02:32:32 +01:00
2020-05-05 19:40:57 +02:00
let definition = match definition_arguments.len()
{
1 => definition_arguments.pop().unwrap(),
0 => crate::Formula::true_(),
_ => crate::Formula::and(definition_arguments),
2020-05-05 19:40:57 +02:00
};
2020-02-01 21:59:36 +01:00
let definition = crate::OpenFormula
2020-05-05 19:40:57 +02:00
{
free_variable_declarations: std::rc::Rc::new(free_variable_declarations),
formula: definition,
};
2020-02-02 02:32:32 +01:00
2020-05-05 19:40:57 +02:00
predicate_definitions.definitions.push(definition);
},
HeadType::IntegrityConstraint =>
2020-02-02 02:32:32 +01:00
{
2020-05-05 19:40:57 +02:00
let free_variable_declarations = std::cell::RefCell::new(vec![]);
let free_layer =
crate::VariableDeclarationStackLayer::Free(free_variable_declarations);
2020-02-02 02:32:32 +01:00
2020-05-05 19:40:57 +02:00
let mut arguments = translate_body(rule.body(), self.problem, &free_layer)?;
2020-02-02 02:32:32 +01:00
2020-05-05 19:40:57 +02:00
// TODO: refactor
let free_variable_declarations = match free_layer
{
crate::VariableDeclarationStackLayer::Free(free_variable_declarations)
2020-05-05 19:40:57 +02:00
=> free_variable_declarations.into_inner(),
_ => unreachable!(),
};
2020-05-05 19:40:57 +02:00
let formula = match arguments.len()
{
1 => crate::Formula::not(Box::new(arguments.pop().unwrap())),
0 => crate::Formula::false_(),
_ => crate::Formula::not(Box::new(crate::Formula::and(arguments))),
2020-05-05 19:40:57 +02:00
};
let open_formula = crate::OpenFormula
2020-05-05 19:40:57 +02:00
{
free_variable_declarations: std::rc::Rc::new(free_variable_declarations),
formula,
};
2020-05-11 03:58:30 +02:00
let integrity_constraint = crate::universal_closure(open_formula);
2020-02-02 17:57:27 +01:00
2020-05-05 19:40:57 +02:00
let statement = crate::problem::Statement::new(
2020-05-13 02:24:13 +02:00
crate::problem::StatementKind::IntegrityConstraint, integrity_constraint)
2020-05-13 03:16:51 +02:00
.with_name("integrity_constraint".to_string());
2020-05-05 19:40:57 +02:00
self.problem.add_statement(crate::problem::SectionKind::IntegrityConstraints,
statement);
},
HeadType::Trivial => log::info!("skipping trivial rule"),
}
2020-05-05 19:40:57 +02:00
Ok(())
2020-02-01 15:32:41 +01:00
}
2020-01-24 13:32:43 +01:00
}