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