Where a node stands, given what is known.
Every test up to here holds.
8 Holds,
A test up to here is known to fail. Nothing downstream can fire.
10 Fails,
A join node: everything left requires, and one more test. left is
another join, or None when this is a rule's first test.
Index into [Network::alphas].
31 pub alpha: usize,
A rule's place in the network: the join that holds when the rule does.
One per distinct test, however many rules use it.
48 pub alphas: Vec<Test<D>>,
Shared by every rule that begins with the same tests.
50 pub joins: Vec<Join>,
A rule ends the query outright.
62 End(D::End),
No rule has anything left to do and nothing more can be learned: the query is over, and what to show is in the notes of the rules that hold.
68impl<D: Domain> Network<D> {
Merges the rules: one alpha per distinct test, and for each rule a chain of joins, shared by rules that begin with the same tests.
Panics
On a rule with no tests, which holds always and so cannot be placed
in a network of tests. [crate::load] refuses one before it gets here.
76 pub fn compile(rules: &[Rule<'_, D>]) -> Self { 77 let mut network = Network { alphas: Vec::new(), joins: Vec::new(), terminals: Vec::new() }; 78 for rule in rules { 79 let mut left = None; 80 for (depth, test) in rule.when.iter().enumerate() { 81 let alpha = network.alphas.iter().position(|known| known == test).unwrap_or_else(|| { 82 network.alphas.push(*test); 83 network.alphas.len() - 1 84 }); 85 let join = Join { left, alpha, depth: depth + 1 }; 86 left = Some(network.joins.iter().position(|known| *known == join).unwrap_or_else(|| { 87 network.joins.push(join); 88 network.joins.len() - 1 89 })); 90 } 91 let join = left.expect("a rule has at least one test"); 92 network.terminals.push(Terminal { name: rule.name.to_owned(), join, then: rule.then }); 93 } 94 network 95 }
97 pub fn alpha(&self, alpha: usize, known: &Known<D>) -> State { 98 let test = self.alphas[alpha]; 99 match (test, known.get(test.fact())) { 100 (_, None) => State::Waits, 101 (Test::Known(_), Some(_)) => State::Holds, 102 (Test::Is(_, wanted), Some(value)) if wanted == value => State::Holds, 103 (Test::Is(..), Some(_)) => State::Fails, 104 } 105 } 106 107 pub fn join(&self, join: usize, known: &Known<D>) -> State { 108 let Join { left, alpha, .. } = self.joins[join]; 109 let here = self.alpha(alpha, known); 110 left.map_or(here, |left| self.join(left, known).and(here)) 111 }
The facts a join's tests are on, first test first.
What to do, given what is known, and the rule that says so (its index
in [Network::terminals]), when one does.
A rule that holds decides, in rule order; an effect whose fact is already known has been done and is passed over. If no rule decides, every fact a source supplies that a rule not yet failed is waiting on is wanted, and they are asked for together.
128 pub fn decide(&self, known: &Known<D>) -> (Option<usize>, Next<D>) { 129 for (index, terminal) in self.terminals.iter().enumerate() { 130 if self.join(terminal.join, known) != State::Holds { 131 continue; 132 } 133 match terminal.then { 134 Then::End(end) => return (Some(index), Next::End(end)), 135 Then::Do(effect) if known.get(D::teaches(effect)).is_none() => { 136 return (Some(index), Next::Do(effect)); 137 } 138 Then::Do(_) | Then::Note(_) => {} 139 } 140 } 141 let mut wanted: Vec<D::Fact> = self 142 .terminals 143 .iter() 144 .filter(|terminal| self.join(terminal.join, known) == State::Waits) 145 .flat_map(|terminal| self.facts(terminal.join)) 146 .filter(|fact| D::asked_for(*fact) && known.get(*fact).is_none()) 147 .collect(); 148 wanted.sort(); 149 wanted.dedup(); 150 (None, if wanted.is_empty() { Next::Done } else { Next::Ask(wanted) }) 151 }
What to do, given what is known.
The rules that hold, in rule order.
The names of the rules that hold, in rule order.
The joins and alphas that a rule that holds stands on: what, of everything known, turned out to matter.
170 pub fn used(&self, known: &Known<D>) -> (Vec<bool>, Vec<bool>) { 171 let mut joins = vec![false; self.joins.len()]; 172 let mut alphas = vec![false; self.alphas.len()]; 173 for terminal in &self.terminals { 174 if self.join(terminal.join, known) != State::Holds { 175 continue; 176 } 177 let mut at = Some(terminal.join); 178 while let Some(join) = at { 179 joins[join] = true; 180 alphas[self.joins[join].alpha] = true; 181 at = self.joins[join].left; 182 } 183 } 184 (joins, alphas) 185 }
What rule rule (an index into [Network::terminals]) stands on,
given what is known: for a trace.
189 pub fn explain(&self, rule: usize, known: &Known<D>) -> Firing<D> { 190 let terminal = &self.terminals[rule]; 191 let on = self.facts(terminal.join).into_iter().filter_map(|fact| known.get(fact).map(|value| (fact, value))).collect(); 192 Firing { rule, name: terminal.name.clone(), then: terminal.then, on } 193 } 194}