Skip to main content

prolog2/predicate_modules/
meta_predicates.rs

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