/// <summary> /// Delete_alpha_memories the specified amem. /// </summary> /// <param name="amem">The amem.</param> private void delete_alpha_memory(AlphaMemory amem) { Console.WriteLine(amem); throw new Exception(); }
/// <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> /// 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> /// Finally, we have a helper function for creating a new alpha memory for a given condition, /// or finding an existing one to share. The implementation of this function depends on what type /// of alpha net implementation is used. If we use a traditional data /// ow network, as described in /// Section 2.2.1, then we simply start at the top of the alpha network and work our way down, /// sharing or building new constant test nodes: /// </summary> /// <param name="c">The c.</param> /// <returns></returns> private AlphaMemory build_or_share_alpha_memory(Condition c) { AlphaMemory am; int attributeHash = c.Attribute.GetHashCode(); int valueHash = c.Value.GetHashCode(); int idHash = c.Id.GetHashCode(); if (_alpha_network.ContainsKey(attributeHash)) { Dictionary<int, Dictionary<int, AlphaMemory>> valueDict = _alpha_network[attributeHash]; if (valueDict.ContainsKey(valueHash)) { Dictionary<int, AlphaMemory> idDict = valueDict[valueHash]; if (idDict.ContainsKey(idHash)) { am = idDict[idHash]; am.Conditions.Add(c.ToString()); return am; } else //no idHash { am = new AlphaMemory(); am.ReferenceCount = 0; am.Label = "A" + (++_next_alpha_node); am.Conditions.Add(c.ToString()); idDict.Add(idHash, am); } } else //no valueHash { am = new AlphaMemory(); am.ReferenceCount = 0; am.Label = "A" + (++_next_alpha_node); am.Conditions.Add(c.ToString()); Dictionary<int, AlphaMemory> idDict = new Dictionary<int, AlphaMemory>(THIRD_LEVEL_ALPHA_HASH_INITIAL_SIZE); idDict.Add(idHash, am); valueDict.Add(valueHash, idDict); } } else //no attribHash { am = new AlphaMemory(); am.ReferenceCount = 0; am.Label = "A" + (++_next_alpha_node); am.Conditions.Add(c.ToString()); Dictionary<int, AlphaMemory> idDict = new Dictionary<int, AlphaMemory>(THIRD_LEVEL_ALPHA_HASH_INITIAL_SIZE); idDict.Add(idHash, am); Dictionary<int, Dictionary<int, AlphaMemory>> valueDict = new Dictionary<int, Dictionary<int, AlphaMemory>>(SECOND_LEVEL_ALPHA_HASH_INITIAL_SIZE); valueDict.Add(valueHash, idDict); _alpha_network.Add(attributeHash, valueDict); } foreach (WME w in _working_memory) { if (check_constant_tests(w, c)) { alpha_memory_activation(am, w); } } return am; }
/// <summary> /// Whenever a new WME is filtered through the alpha network and reaches an alpha memory, we /// simply add it to the list of other WMEs in that memory, and inform each of the attached join /// nodes: /// </summary> /// <param name="node">The node.</param> /// <param name="w">The w.</param> private void alpha_memory_activation(AlphaMemory node, WME w) { ItemInAlphaMemory new_item = new ItemInAlphaMemory(); new_item.WME = w; new_item.AlphaMemory = node; node.Items.Add(new_item); w.AlphaMemoryItems.AddToFront(new_item); // *** Neo Integration *** if (w.Value.TermType == TermType.EntityObject) { IFactProvider eo = (IFactProvider) w.Value.Value; if (eo.MyFactsHaveBeenAsserted == false) { foreach (WME wme in eo.GenerateFactsForRelatedObject(w.Attribute.Value.ToString(), w.Identifier.Value as IFactProvider)) { AddWME(wme); } } } if (w.Value.TermType == TermType.ObjectRelation) { ObjectRelationBase orb = (ObjectRelationBase) w.Value.Value; foreach (RulesEnabledEntityObject eo in orb) { if (eo.MyFactsHaveBeenAsserted == false) { foreach (WME wme in eo.GenerateFactsForObjectInCollection(w.Attribute.Value.ToString(), orb)) { AddWME(wme); } } } } // *** End Neo Integration *** //The unlinking process changes the underlying collection so we need a new collection... BigList<ReteNode> successors = node.Successors.Clone(); foreach (ReteNode successor in successors) { right_activation(successor, w); } }
/// <summary> /// For right unlinking, we need to initialize the nearest-ancestor-with-same-amem fields on /// newly-created join and negative nodes. The find-nearest-ancestor-with-same-amem procedure /// finds the appropriate value. It starts at a given node and walks up the beta network, returning /// the first node it finds that uses a given alpha memory. Note that this node may be in the /// subnetwork for a conjunctive negation. /// </summary> /// <param name="node">The node.</param> /// <param name="am">The am.</param> /// <returns></returns> private ReteNode find_nearest_ancestor_with_same_amem(ReteNode node, AlphaMemory am) { if (node is DummyTopNode) { return null; } if (node.Type == ReteNodeType.Dummy) { return null; } if (node.Type == ReteNodeType.Join) { if (((JoinNode) node).AlphaMemory == am) { return node; } } if (node.Type == ReteNodeType.Negative) { if (((NegativeNode) node).AlphaMemory == am) { return node; } } if (node.Type == ReteNodeType.NCC) { return find_nearest_ancestor_with_same_amem(((NCCNode) node).Partner.Parent, am); } return find_nearest_ancestor_with_same_amem(node.Parent, am); }