1 use std::cell::RefCell;
2 use std::collections::hash_map::Entry;
3 use std::rc::Rc;
4 use std::sync::atomic::{AtomicU64, Ordering};
5 
6 use crate::bindings::{BindingManager, Bsp, FollowerId, VariableState};
7 use crate::counter::Counter;
8 use crate::error::PolarResult;
9 use crate::events::QueryEvent;
10 use crate::formatting::ToPolarString;
11 use crate::kb::Bindings;
12 use crate::partial::simplify_bindings;
13 use crate::runnable::Runnable;
14 use crate::terms::{Operation, Operator, Term, Value};
15 use crate::vm::{Goals, PolarVirtualMachine};
16 
17 /// The inverter implements the `not` operation in Polar.
18 ///
19 /// It is a `Runnable` that runs `goals` using `vm`, and returns inverted results.
20 ///
21 /// If the inverter has no results, the inverted query is considered successful.
22 /// If the inverter has results, the new bindings or constraints made during the query
23 /// are inverted, and returned to the outer VM.
24 #[derive(Clone)]
25 pub struct Inverter {
26     vm: PolarVirtualMachine,
27 
28     /// The bsp in VM when the inverter started.
29     /// Used to determine which variables can have added constraints.
30     bsp: Bsp,
31 
32     /// Acculumates new bindings from VM.
33     results: Vec<BindingManager>,
34 
35     /// Constraints to return to parent VM.
36     add_constraints: Rc<RefCell<Bindings>>,
37 
38     /// The ID of the current binding manager follower. Initialized in `run`.
39     follower: Option<FollowerId>,
40 
41     /// An ID to distinguish logging from each inverter, useful when debugging
42     /// queries with multiple nested `not` operations.
43     _debug_id: u64,
44 }
45 
46 static ID: AtomicU64 = AtomicU64::new(0);
47 
48 impl Inverter {
new( vm: &PolarVirtualMachine, goals: Goals, add_constraints: Rc<RefCell<Bindings>>, bsp: Bsp, ) -> Self49     pub fn new(
50         vm: &PolarVirtualMachine,
51         goals: Goals,
52         add_constraints: Rc<RefCell<Bindings>>,
53         bsp: Bsp,
54     ) -> Self {
55         let mut vm = vm.clone_with_goals(goals);
56         vm.inverting = true;
57         Self {
58             vm,
59             bsp,
60             add_constraints,
61             results: vec![],
62             follower: None,
63             _debug_id: ID.fetch_add(1, Ordering::AcqRel),
64         }
65     }
66 }
67 
68 /// Convert a list of new bindings into inverted constraints.
69 ///
70 /// `results` represents a disjunction not OR[result1, result2, ...].
71 ///
72 /// To invert results, we:
73 ///
74 /// 1. Invert each result.
75 /// 2. AND the inverted constraints together.
76 ///
77 /// The output constraints are AND[!result1, !result2, ...].
results_to_constraints(results: Vec<BindingManager>) -> Bindings78 fn results_to_constraints(results: Vec<BindingManager>) -> Bindings {
79     let inverted = results.into_iter().map(invert_partials).collect();
80     let reduced = reduce_constraints(inverted);
81     let simplified = simplify_bindings(reduced, true).unwrap_or_else(Bindings::new);
82 
83     simplified
84         .into_iter()
85         .map(|(k, v)| match v.value() {
86             Value::Expression(_) => (k, v),
87             _ => (
88                 k.clone(),
89                 v.clone_with_value(Value::Expression(op!(Unify, term!(k), v.clone()))),
90             ),
91         })
92         .collect()
93 }
94 
95 /// Invert constraints in `bindings`.
96 ///
97 /// Constraints are inverted by getting each binding as a constraint.
98 /// Simplification is performed, to subsitute bindings and remove temporary variables.
99 /// Then, each simplified expression is inverted.
100 /// A binding of `var` to `val` after simplification is converted into `var != val`.
invert_partials(bindings: BindingManager) -> Bindings101 fn invert_partials(bindings: BindingManager) -> Bindings {
102     let mut new_bindings = Bindings::new();
103 
104     for var in bindings.variables() {
105         let constraint = bindings.get_constraints(&var);
106         new_bindings.insert(var.clone(), term!(constraint));
107     }
108 
109     let simplified = simplify_bindings(new_bindings, true).unwrap_or_else(Bindings::new);
110 
111     simplified
112         .into_iter()
113         .map(|(k, v)| match v.value() {
114             Value::Expression(e) => (k, e.invert().into_term()),
115             _ => (
116                 k.clone(),
117                 term!(op!(And, term!(op!(Neq, term!(k), v.clone())))),
118             ),
119         })
120         .collect::<Bindings>()
121 }
122 
123 /// Takes a vec of bindings and merges constraints on each variable.
reduce_constraints(bindings: Vec<Bindings>) -> Bindings124 fn reduce_constraints(bindings: Vec<Bindings>) -> Bindings {
125     bindings
126         .into_iter()
127         .fold(Bindings::new(), |mut acc, bindings| {
128             bindings
129                 .into_iter()
130                 .for_each(|(var, value)| match acc.entry(var.clone()) {
131                     Entry::Occupied(mut o) => match (o.get().value(), value.value()) {
132                         (Value::Expression(x), Value::Expression(y)) => {
133                             let mut x = x.clone();
134                             x.merge_constraints(y.clone());
135                             o.insert(value.clone_with_value(value!(x)));
136                         }
137                         (existing, new) => panic!(
138                             "Illegal state reached while reducing constraints for {}: {} → {}",
139                             var,
140                             existing.to_polar(),
141                             new.to_polar()
142                         ),
143                     },
144                     Entry::Vacant(v) => {
145                         v.insert(value);
146                     }
147                 });
148             acc
149         })
150 }
151 
152 /// Decide which variables come out of negation. This is hacky.
153 /// HACK: Remove known internal vars like `_value_*` and `_runnable_*`.
154 /// HACK: Do not emit constraints for variables that were unconstrained
155 /// (bound or unbound) before the inversion.
156 ///
157 /// This prevents rules like `f(x) if not (w = 1) and x = w;` from working.
158 /// But, without this, an inverted query like:
159 /// f(x) if not g(x);
160 /// g(y) if y = 1;
161 ///
162 /// ?= f(1);
163 ///
164 /// incorrectly emits constraints on temporaries made when calling `g`,
165 /// like `_y_5`.
166 ///
167 /// We can improve this by explicitly indicating to the simplifier
168 /// which variables are allowed.
filter_inverted_constraints( constraints: Bindings, vm: &PolarVirtualMachine, bsp: Bsp, ) -> Bindings169 fn filter_inverted_constraints(
170     constraints: Bindings,
171     vm: &PolarVirtualMachine,
172     bsp: Bsp,
173 ) -> Bindings {
174     constraints
175         .into_iter()
176         .filter(|(k, _)| {
177             !(matches!(
178                 vm.variable_state_at_point(k, &bsp),
179                 VariableState::Unbound | VariableState::Bound(_)
180             ))
181         })
182         .collect::<Bindings>()
183 }
184 
185 /// A Runnable that runs a query and inverts the results in three ways:
186 ///
187 /// 1. If no results are emitted (indicating failure), return true.
188 /// 2. If at least one result is emitted containing a partial, invert the partial's constraints,
189 ///    pass the inverted partials back to the parent Runnable via a shared BindingStack, and return
190 ///    true.
191 /// 3. In all other cases, return false.
192 impl Runnable for Inverter {
run(&mut self, _: Option<&mut Counter>) -> PolarResult<QueryEvent>193     fn run(&mut self, _: Option<&mut Counter>) -> PolarResult<QueryEvent> {
194         if self.follower.is_none() {
195             // Binding followers are used to collect new bindings made during
196             // the inversion.
197             self.follower = Some(self.vm.add_binding_follower());
198         }
199 
200         loop {
201             // Pass most events through, but collect results and invert them.
202             match self.vm.run(None)? {
203                 QueryEvent::Done { .. } => {
204                     let result = self.results.is_empty();
205                     if !result {
206                         // If there are results, the inversion should usually fail. However,
207                         // if those results have constraints we collect them and pass them
208                         // out to the parent VM.
209                         let constraints =
210                             results_to_constraints(self.results.drain(..).collect::<Vec<_>>());
211                         let mut bsp = Bsp::default();
212                         // Use mem swap to avoid cloning bsps.
213                         std::mem::swap(&mut self.bsp, &mut bsp);
214                         let constraints = filter_inverted_constraints(constraints, &self.vm, bsp);
215 
216                         if !constraints.is_empty() {
217                             // Return inverted constraints to parent VM.
218                             // TODO (dhatch): Would be nice to come up with a better way of doing this.
219                             self.add_constraints.borrow_mut().extend(constraints);
220 
221                             return Ok(QueryEvent::Done { result: true });
222                         }
223                     }
224                     return Ok(QueryEvent::Done { result });
225                 }
226                 QueryEvent::Result { .. } => {
227                     // Retrieve new bindings made when running inverted query.
228                     let binding_follower = self
229                         .vm
230                         .remove_binding_follower(&self.follower.unwrap())
231                         .unwrap();
232                     self.results.push(binding_follower);
233                     self.follower = Some(self.vm.add_binding_follower());
234                 }
235                 event => return Ok(event),
236             }
237         }
238     }
239 
external_question_result(&mut self, call_id: u64, answer: bool) -> PolarResult<()>240     fn external_question_result(&mut self, call_id: u64, answer: bool) -> PolarResult<()> {
241         self.vm.external_question_result(call_id, answer)
242     }
243 
external_call_result(&mut self, call_id: u64, term: Option<Term>) -> PolarResult<()>244     fn external_call_result(&mut self, call_id: u64, term: Option<Term>) -> PolarResult<()> {
245         self.vm.external_call_result(call_id, term)
246     }
247 
debug_command(&mut self, command: &str) -> PolarResult<()>248     fn debug_command(&mut self, command: &str) -> PolarResult<()> {
249         self.vm.debug_command(command)
250     }
251 
clone_runnable(&self) -> Box<dyn Runnable>252     fn clone_runnable(&self) -> Box<dyn Runnable> {
253         Box::new(self.clone())
254     }
255 }
256