Skip to main content

prolog2/predicate_modules/
meta_predicates.rs

1use crate::{
2    heap::{heap::Heap, query_heap::QueryHeap},
3    program::{hypothesis::Hypothesis, predicate_table::PredicateTable},
4    resolution::proof::Proof,
5    Config,
6};
7
8use super::PredReturn;
9
10/// Negation as failure: succeeds if the inner goal cannot be proven
11pub fn not(
12    heap: &mut QueryHeap,
13    hypothesis: &mut Hypothesis,
14    goal: usize,
15    predicate_table: &PredicateTable,
16    config: Config,
17) -> PredReturn {
18    use crate::heap::heap::Tag;
19
20    // The goal is not(X), we want to prove X
21    // Goal may be a Str cell pointing to the Func, or directly a Func cell
22    // We need to find the actual Func cell first, then get the first argument
23
24    // First dereference to handle any Ref indirection
25    let mut func_addr = heap.deref_addr(goal);
26
27    // If it's a Str cell, follow the pointer to the actual Func
28    if let (Tag::Str, pointer) = heap[func_addr] {
29        func_addr = pointer;
30    }
31
32    // Now func_addr points to: Func(2) | Con("not") | InnerGoal
33    // The inner goal is at func_addr + 2
34    // But it might be a Str cell pointing to the actual goal structure
35    let arg_addr = func_addr + 2;
36    let inner_goal = match heap[arg_addr] {
37        (Tag::Str, pointer) => pointer, // Follow Str to actual goal
38        (Tag::Ref, _) => heap.deref_addr(arg_addr), // Follow Ref chain
39        _ => arg_addr,                  // Direct reference
40    };
41
42    // Create a config with learning disabled - we only want to test if the goal
43    // can be proven with the CURRENT hypothesis, not learn new clauses
44    let mut inner_config = config;
45    inner_config.max_clause = 0; // Disable learning by not allowing new clauses
46
47    let inner_heap = heap.branch(1).pop().unwrap();
48
49    // Clone the current hypothesis so the inner proof can use the learned clauses
50    // This is essential: we need to test if the inner goal succeeds given what
51    // we've already learned. If it does, this hypothesis is bad and we backtrack.
52    let hypothesis_clone = hypothesis.clone();
53    let mut inner_proof = Proof::with_hypothesis(inner_heap, &[inner_goal], hypothesis_clone);
54
55    if config.debug {
56        eprintln!(
57            "[NEGATE] {} with {} hypothesis clauses",
58            inner_proof.heap.term_string(inner_goal),
59            inner_proof.hypothesis.len()
60        );
61    }
62
63    // Try to prove the inner goal with the current hypothesis
64    // If it succeeds, not/1 fails (the hypothesis entails something it shouldn't)
65    // If it fails, not/1 succeeds (the hypothesis correctly doesn't entail this)
66    if inner_proof.prove(predicate_table, inner_config) {
67        if config.debug {
68            eprintln!(
69                "[FAILED_TO_NEGATE] {}",
70                inner_proof.heap.term_string(inner_goal)
71            );
72        }
73        PredReturn::False
74    } else {
75        if config.debug {
76            eprintln!(
77                "[NEGATED_THROUGH_FAILURE] {}",
78                inner_proof.heap.term_string(inner_goal)
79            );
80        }
81        PredReturn::True
82    }
83}