use super::*;
fn p() -> TLExpr {
TLExpr::pred("P", vec![])
}
fn q() -> TLExpr {
TLExpr::pred("Q", vec![])
}
fn r() -> TLExpr {
TLExpr::pred("R", vec![])
}
#[test]
fn test_literal_creation() {
let lit_pos = Literal::positive(p());
assert!(lit_pos.is_positive());
assert!(!lit_pos.is_negative());
let lit_neg = Literal::negative(p());
assert!(!lit_neg.is_positive());
assert!(lit_neg.is_negative());
}
#[test]
fn test_literal_complementary() {
let lit_pos = Literal::positive(p());
let lit_neg = Literal::negative(p());
assert!(lit_pos.is_complementary(&lit_neg));
assert!(lit_neg.is_complementary(&lit_pos));
assert!(!lit_pos.is_complementary(&lit_pos));
}
#[test]
fn test_clause_empty() {
let clause = Clause::empty();
assert!(clause.is_empty());
assert_eq!(clause.len(), 0);
}
#[test]
fn test_clause_unit() {
let clause = Clause::unit(Literal::positive(p()));
assert!(clause.is_unit());
assert_eq!(clause.len(), 1);
}
#[test]
fn test_clause_tautology() {
let clause = Clause::from_literals(vec![Literal::positive(p()), Literal::negative(p())]);
assert!(clause.is_tautology());
}
#[test]
fn test_resolution_basic() {
let mut prover = ResolutionProver::new();
prover.add_clause(Clause::unit(Literal::positive(p())));
prover.add_clause(Clause::unit(Literal::negative(p())));
let result = prover.prove();
assert!(result.is_unsatisfiable());
}
#[test]
fn test_resolution_modus_ponens() {
let mut prover = ResolutionProver::new();
prover.add_clause(Clause::unit(Literal::positive(p())));
prover.add_clause(Clause::from_literals(vec![
Literal::negative(p()),
Literal::positive(q()),
]));
prover.add_clause(Clause::unit(Literal::negative(q())));
let result = prover.prove();
assert!(result.is_unsatisfiable());
}
#[test]
fn test_resolution_satisfiable() {
let mut prover = ResolutionProver::new();
prover.add_clause(Clause::unit(Literal::positive(p())));
prover.add_clause(Clause::unit(Literal::positive(q())));
let result = prover.prove();
assert!(!result.is_unsatisfiable());
}
#[test]
fn test_cnf_conversion_and() {
let expr = TLExpr::and(p(), q());
let clauses = to_cnf(&expr).expect("unwrap");
assert_eq!(clauses.len(), 2);
assert!(clauses.iter().all(|c| c.is_unit()));
}
#[test]
fn test_cnf_conversion_or() {
let expr = TLExpr::or(p(), q());
let clauses = to_cnf(&expr).expect("unwrap");
assert_eq!(clauses.len(), 1);
assert_eq!(clauses[0].len(), 2);
}
#[test]
fn test_resolution_strategy_unit() {
let mut prover =
ResolutionProver::with_strategy(ResolutionStrategy::UnitResolution { max_steps: 100 });
prover.add_clause(Clause::unit(Literal::positive(p())));
prover.add_clause(Clause::unit(Literal::negative(p())));
let result = prover.prove();
assert!(result.is_unsatisfiable());
}
#[test]
fn test_resolution_three_clauses() {
let mut prover = ResolutionProver::new();
prover.add_clause(Clause::from_literals(vec![
Literal::positive(p()),
Literal::positive(q()),
]));
prover.add_clause(Clause::from_literals(vec![
Literal::negative(p()),
Literal::positive(r()),
]));
prover.add_clause(Clause::unit(Literal::negative(q())));
prover.add_clause(Clause::unit(Literal::negative(r())));
let result = prover.prove();
assert!(result.is_unsatisfiable());
}
#[test]
fn test_horn_clause_detection() {
let clause = Clause::from_literals(vec![
Literal::negative(p()),
Literal::negative(q()),
Literal::positive(r()),
]);
assert!(clause.is_horn());
let non_horn = Clause::from_literals(vec![Literal::positive(p()), Literal::positive(q())]);
assert!(!non_horn.is_horn());
}
#[test]
fn test_prover_stats() {
let mut prover = ResolutionProver::new();
prover.add_clause(Clause::unit(Literal::positive(p())));
prover.add_clause(Clause::unit(Literal::negative(p())));
let result = prover.prove();
assert!(prover.stats.empty_clause_found);
assert!(prover.stats.resolution_steps > 0);
assert!(result.is_unsatisfiable());
}