use core::fmt::Debug;
use crate::ontology::meta::{Citation, Label, ModulePath, OntologyName, Provenance};
pub type Verdict = Result<Box<dyn Proof>, Box<dyn Counterexample>>;
pub trait Proof: Debug {
fn meta(&self) -> Provenance;
}
pub trait Counterexample: Debug {
fn meta(&self) -> Provenance;
}
#[derive(Debug, Clone)]
pub struct SimpleProof {
meta: Provenance,
}
impl SimpleProof {
pub fn new(meta: Provenance) -> Self {
Self { meta }
}
}
impl Proof for SimpleProof {
fn meta(&self) -> Provenance {
self.meta.clone()
}
}
#[derive(Debug, Clone)]
pub struct SimpleCounterexample {
meta: Provenance,
}
impl SimpleCounterexample {
pub fn new(meta: Provenance) -> Self {
Self { meta }
}
}
impl Counterexample for SimpleCounterexample {
fn meta(&self) -> Provenance {
self.meta.clone()
}
}
#[derive(Debug)]
pub struct CompositeProof {
meta: Provenance,
subproofs: Vec<Box<dyn Proof>>,
}
impl CompositeProof {
pub fn new(meta: Provenance, subproofs: Vec<Box<dyn Proof>>) -> Self {
Self { meta, subproofs }
}
pub fn subproofs(&self) -> &[Box<dyn Proof>] {
&self.subproofs
}
}
impl Proof for CompositeProof {
fn meta(&self) -> Provenance {
self.meta.clone()
}
}
#[derive(Debug)]
pub struct CompositeCounterexample {
meta: Provenance,
passed: Vec<Box<dyn Proof>>,
failed: Vec<Box<dyn Counterexample>>,
}
impl CompositeCounterexample {
pub fn new(
meta: Provenance,
passed: Vec<Box<dyn Proof>>,
failed: Vec<Box<dyn Counterexample>>,
) -> Self {
Self {
meta,
passed,
failed,
}
}
pub fn passed(&self) -> &[Box<dyn Proof>] {
&self.passed
}
pub fn failed(&self) -> &[Box<dyn Counterexample>] {
&self.failed
}
}
impl Counterexample for CompositeCounterexample {
fn meta(&self) -> Provenance {
self.meta.clone()
}
}
pub fn combine_verdicts(meta: Provenance, subverdicts: Vec<Verdict>) -> Verdict {
let mut passed: Vec<Box<dyn Proof>> = Vec::new();
let mut failed: Vec<Box<dyn Counterexample>> = Vec::new();
for v in subverdicts {
match v {
Ok(p) => passed.push(p),
Err(c) => failed.push(c),
}
}
if failed.is_empty() {
Ok(Box::new(CompositeProof::new(meta, passed)))
} else {
Err(Box::new(CompositeCounterexample::new(meta, passed, failed)))
}
}
pub fn proof_meta(name: &'static str, citation: &'static str) -> Provenance {
Provenance {
name: OntologyName::new_static(name),
description: Label::new_static(name),
citation: Citation::parse_static(citation),
module_path: ModulePath::new_static(module_path!()),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[crate::praxis_value(Explainable)]
#[test]
fn simple_proof_carries_meta() {
let p = SimpleProof::new(proof_meta("TestClaim", "Tarski (1941)"));
assert_eq!(p.meta().name.as_str(), "TestClaim");
}
#[crate::praxis_value(Explainable)]
#[test]
fn simple_counterexample_carries_meta() {
let c = SimpleCounterexample::new(proof_meta("FailedClaim", "Lewis (1973)"));
assert_eq!(c.meta().name.as_str(), "FailedClaim");
}
#[crate::praxis_value(Verifiable)]
#[test]
fn combine_all_ok_yields_ok_composite() {
let subs: Vec<Verdict> = vec![
Ok(Box::new(SimpleProof::new(proof_meta("A", "X")))),
Ok(Box::new(SimpleProof::new(proof_meta("B", "X")))),
];
match combine_verdicts(proof_meta("Composite", "X"), subs) {
Ok(_) => {}
Err(_) => panic!("expected composite proof"),
}
}
#[crate::praxis_value(Honest, Verifiable)]
#[test]
fn combine_with_any_err_yields_err_composite() {
let subs: Vec<Verdict> = vec![
Ok(Box::new(SimpleProof::new(proof_meta("A", "X")))),
Err(Box::new(SimpleCounterexample::new(proof_meta("B", "X")))),
];
match combine_verdicts(proof_meta("Composite", "X"), subs) {
Ok(_) => panic!("expected composite counterexample"),
Err(c) => assert!(!c.meta().name.as_str().is_empty()),
}
}
#[crate::praxis_value(Verifiable)]
#[test]
fn proof_is_dyn_safe() {
let _p: Box<dyn Proof> = Box::new(SimpleProof::new(proof_meta("X", "Y")));
}
#[crate::praxis_value(Verifiable)]
#[test]
fn counterexample_is_dyn_safe() {
let _c: Box<dyn Counterexample> = Box::new(SimpleCounterexample::new(proof_meta("X", "Y")));
}
}