#![cfg_attr(docsrs, feature(doc_cfg))]
pub mod certifier;
pub mod engine;
pub mod error;
pub mod hints;
pub mod unify;
#[cfg(feature = "verification")]
pub mod oracle;
pub use engine::BackwardChainer;
pub use error::ProofError;
pub use hints::{suggest_hint, SocraticHint, SuggestedTactic};
pub use unify::Substitution;
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ProofTerm {
Constant(String),
Variable(String),
Function(String, Vec<ProofTerm>),
Group(Vec<ProofTerm>),
BoundVarRef(String),
}
impl fmt::Display for ProofTerm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ProofTerm::Constant(s) => write!(f, "{}", s),
ProofTerm::Variable(s) => write!(f, "{}", s),
ProofTerm::Function(name, args) => {
write!(f, "{}(", name)?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", arg)?;
}
write!(f, ")")
}
ProofTerm::Group(terms) => {
write!(f, "(")?;
for (i, t) in terms.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", t)?;
}
write!(f, ")")
}
ProofTerm::BoundVarRef(s) => write!(f, "#{}", s),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ProofExpr {
Predicate {
name: String,
args: Vec<ProofTerm>,
world: Option<String>,
},
Identity(ProofTerm, ProofTerm),
Atom(String),
And(Box<ProofExpr>, Box<ProofExpr>),
Or(Box<ProofExpr>, Box<ProofExpr>),
Implies(Box<ProofExpr>, Box<ProofExpr>),
Iff(Box<ProofExpr>, Box<ProofExpr>),
Not(Box<ProofExpr>),
ForAll {
variable: String,
body: Box<ProofExpr>,
},
Exists {
variable: String,
body: Box<ProofExpr>,
},
Modal {
domain: String,
force: f32,
flavor: String,
body: Box<ProofExpr>,
},
Temporal {
operator: String,
body: Box<ProofExpr>,
},
TemporalBinary {
operator: String,
left: Box<ProofExpr>,
right: Box<ProofExpr>,
},
Lambda {
variable: String,
body: Box<ProofExpr>,
},
App(Box<ProofExpr>, Box<ProofExpr>),
NeoEvent {
event_var: String,
verb: String,
roles: Vec<(String, ProofTerm)>,
},
Ctor {
name: String,
args: Vec<ProofExpr>,
},
Match {
scrutinee: Box<ProofExpr>,
arms: Vec<MatchArm>,
},
Fixpoint {
name: String,
body: Box<ProofExpr>,
},
TypedVar {
name: String,
typename: String,
},
Hole(String),
Term(ProofTerm),
Unsupported(String),
}
#[derive(Debug, Clone, PartialEq)]
pub struct MatchArm {
pub ctor: String,
pub bindings: Vec<String>,
pub body: ProofExpr,
}
impl fmt::Display for ProofExpr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ProofExpr::Predicate { name, args, world } => {
write!(f, "{}", name)?;
if !args.is_empty() {
write!(f, "(")?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", arg)?;
}
write!(f, ")")?;
}
if let Some(w) = world {
write!(f, " @{}", w)?;
}
Ok(())
}
ProofExpr::Identity(left, right) => write!(f, "{} = {}", left, right),
ProofExpr::Atom(s) => write!(f, "{}", s),
ProofExpr::And(left, right) => write!(f, "({} ∧ {})", left, right),
ProofExpr::Or(left, right) => write!(f, "({} ∨ {})", left, right),
ProofExpr::Implies(left, right) => write!(f, "({} → {})", left, right),
ProofExpr::Iff(left, right) => write!(f, "({} ↔ {})", left, right),
ProofExpr::Not(inner) => write!(f, "¬{}", inner),
ProofExpr::ForAll { variable, body } => write!(f, "∀{} {}", variable, body),
ProofExpr::Exists { variable, body } => write!(f, "∃{} {}", variable, body),
ProofExpr::Modal { domain, force, flavor, body } => {
write!(f, "□[{}/{}/{}]{}", domain, force, flavor, body)
}
ProofExpr::Temporal { operator, body } => write!(f, "{}({})", operator, body),
ProofExpr::TemporalBinary { operator, left, right } => {
write!(f, "TemporalBinary({}, {}, {})", operator, left, right)
}
ProofExpr::Lambda { variable, body } => write!(f, "λ{}.{}", variable, body),
ProofExpr::App(func, arg) => write!(f, "({} {})", func, arg),
ProofExpr::NeoEvent { event_var, verb, roles } => {
write!(f, "∃{}({}({})", event_var, verb, event_var)?;
for (role, term) in roles {
write!(f, " ∧ {}({}, {})", role, event_var, term)?;
}
write!(f, ")")
}
ProofExpr::Ctor { name, args } => {
write!(f, "{}", name)?;
if !args.is_empty() {
write!(f, "(")?;
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", arg)?;
}
write!(f, ")")?;
}
Ok(())
}
ProofExpr::Match { scrutinee, arms } => {
write!(f, "match {} {{ ", scrutinee)?;
for (i, arm) in arms.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{}", arm.ctor)?;
if !arm.bindings.is_empty() {
write!(f, "({})", arm.bindings.join(", "))?;
}
write!(f, " => {}", arm.body)?;
}
write!(f, " }}")
}
ProofExpr::Fixpoint { name, body } => write!(f, "fix {}.{}", name, body),
ProofExpr::TypedVar { name, typename } => write!(f, "{}:{}", name, typename),
ProofExpr::Unsupported(desc) => write!(f, "⟨unsupported: {}⟩", desc),
ProofExpr::Hole(name) => write!(f, "?{}", name),
ProofExpr::Term(term) => write!(f, "{}", term),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum InferenceRule {
PremiseMatch,
ModusPonens,
ModusTollens,
ConjunctionIntro,
ConjunctionElim,
DisjunctionIntro,
DisjunctionElim,
DoubleNegation,
UniversalInst(String),
UniversalIntro { variable: String, var_type: String },
ExistentialIntro {
witness: String,
witness_type: String,
},
ModalAccess,
ModalGeneralization,
TemporalTransitivity,
TemporalInduction,
TemporalUnfolding,
EventualityProgress,
UntilInduction,
StructuralInduction {
variable: String, ind_type: String, step_var: String, },
Rewrite {
from: ProofTerm,
to: ProofTerm,
},
EqualitySymmetry,
EqualityTransitivity,
Reflexivity,
Axiom,
OracleVerification(String),
ReductioAdAbsurdum,
Contradiction,
ExistentialElim { witness: String },
CaseAnalysis { case_formula: String },
}
#[derive(Debug, Clone)]
pub struct DerivationTree {
pub conclusion: ProofExpr,
pub rule: InferenceRule,
pub premises: Vec<DerivationTree>,
pub depth: usize,
pub substitution: unify::Substitution,
}
impl DerivationTree {
pub fn new(
conclusion: ProofExpr,
rule: InferenceRule,
premises: Vec<DerivationTree>,
) -> Self {
let max_depth = premises.iter().map(|p| p.depth).max().unwrap_or(0);
Self {
conclusion,
rule,
premises,
depth: max_depth + 1,
substitution: unify::Substitution::new(),
}
}
pub fn leaf(conclusion: ProofExpr, rule: InferenceRule) -> Self {
Self::new(conclusion, rule, vec![])
}
pub fn with_substitution(mut self, subst: unify::Substitution) -> Self {
self.substitution = subst;
self
}
pub fn display_tree(&self) -> String {
self.display_recursive(0)
}
fn display_recursive(&self, indent: usize) -> String {
let prefix = " ".repeat(indent);
let rule_name = match &self.rule {
InferenceRule::UniversalInst(var) => format!("UniversalInst({})", var),
InferenceRule::UniversalIntro { variable, var_type } => {
format!("UniversalIntro({}:{})", variable, var_type)
}
InferenceRule::ExistentialIntro { witness, witness_type } => {
format!("∃Intro({}:{})", witness, witness_type)
}
InferenceRule::StructuralInduction { variable, ind_type, step_var } => {
format!("Induction({}:{}, step={})", variable, ind_type, step_var)
}
InferenceRule::OracleVerification(s) => format!("Oracle({})", s),
InferenceRule::Rewrite { from, to } => format!("Rewrite({} → {})", from, to),
InferenceRule::EqualitySymmetry => "EqSymmetry".to_string(),
InferenceRule::EqualityTransitivity => "EqTransitivity".to_string(),
r => format!("{:?}", r),
};
let mut output = format!("{}└─ [{}] {}\n", prefix, rule_name, self.conclusion);
for premise in &self.premises {
output.push_str(&premise.display_recursive(indent + 1));
}
output
}
}
impl fmt::Display for DerivationTree {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.display_tree())
}
}
#[derive(Debug, Clone)]
pub struct ProofGoal {
pub target: ProofExpr,
pub context: Vec<ProofExpr>,
}
impl ProofGoal {
pub fn new(target: ProofExpr) -> Self {
Self {
target,
context: Vec::new(),
}
}
pub fn with_context(target: ProofExpr, context: Vec<ProofExpr>) -> Self {
Self { target, context }
}
}