use crate::alethe::{AletheProof, AletheRule};
use crate::theory::{TheoryProof, TheoryRule, TheoryStepId};
use std::collections::HashMap;
#[allow(dead_code)]
#[must_use]
pub fn theory_to_alethe(theory_proof: &TheoryProof) -> AletheProof {
let mut alethe = AletheProof::new();
let mut step_map: HashMap<TheoryStepId, u32> = HashMap::new();
for step in theory_proof.steps() {
let alethe_premises: Vec<u32> = step
.premises
.iter()
.filter_map(|&p| step_map.get(&p).copied())
.collect();
let alethe_rule = map_theory_rule_to_alethe(&step.rule);
let alethe_idx = if step.premises.is_empty() && is_assumption(&step.rule) {
alethe.assume(&step.conclusion.0)
} else {
let clause = vec![step.conclusion.0.clone()];
let args: Vec<String> = step.args.iter().map(|a| a.0.clone()).collect();
alethe.step(clause, alethe_rule, alethe_premises, args)
};
step_map.insert(step.id, alethe_idx);
}
alethe
}
#[allow(dead_code)]
fn map_theory_rule_to_alethe(rule: &TheoryRule) -> AletheRule {
match rule {
TheoryRule::Refl => AletheRule::Refl,
TheoryRule::Symm => AletheRule::Symm,
TheoryRule::Trans => AletheRule::Trans,
TheoryRule::Cong => AletheRule::Cong,
TheoryRule::LaGeneric => AletheRule::LaGeneric,
TheoryRule::LaTighten => AletheRule::LaTightening,
TheoryRule::LaTotality => AletheRule::LaTotality,
TheoryRule::LaDiseq => AletheRule::LaDisequality,
TheoryRule::ArrReadWrite1 => AletheRule::ArrayRowSame,
TheoryRule::ArrReadWrite2 => AletheRule::ArrayRowDiff,
TheoryRule::ArrExt => AletheRule::ArrayExt,
TheoryRule::TheoryConflict => AletheRule::ThLemma,
TheoryRule::TheoryProp => AletheRule::ThLemma,
_ => AletheRule::ThLemma,
}
}
#[allow(dead_code)]
fn is_assumption(rule: &TheoryRule) -> bool {
matches!(
rule,
TheoryRule::Custom(_)
| TheoryRule::Refl
| TheoryRule::ArrReadWrite1
| TheoryRule::ArrConst
| TheoryRule::LaTotality
)
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ConversionStats {
pub source_steps: usize,
pub target_steps: usize,
pub assumptions: usize,
pub inferences: usize,
}
#[allow(dead_code)]
impl ConversionStats {
#[must_use]
pub fn compute(source: &TheoryProof, target: &AletheProof) -> Self {
let assumptions = source
.steps()
.iter()
.filter(|s| s.premises.is_empty())
.count();
Self {
source_steps: source.len(),
target_steps: target.len(),
assumptions,
inferences: source.len() - assumptions,
}
}
}
#[allow(dead_code)]
#[must_use]
pub fn theory_to_alethe_with_stats(theory_proof: &TheoryProof) -> (AletheProof, ConversionStats) {
let alethe = theory_to_alethe(theory_proof);
let stats = ConversionStats::compute(theory_proof, &alethe);
(alethe, stats)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::theory::ProofTerm;
#[test]
fn test_theory_to_alethe_simple() {
let mut theory = TheoryProof::new();
theory.refl("x");
let alethe = theory_to_alethe(&theory);
assert_eq!(alethe.len(), 1);
}
#[test]
fn test_theory_to_alethe_transitivity() {
let mut theory = TheoryProof::new();
let s1 = theory.add_axiom(TheoryRule::Custom("assert".into()), "(= a b)");
let s2 = theory.add_axiom(TheoryRule::Custom("assert".into()), "(= b c)");
theory.trans(s1, s2, "a", "c");
let alethe = theory_to_alethe(&theory);
assert_eq!(alethe.len(), 3);
}
#[test]
fn test_theory_to_alethe_arithmetic() {
let mut theory = TheoryProof::new();
let s1 = theory.add_axiom(TheoryRule::Custom("bound".into()), "(>= x 10)");
let s2 = theory.add_axiom(TheoryRule::Custom("bound".into()), "(<= x 5)");
theory.farkas(
vec![s1, s2],
&[ProofTerm("1".into()), ProofTerm("1".into())],
);
let alethe = theory_to_alethe(&theory);
assert_eq!(alethe.len(), 3);
}
#[test]
fn test_conversion_stats() {
let mut theory = TheoryProof::new();
theory.add_axiom(TheoryRule::Custom("assert".into()), "(= x y)");
theory.add_axiom(TheoryRule::Custom("assert".into()), "(= y z)");
theory.refl("w");
let alethe = theory_to_alethe(&theory);
let stats = ConversionStats::compute(&theory, &alethe);
assert_eq!(stats.source_steps, 3);
assert_eq!(stats.assumptions, 3);
assert_eq!(stats.inferences, 0);
}
#[test]
fn test_theory_to_alethe_with_stats() {
let mut theory = TheoryProof::new();
let s1 = theory.add_axiom(TheoryRule::Custom("assert".into()), "(= a b)");
let s2 = theory.add_axiom(TheoryRule::Custom("assert".into()), "(= b c)");
theory.trans(s1, s2, "a", "c");
let (alethe, stats) = theory_to_alethe_with_stats(&theory);
assert_eq!(alethe.len(), 3);
assert_eq!(stats.source_steps, 3);
assert_eq!(stats.assumptions, 2);
assert_eq!(stats.inferences, 1);
}
#[test]
fn test_map_theory_rule_to_alethe() {
assert_eq!(
map_theory_rule_to_alethe(&TheoryRule::Refl),
AletheRule::Refl
);
assert_eq!(
map_theory_rule_to_alethe(&TheoryRule::Trans),
AletheRule::Trans
);
assert_eq!(
map_theory_rule_to_alethe(&TheoryRule::LaGeneric),
AletheRule::LaGeneric
);
assert_eq!(
map_theory_rule_to_alethe(&TheoryRule::ArrReadWrite1),
AletheRule::ArrayRowSame
);
}
#[test]
fn test_is_assumption() {
assert!(is_assumption(&TheoryRule::Refl));
assert!(is_assumption(&TheoryRule::Custom("test".into())));
assert!(!is_assumption(&TheoryRule::Trans));
assert!(!is_assumption(&TheoryRule::Cong));
}
}