pub trait DisplayTPTP<'a, DisplayType> where DisplayType: 'a + std::fmt::Debug + std::fmt::Display { fn display_tptp(&'a self) -> DisplayType; } pub fn is_formula_statement_axiom(formula_statement: &crate::project::FormulaStatement, proof_direction: crate::project::ProofDirection) -> bool { if formula_statement.proven { return true; } match (proof_direction, &formula_statement.kind) { (_, crate::project::FormulaStatementKind::Axiom) => true, (_, crate::project::FormulaStatementKind::Assumption) => true, (crate::project::ProofDirection::Forward, crate::project::FormulaStatementKind::Completion(_)) => true, (crate::project::ProofDirection::Backward, crate::project::FormulaStatementKind::Assertion) => true, _ => false, } } pub fn is_formula_statement_lemma(formula_statement: &crate::project::FormulaStatement, proof_direction: crate::project::ProofDirection) -> bool { if formula_statement.proven { return false; } match (proof_direction, &formula_statement.kind) { (_, crate::project::FormulaStatementKind::Lemma(None)) => true, (proof_direction, crate::project::FormulaStatementKind::Lemma(Some(proof_direction_lemma))) => proof_direction == *proof_direction_lemma, _ => false, } } pub fn is_formula_statement_theorem(formula_statement: &crate::project::FormulaStatement, proof_direction: crate::project::ProofDirection) -> bool { if formula_statement.proven { return false; } match (proof_direction, &formula_statement.kind) { (crate::project::ProofDirection::Forward, crate::project::FormulaStatementKind::Assertion) => true, (crate::project::ProofDirection::Backward, crate::project::FormulaStatementKind::Completion(_)) => true, _ => false, } } pub fn is_formula_statement_ignored(formula_statement: &crate::project::FormulaStatement, input_predicates: &std::collections::HashSet) -> bool { // Hide completed definitions of input predicates if let crate::project::FormulaStatementKind::Completion(crate::project::CompletionTarget::Predicate(ref predicate_declaration)) = formula_statement.kind { return input_predicates.contains(predicate_declaration); } false } fn is_integer_input_constant(constant_name: &str, input_constants: &std::collections::HashSet) -> bool { let input_constant = crate::project::InputConstantDeclaration { // TODO: avoid unnecessary allocation name: constant_name.to_owned(), domain: foliage::Domain::Integer, }; input_constants.contains(&input_constant) } fn is_arithmetic_term(term: &foliage::Term, input_constants: &std::collections::HashSet) -> bool { match term { foliage::Term::Infimum => false, foliage::Term::Supremum => false, foliage::Term::Integer(_) => true, foliage::Term::Symbolic(ref name) => { is_integer_input_constant(name, input_constants) }, foliage::Term::String(_) => false, foliage::Term::Variable(ref declaration) => match declaration.domain { foliage::Domain::Program => false, foliage::Domain::Integer => true, }, foliage::Term::Add(ref left, ref right) => is_arithmetic_term(left, input_constants) && is_arithmetic_term(right, input_constants), foliage::Term::Subtract(ref left, ref right) => is_arithmetic_term(left, input_constants) && is_arithmetic_term(right, input_constants), foliage::Term::Multiply(ref left, ref right) => is_arithmetic_term(left, input_constants) && is_arithmetic_term(right, input_constants), foliage::Term::Negative(ref argument) => is_arithmetic_term(argument, input_constants), } } fn collect_predicate_declarations_in_formula<'a>( predicate_declarations: &mut std::collections::HashSet<&'a foliage::PredicateDeclaration>, formula: &'a foliage::Formula) { match formula { foliage::Formula::Exists(ref exists) => collect_predicate_declarations_in_formula(predicate_declarations, &exists.argument), foliage::Formula::ForAll(ref for_all) => collect_predicate_declarations_in_formula(predicate_declarations, &for_all.argument), foliage::Formula::Not(ref argument) => collect_predicate_declarations_in_formula(predicate_declarations, argument), foliage::Formula::And(ref arguments) => for argument in arguments { collect_predicate_declarations_in_formula(predicate_declarations, argument); }, foliage::Formula::Or(ref arguments) => for argument in arguments { collect_predicate_declarations_in_formula(predicate_declarations, argument); }, foliage::Formula::Implies(ref left, ref right, _) => { collect_predicate_declarations_in_formula(predicate_declarations, left); collect_predicate_declarations_in_formula(predicate_declarations, right); }, foliage::Formula::Biconditional(ref left, ref right) => { collect_predicate_declarations_in_formula(predicate_declarations, left); collect_predicate_declarations_in_formula(predicate_declarations, right); }, foliage::Formula::Less(_, _) => (), foliage::Formula::LessOrEqual(_, _) => (), foliage::Formula::Greater(_, _) => (), foliage::Formula::GreaterOrEqual(_, _) => (), foliage::Formula::Equal(_, _) => (), foliage::Formula::NotEqual(_, _) => (), foliage::Formula::Boolean(_) => (), foliage::Formula::Predicate(ref predicate) => { predicate_declarations.insert(&predicate.declaration); }, } } fn collect_predicate_declarations_in_project<'a>(project: &'a crate::Project) -> std::collections::HashSet<&'a foliage::PredicateDeclaration> { let mut predicate_declarations = std::collections::HashSet::new(); let formulas = project.blocks.iter() .filter_map( |block| match block { crate::project::Block::Whitespace(_) => None, crate::project::Block::FormulaStatement(ref formula_statement) => Some(&formula_statement.formula), crate::project::Block::InputStatement(_) => None, }); for formula in formulas { collect_predicate_declarations_in_formula(&mut predicate_declarations, formula); } predicate_declarations } fn collect_symbolic_constants_in_term<'a>( symbolic_constants: &mut std::collections::HashSet<&'a str>, term: &'a foliage::Term) { match term { foliage::Term::Infimum => (), foliage::Term::Supremum => (), foliage::Term::Integer(_) => (), foliage::Term::Symbolic(ref name) => { symbolic_constants.insert(name); }, foliage::Term::String(_) => (), foliage::Term::Variable(_) => (), foliage::Term::Add(ref left, ref right) => { collect_symbolic_constants_in_term(symbolic_constants, left); collect_symbolic_constants_in_term(symbolic_constants, right); }, foliage::Term::Subtract(ref left, ref right) => { collect_symbolic_constants_in_term(symbolic_constants, left); collect_symbolic_constants_in_term(symbolic_constants, right); }, foliage::Term::Multiply(ref left, ref right) => { collect_symbolic_constants_in_term(symbolic_constants, left); collect_symbolic_constants_in_term(symbolic_constants, right); }, foliage::Term::Negative(ref argument) => { collect_symbolic_constants_in_term(symbolic_constants, argument); }, } } fn collect_symbolic_constants_in_formula<'a>( symbolic_constants: &mut std::collections::HashSet<&'a str>, formula: &'a foliage::Formula) { match formula { foliage::Formula::Exists(ref exists) => collect_symbolic_constants_in_formula(symbolic_constants, &exists.argument), foliage::Formula::ForAll(ref for_all) => collect_symbolic_constants_in_formula(symbolic_constants, &for_all.argument), foliage::Formula::Not(ref argument) => collect_symbolic_constants_in_formula(symbolic_constants, argument), foliage::Formula::And(ref arguments) => for argument in arguments { collect_symbolic_constants_in_formula(symbolic_constants, argument); }, foliage::Formula::Or(ref arguments) => for argument in arguments { collect_symbolic_constants_in_formula(symbolic_constants, argument); }, foliage::Formula::Implies(ref left, ref right, _) => { collect_symbolic_constants_in_formula(symbolic_constants, left); collect_symbolic_constants_in_formula(symbolic_constants, right); }, foliage::Formula::Biconditional(ref left, ref right) => { collect_symbolic_constants_in_formula(symbolic_constants, left); collect_symbolic_constants_in_formula(symbolic_constants, right); }, foliage::Formula::Less(ref left, ref right) => { collect_symbolic_constants_in_term(symbolic_constants, left); collect_symbolic_constants_in_term(symbolic_constants, right); }, foliage::Formula::LessOrEqual(ref left, ref right) => { collect_symbolic_constants_in_term(symbolic_constants, left); collect_symbolic_constants_in_term(symbolic_constants, right); }, foliage::Formula::Greater(ref left, ref right) => { collect_symbolic_constants_in_term(symbolic_constants, left); collect_symbolic_constants_in_term(symbolic_constants, right); }, foliage::Formula::GreaterOrEqual(ref left, ref right) => { collect_symbolic_constants_in_term(symbolic_constants, left); collect_symbolic_constants_in_term(symbolic_constants, right); }, foliage::Formula::Equal(ref left, ref right) => { collect_symbolic_constants_in_term(symbolic_constants, left); collect_symbolic_constants_in_term(symbolic_constants, right); }, foliage::Formula::NotEqual(ref left, ref right) => { collect_symbolic_constants_in_term(symbolic_constants, left); collect_symbolic_constants_in_term(symbolic_constants, right); }, foliage::Formula::Boolean(_) => (), foliage::Formula::Predicate(ref predicate) => { for argument in &predicate.arguments { collect_symbolic_constants_in_term(symbolic_constants, &argument); } }, } } fn collect_symbolic_constants_in_project<'a>(project: &'a crate::Project) -> std::collections::HashSet<&'a str> { let mut symbolic_constants = std::collections::HashSet::new(); // TODO: avoid code duplication let formulas = project.blocks.iter() .filter_map( |block| match block { crate::project::Block::Whitespace(_) => None, crate::project::Block::FormulaStatement(ref formula_statement) => Some(&formula_statement.formula), crate::project::Block::InputStatement(_) => None, }); for formula in formulas { collect_symbolic_constants_in_formula(&mut symbolic_constants, formula); } symbolic_constants } struct VariableDeclarationDisplay<'a>(&'a foliage::VariableDeclaration); struct PredicateDeclarationDisplay<'a>(&'a foliage::PredicateDeclaration); struct TermDisplay<'a>(&'a foliage::Term); struct FormulaDisplay<'a, 'project> { formula: &'a foliage::Formula, input_constants: &'project std::collections::HashSet, } struct FormulaStatementDisplay<'a, 'project> { formula_statement: &'a crate::project::FormulaStatement, proof_direction: crate::project::ProofDirection, input_constants: &'project std::collections::HashSet, } pub struct ProjectDisplay<'a> { project: &'a crate::project::Project, conjecture: &'a crate::project::FormulaStatement, proof_direction: crate::project::ProofDirection, } impl<'a> DisplayTPTP<'a, VariableDeclarationDisplay<'a>> for foliage::VariableDeclaration { fn display_tptp(&'a self) -> VariableDeclarationDisplay<'a> { VariableDeclarationDisplay(self) } } impl<'a> DisplayTPTP<'a, PredicateDeclarationDisplay<'a>> for foliage::PredicateDeclaration { fn display_tptp(&'a self) -> PredicateDeclarationDisplay<'a> { PredicateDeclarationDisplay(self) } } impl<'a> DisplayTPTP<'a, TermDisplay<'a>> for foliage::Term { fn display_tptp(&'a self) -> TermDisplay<'a> { TermDisplay(self) } } fn display_formula_tptp<'a, 'project>(formula: &'a foliage::Formula, input_constants: &'project std::collections::HashSet) -> FormulaDisplay<'a, 'project> { FormulaDisplay { formula, input_constants, } } fn display_formula_statement_tptp<'a, 'project>(formula_statement: &'a crate::project::FormulaStatement, proof_direction: crate::project::ProofDirection, input_constants: &'project std::collections::HashSet,) -> FormulaStatementDisplay<'a, 'project> { FormulaStatementDisplay { formula_statement, proof_direction, input_constants, } } pub fn display_project_with_conjecture_tptp<'a>(project: &'a crate::Project, conjecture: &'a crate::project::FormulaStatement, proof_direction: crate::project::ProofDirection) -> ProjectDisplay<'a> { ProjectDisplay { project, conjecture, proof_direction, } } impl<'a> std::fmt::Debug for VariableDeclarationDisplay<'a> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { match &self.0.domain { foliage::Domain::Program => write!(format, "{}: object", self.0.name), foliage::Domain::Integer => write!(format, "{}: $int", self.0.name), } } } impl<'a> std::fmt::Display for VariableDeclarationDisplay<'a> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", &self) } } impl<'a> std::fmt::Debug for PredicateDeclarationDisplay<'a> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{}: (", self.0.name)?; let mut separator = ""; for _ in 0..self.0.arity { write!(format, "{}object", separator)?; separator = " * " } write!(format, ") > $o") } } impl<'a> std::fmt::Display for PredicateDeclarationDisplay<'a> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", &self) } } impl<'a> std::fmt::Debug for TermDisplay<'a> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { match self.0 { foliage::Term::Infimum => write!(format, "c__infimum__"), foliage::Term::Supremum => write!(format, "c__supremum__"), foliage::Term::Integer(value) => write!(format, "{}", value), foliage::Term::Symbolic(ref value) => write!(format, "{}", value), foliage::Term::String(ref value) => write!(format, "\"{}\"", value), foliage::Term::Variable(ref declaration) => match declaration.domain { foliage::Domain::Program => write!(format, "{}", declaration.name), foliage::Domain::Integer => write!(format, "{}", declaration.name), }, foliage::Term::Add(ref left, ref right) => write!(format, "$sum({:?}, {:?})", (&**left).display_tptp(), right.display_tptp()), foliage::Term::Subtract(ref left, ref right) => write!(format, "$difference({:?}, {:?})", left.display_tptp(), right.display_tptp()), foliage::Term::Multiply(ref left, ref right) => write!(format, "$product({:?}, {:?})", left.display_tptp(), right.display_tptp()), foliage::Term::Negative(ref argument) => write!(format, "$uminus({:?})", argument.display_tptp()), } } } impl<'a> std::fmt::Display for TermDisplay<'a> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", self) } } impl<'a, 'project> std::fmt::Debug for FormulaDisplay<'a, 'project> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { #[derive(Eq, PartialEq)] enum Notation { Prefix, Infix, } let mut display_comparison = |notation, operator_identifier: &str, operator_identifier_fallback, left, right| -> Result<(), std::fmt::Error> { write!(format, "(")?; let mut notation = notation; let mut operator_identifier = operator_identifier; let left_is_arithmetic_term = is_arithmetic_term(left, self.input_constants); let right_is_arithmetic_term = is_arithmetic_term(right, self.input_constants); if let Some(operator_identifier_fallback) = operator_identifier_fallback { if !left_is_arithmetic_term || !right_is_arithmetic_term { notation = Notation::Prefix; operator_identifier = operator_identifier_fallback; } } if notation == Notation::Prefix { write!(format, "{}(", operator_identifier)?; } if left_is_arithmetic_term && !right_is_arithmetic_term { write!(format, "f__integer__({})", left.display_tptp())?; } else { write!(format, "{}", left.display_tptp())?; } match notation { Notation::Prefix => write!(format, ", ")?, Notation::Infix => write!(format, " {} ", operator_identifier)?, } if right_is_arithmetic_term && !left_is_arithmetic_term { write!(format, "f__integer__({})", right.display_tptp())?; } else { write!(format, "{}", right.display_tptp())?; } if notation == Notation::Prefix { write!(format, ")")?; } write!(format, ")") }; match self.formula { foliage::Formula::Exists(ref exists) => { write!(format, "?[")?; let mut separator = ""; for parameter in &exists.parameters { write!(format, "{}{:?}", separator, parameter.display_tptp())?; separator = ", " } write!(format, "]: ({:?})", display_formula_tptp(&exists.argument, self.input_constants)) }, foliage::Formula::ForAll(ref for_all) => { write!(format, "![")?; let mut separator = ""; for parameter in &for_all.parameters { write!(format, "{}{:?}", separator, parameter.display_tptp())?; separator = ", " } write!(format, "]: ({:?})", display_formula_tptp(&for_all.argument, self.input_constants)) }, foliage::Formula::Not(ref argument) => write!(format, "~({:?})", display_formula_tptp(argument, self.input_constants)), foliage::Formula::And(ref arguments) => { write!(format, "(")?; let mut separator = ""; for argument in arguments { write!(format, "{}{:?}", separator, display_formula_tptp(argument, self.input_constants))?; separator = " & " } write!(format, ")") }, foliage::Formula::Or(ref arguments) => { write!(format, "(")?; let mut separator = ""; for argument in arguments { write!(format, "{}{:?}", separator, display_formula_tptp(argument, self.input_constants))?; separator = " | " } write!(format, ")") }, foliage::Formula::Implies(ref left, ref right, implication_direction) => match implication_direction { foliage::ImplicationDirection::LeftToRight => write!(format, "({:?} => {:?})", display_formula_tptp(left, self.input_constants), display_formula_tptp(right, self.input_constants)), foliage::ImplicationDirection::RightToLeft => write!(format, "({:?} <= {:?})", display_formula_tptp(left, self.input_constants), display_formula_tptp(right, self.input_constants)), }, foliage::Formula::Biconditional(ref left, ref right) => write!(format, "({:?} <=> {:?})", display_formula_tptp(left, self.input_constants), display_formula_tptp(right, self.input_constants)), foliage::Formula::Less(ref left, ref right) => display_comparison(Notation::Prefix, "$less", Some("p__less__"), left, right), foliage::Formula::LessOrEqual(ref left, ref right) => display_comparison(Notation::Prefix, "$lesseq", Some("p__less_equal__"), left, right), foliage::Formula::Greater(ref left, ref right) => display_comparison(Notation::Prefix, "$greater", Some("p__greater__"), left, right), foliage::Formula::GreaterOrEqual(ref left, ref right) => display_comparison(Notation::Prefix, "$greatereq", Some("p__greater_equal__"), left, right), foliage::Formula::Equal(ref left, ref right) => display_comparison(Notation::Infix, "=", None, left, right), foliage::Formula::NotEqual(ref left, ref right) => display_comparison(Notation::Infix, "!=", None, left, right), foliage::Formula::Boolean(value) => match value { true => write!(format, "$true"), false => write!(format, "$false"), }, foliage::Formula::Predicate(ref predicate) => { write!(format, "{}", predicate.declaration.name)?; if !predicate.arguments.is_empty() { write!(format, "(")?; let mut separator = ""; for argument in &predicate.arguments { let argument_is_arithmetic_term = is_arithmetic_term(argument, self.input_constants); write!(format, "{}", separator)?; if argument_is_arithmetic_term { write!(format, "f__integer__(")?; } write!(format, "{:?}", argument.display_tptp())?; if argument_is_arithmetic_term { write!(format, ")")?; } separator = ", " } write!(format, ")")?; } Ok(()) }, } } } impl<'a, 'project> std::fmt::Display for FormulaDisplay<'a, 'project> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", self) } } impl<'a, 'project> std::fmt::Debug for FormulaStatementDisplay<'a, 'project> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "\ntff(")?; let identifier = match &self.formula_statement.kind { crate::project::FormulaStatementKind::Axiom => "axiom", crate::project::FormulaStatementKind::Assumption => "assumption", crate::project::FormulaStatementKind::Completion(_) => "completion", crate::project::FormulaStatementKind::Assertion => "assertion", crate::project::FormulaStatementKind::Lemma(_) => "lemma", }; write!(format, "{}, ", identifier)?; if is_formula_statement_theorem(&self.formula_statement, self.proof_direction) || is_formula_statement_lemma(&self.formula_statement, self.proof_direction) { write!(format, "conjecture")?; } else if is_formula_statement_axiom(&self.formula_statement, self.proof_direction) { write!(format, "axiom")?; } else { panic!("expected formula statement to be either theorem, lemma, or axiom, please report to bug tracker"); } write!(format, ", {:?}).", display_formula_tptp(&self.formula_statement.formula, self.input_constants)) } } impl<'a, 'project> std::fmt::Display for FormulaStatementDisplay<'a, 'project> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", &self) } } impl<'a> std::fmt::Debug for ProjectDisplay<'a> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { let write_title = |format: &mut std::fmt::Formatter, line_separator, title_identifier| { write!(format, "{}{}", line_separator, "%".repeat(80))?; write!(format, "\n% {}", title_identifier)?; write!(format, "\n{}", "%".repeat(80)) }; write_title(format, "", "anthem types")?; let tptp_preamble_anthem_types = include_str!("tptp_preamble_anthem_types.tptp").trim_end(); write!(format, "\n{}", tptp_preamble_anthem_types)?; write_title(format, "\n\n", "anthem axioms")?; let tptp_preamble_anthem_axioms = include_str!("tptp_preamble_anthem_axioms.tptp").trim_end(); write!(format, "\n{}", tptp_preamble_anthem_axioms)?; let predicate_declarations = collect_predicate_declarations_in_project(self.project); let symbolic_constants = collect_symbolic_constants_in_project(self.project); if !predicate_declarations.is_empty() || !symbolic_constants.is_empty() { write_title(format, "\n\n", "types")?; for predicate_declaration in predicate_declarations { write!(format, "\ntff(type, type, {:?}).", predicate_declaration.display_tptp())?; } for symbolic_constant in symbolic_constants { match is_integer_input_constant(symbolic_constant, &self.project.input_constants) { true => write!(format, "\ntff(type, type, {}: $int).", symbolic_constant)?, false => write!(format, "\ntff(type, type, {}: object).", symbolic_constant)?, } } } let axioms = self.project.blocks.iter() .filter_map( |block| match block { crate::project::Block::Whitespace(_) => None, crate::project::Block::FormulaStatement(ref formula_statement) => { if is_formula_statement_ignored(formula_statement, &self.project.input_predicates) { return None; } match is_formula_statement_axiom(&formula_statement, self.proof_direction) { true => Some(formula_statement), false => None, } }, crate::project::Block::InputStatement(_) => None, }); for axiom in axioms { write!(format, "\n{}", display_formula_statement_tptp(&axiom, self.proof_direction, &self.project.input_constants))?; } write_title(format, "\n\n", "assertion")?; write!(format, "\n{}", display_formula_statement_tptp(&self.conjecture, self.proof_direction, &self.project.input_constants)) } } impl<'a> std::fmt::Display for ProjectDisplay<'a> { fn fmt(&self, format: &mut std::fmt::Formatter) -> std::fmt::Result { write!(format, "{:?}", &self) } }