/// <summary> /// When adding a production that uses an NCC, we use the build-or-share-ncc-nodes function. /// Most of the work in this function is done by the helper function build-or-share-network-for- /// conditions, which builds or shares the whole subnetwork for the subconditions of the NCC. The /// rest of the build-or-share-ncc-nodes function then builds or shares the NCC and NCC partner /// nodes. /// </summary> /// <param name="parent">The parent.</param> /// <param name="c">The c.</param> /// <param name="earlier_conds">The earlier_conds.</param> /// <returns></returns> private ReteNode build_or_share_ncc_nodes(JoinNode parent, Condition c, List<LeftHandSideCondition> earlier_conds) { ReteNode bottom_of_subnetwork = build_or_share_network_for_conditions(parent, c.SubConditions, earlier_conds); foreach (ReteNode child in parent.Children) { if (child.Type == ReteNodeType.NCC && ((NCCNode) child).Partner.Parent == bottom_of_subnetwork) { return child; } } NCCNode new_node = new NCCNode(); NCCPartnerNode new_partner = new NCCPartnerNode(); new_node.Type = ReteNodeType.NCC; // "NCC"; new_partner.Type = ReteNodeType.NCCPartner; // "NCC-partner"; parent.IsHeadOfSubNetwork = true; new_node.Parent = parent; parent.Children.Add(new_node); new_partner.Parent = bottom_of_subnetwork; bottom_of_subnetwork.Children.AddToFront(new_partner); new_node.Partner = new_partner; new_partner.NCCNode = new_node; new_partner.NumberOfConjuncts = c.SubConditions.Count; update_new_node_with_matches_from_above(new_node); update_new_node_with_matches_from_above(new_partner); return new_node; }
/// <summary> /// The next helper function is similar, except it handles join nodes rather than beta memory /// nodes. The two additional arguments specify the alpha memory to which the join node must /// be attached and the variable binding consistency checks it must perform. Note that there is no /// need to call update-new-node-with-matches-from-above in this case, because a join node does not /// store any tokens, and a newly created join node has no children onto which join results should /// be passed. /// </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_join_node(BetaMemory parent, AlphaMemory am, ICollection<TestAtJoinNode> tests) { foreach (ReteNode child in parent.AllChildren) { if (child.Type == ReteNodeType.Join) { JoinNode childJoinNode = (JoinNode) child; if (childJoinNode.AlphaMemory == am) { if (childJoinNode.Tests.Count == 0 && tests.Count == 0) { return child; } else { if (childJoinNode.Tests.Count == tests.Count) { bool testsMatch = true; foreach (TestAtJoinNode test in tests) { if (childJoinNode.Tests.Contains(test) == false) { testsMatch = false; continue; } } if (testsMatch) { return child; } //Need to compare tests... throw new ApplicationException("Unhandled..."); } } } } } JoinNode new_node = new JoinNode(); new_node.Type = ReteNodeType.Join; // "join"; new_node.Parent = parent; parent.Children.AddToFront(new_node); parent.AllChildren.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); // *** Right Unlinking *** if (parent.Items.Count == 0) { am.Successors.Remove(new_node); new_node.IsRightUnlinked = true; } else if (am.Items.Count == 0) { if ((parent is DummyTopNode) == false) { parent.Children.Remove(new_node); new_node.IsRightUnlinked = true; } } // *** End Right Unlinking *** return new_node; }
/// <summary> /// Relink_to_beta_memories the specified node. /// </summary> /// <param name="node">The node.</param> private void relink_to_beta_memory(JoinNode node) { node.Parent.Children.AddToFront(node); node.IsLeftUnlinked = false; }
/// <summary> /// Relink_to_alpha_memories the specified node. /// </summary> /// <param name="node">The node.</param> private void relink_to_alpha_memory(JoinNode node) { JoinNode ancestor = (JoinNode) node.NearestAncestorWithSameAmem; while (ancestor != null && ancestor.IsRightUnlinked) { ancestor = (JoinNode) 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> /// Upon a right activation (when a new WME w is added to the alpha memory), we look /// through the beta memory and find any token(s) t for which all these t-versus-w tests succeed. /// Any successful (t;w) combinations are passed on to the join node's children. /// </summary> /// <param name="node">The node.</param> /// <param name="w">The w.</param> private void join_node_right_activation(JoinNode node, WME w) { // *** Left Unlinking *** if (node.IsLeftUnlinked) { relink_to_beta_memory(node); if (((BetaMemory) node.Parent).Items.Count == 0) { node.AlphaMemory.Successors.Remove(node); node.IsRightUnlinked = true; } } // *** End Left Unlinking *** foreach (Token t in ((BetaMemory) node.Parent).Items) { if (perform_join_tests(node.Tests, t, w)) { foreach (ReteNode child in node.Children) { left_activation(child, t, w); } } } }
/// <summary> /// Upon a left activation (when a new token t is added to the beta memory), we look through the /// alpha memory and find any WME(s) w for which all these t-versus-w tests succeed. Again, any /// successful (t;w) combinations are passed on to the node's children: /// </summary> /// <param name="node">The node.</param> /// <param name="t">The t.</param> private void join_node_left_activation(JoinNode node, Token t) { // *** Right Unlinking *** if (node.IsRightUnlinked) { relink_to_alpha_memory(node); // *** Left Unlinking *** if (node.AlphaMemory.Items.Count == 0) { node.Parent.Children.Remove(node); node.IsLeftUnlinked = true; } // *** End Left Unlinking *** } // *** End Right Unlinking *** foreach (ItemInAlphaMemory item in node.AlphaMemory.Items) { if (perform_join_tests(node.Tests, t, item.WME)) { foreach (ReteNode child in node.Children) { left_activation(child, t, item.WME); } } } }