/// <summary> /// We will use several helper functions to make the main add-production procedure simpler. /// The first one, build-or-share-beta-memory-node, looks for an existing beta memory node that is /// a child of the given parent node. If there is one, it returns it so it can be shared by the new /// production; otherwise the function builds a new one and returns it. This pseudocode assumes /// that beta memories are not indexed; if indexing is used, the procedure would take an extra /// argument specifying which field(s) the memory must be indexed on. /// </summary> /// <param name="parent">The parent.</param> /// <returns></returns> private ReteNode build_or_share_beta_memory_node(ReteNode parent) { if (parent is DummyTopNode) { return parent; } foreach (ReteNode child in parent.Children) { if (child.Type == ReteNodeType.BetaMemory) { return child; } } BetaMemory new_rete = new BetaMemory(); new_rete.Type = ReteNodeType.BetaMemory; new_rete.Parent = parent; new_rete.Label = "B" + (++_next_beta_node); parent.Children.AddToFront(new_rete); update_new_node_with_matches_from_above(new_rete); return new_rete; }
/// <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> /// Whenever a beta memory is informed of a new match (consisting of an existing token and some /// WME), we build a token, add it to the list in the beta memory, and inform each of the beta /// memory's children: /// </summary> /// <param name="node">The node.</param> /// <param name="t">The token.</param> /// <param name="w">The wme.</param> private void beta_memory_left_activation(BetaMemory node, Token t, WME w) { Token new_token = make_token(node, t, w); node.Items.Add(new_token); //The unlinking process changes the underlying collection so we need a new collection... BigList<ReteNode> children = node.Children.Clone(); foreach (ReteNode child in children) { left_activation(child, new_token, null); } }