/// <summary> /// The function for creating new negative nodes is similar to the ones for creating beta memories /// and join nodes. However, one additional consideration is important with negative conditions, /// and also with conjunctive negations. Any time there is a variable <v> which is tested in a negative /// condition and bound in one or more other (positive) conditions, at least one of these positive /// conditions must come before the negative condition. Recall that when we add a production to /// the network, the network-construction routines are given a list of its conditions in some order. If /// all conditions are positive, any order will work. Negative conditions require the aforementioned /// constraint on the order, though, because negative nodes need to be able to access the appropriate /// variable bindings in tokens, and the tokens "seen" by negative nodes indicate only variable /// bindings from earlier conditions, i.e., conditions higher up in the network. /// </summary> /// <param name="parent">The parent.</param> /// <param name="am">The am.</param> /// <param name="tests">The tests.</param> /// <returns></returns> private ReteNode build_or_share_negative_node(ReteNode parent, AlphaMemory am, ICollection<TestAtJoinNode> tests) { foreach (ReteNode child in parent.Children) { if (child.Type == ReteNodeType.Negative) { NegativeNode negativenodeChild = (NegativeNode) child; if (negativenodeChild.AlphaMemory == am) { if (negativenodeChild.Tests.Count == 0 && tests.Count == 0) { return child; } else { //Need to compare tests... throw new ApplicationException("Unhandled..."); } } } } NegativeNode new_node = new NegativeNode(); new_node.Type = ReteNodeType.Negative; // "negative"; new_node.Parent = parent; parent.Children.AddToFront(new_node); foreach (TestAtJoinNode test in tests) { new_node.Tests.Add(test); } new_node.AlphaMemory = am; am.Successors.AddToFront(new_node); ++am.ReferenceCount; new_node.NearestAncestorWithSameAmem = find_nearest_ancestor_with_same_amem(parent, am); update_new_node_with_matches_from_above(new_node); // *** Right Unlinking *** if (new_node.Items.Count == 0) { am.Successors.Remove(new_node); new_node.IsRightUnlinked = true; } // *** End Right Unlinking *** return new_node; }
/// <summary> /// On a right activation of a negative node (when a WME is added to its alpha memory), /// we look for any tokens in its memory consistent with the WME; for each such token, we add /// this WME to its local result memory. Also, if the number of results changes from zero to /// one - indicating that the negated condition was previously true but is now false - then we /// call the delete-descendents-of-token helper function to delete any tokens lower in the network /// that depend on this token. /// </summary> /// <param name="node">The node.</param> /// <param name="w">The w.</param> private void negative_node_right_activation(NegativeNode node, WME w) { foreach (Token t in node.Items) { if (perform_join_tests(node.Tests, t, w)) { if (t.JoinResults.Count == 0) { delete_descendents_of_token(t); } NegativeJoinResult jr = new NegativeJoinResult(); jr.Owner = t; jr.WME = w; t.JoinResults.AddToFront(jr); w.NegativeJoinResults.AddToFront(jr); } } }
/// <summary> /// Relink_to_alpha_memories the specified node. /// </summary> /// <param name="node">The node.</param> private void relink_to_alpha_memory(NegativeNode node) { NegativeNode ancestor = (NegativeNode) node.NearestAncestorWithSameAmem; while (ancestor != null && ancestor.IsRightUnlinked) { ancestor = (NegativeNode) ancestor.NearestAncestorWithSameAmem; } if (ancestor != null) { int pos = node.AlphaMemory.Successors.IndexOf(ancestor); node.AlphaMemory.Successors.Insert(pos, node); } else { node.AlphaMemory.Successors.Add(node); } node.IsRightUnlinked = false; }
/// <summary> /// On a left activation /// (when there is a new match for all the earlier conditions), we build and store a new token, perform /// a join for the token, store the join results in the token structure, and pass the token onto any /// successor nodes if there were no join results. /// </summary> /// <param name="node">The node.</param> /// <param name="t">The t.</param> /// <param name="w">The w.</param> private void negative_node_left_activation(NegativeNode node, Token t, WME w) { // *** Right Unlinking *** if (node.Items.Count == 0) relink_to_alpha_memory(node); // *** End Right Unlinking *** Token new_token = make_token(node, t, w); node.Items.AddToFront(new_token); foreach (ItemInAlphaMemory item in node.AlphaMemory.Items) { if (perform_join_tests(node.Tests, new_token, item.WME)) { NegativeJoinResult jr = new NegativeJoinResult(); jr.Owner = new_token; jr.WME = w; new_token.JoinResults.AddToFront(jr); w.NegativeJoinResults.AddToFront(jr); } } if (new_token.JoinResults.Count == 0) { foreach (ReteNode child in node.Children) { left_activation(child, new_token, null); } } }