/// <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); } } }
/// <summary> /// Builtin_node_left_activations the specified memory. /// </summary> /// <param name="memory">The memory.</param> /// <param name="tok">The tok.</param> /// <param name="w">The w.</param> private void builtin_node_left_activation(BuiltinMemory memory, Token tok, WME w) { Token new_token = make_token(memory, tok, w); memory.Items.AddToFront(new_token); if (memory.PerformEvaluation(new_token)) { foreach (ReteNode child in memory.Children) { left_activation(child, new_token, w); } } }
/// <summary> /// Adds the fact. /// </summary> /// <param name="fact">The fact to the initial facts list.</param> public void AddFact(WME fact) { _initialFacts.Add(fact); }
/// <summary> /// Now, to remove a WME, we just remove it from each alpha memory containing it (these /// alpha memories are now conveniently on a list) and call the helper routine delete-token-and- /// descendents to delete all the tokens involving it (all the necessary "root" tokens involving it are /// also conveniently on a list): /// </summary> /// <param name="wme">The wme.</param> public void RemoveWME(WME wme) { int pos = _working_memory.IndexOf(wme); if (pos < 0) return; WME w = _working_memory[pos]; foreach (ItemInAlphaMemory item in w.AlphaMemoryItems) { item.AlphaMemory.Items.Remove(item); // *** Left Unlinking *** if (item.AlphaMemory.Items.Count == 0) { foreach (ReteNode node in item.AlphaMemory.Successors) { if (node.Type == ReteNodeType.Join) { node.Parent.Children.Remove(node); ((JoinNode) node).IsLeftUnlinked = true; } } } // *** End Left Unlinking *** } while (w.Tokens.Count > 0) { delete_token_and_descendents(w.Tokens[0]); } foreach (NegativeJoinResult jr in w.NegativeJoinResults) { jr.Owner.JoinResults.Remove(jr); if (jr.Owner.JoinResults.Count == 0) { foreach (ReteNode child in jr.Owner.Node.Children) { left_activation(child, jr.Owner, null); } } } _working_memory.Remove(w); }
/// <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> /// P_node_activations the specified node. /// </summary> /// <param name="node">The node.</param> /// <param name="tok">The tok.</param> /// <param name="w">The w.</param> private void p_node_activation(ProductionNode node, Token tok, WME w) { Token new_token = make_token(node, tok, w); node.Items.AddToFront(new_token); int lhsCnt = node.Production.Lhs.Count - 1; foreach (RightHandSideCondition rhsCondition in node.Production.Rhs) { WME newfact = new WME(); for (int f = 0; f < 3; f++) { Term term = rhsCondition.Fields[f]; if (term.TermType == TermType.Variable) { for (int i = lhsCnt; i >= 0; i--) { Condition lhsCondition = node.Production.Lhs[i]; if (lhsCondition.ConditionType == ConditionType.Positive) { int pos = lhsCondition.Contains(term); if (pos >= 0) { Token tok2 = new_token.GetTokenUp(lhsCnt - i); newfact.Fields[f] = tok2.WME[pos]; i = -1; } } } } else { newfact.Fields[f] = term; } } Activation newact = new Activation(newfact, rhsCondition.ConditionType); if (node.Production.InferredFacts.Contains(newact) == false) { node.Production.InferredFacts.Add(newact); } } }
/// <summary> /// Controls the activation flow based on node type /// </summary> /// <param name="child">The child.</param> /// <param name="w">The w.</param> private void right_activation(ReteNode child, WME w) { switch (child.Type) { case ReteNodeType.Join: join_node_right_activation(child as JoinNode, w); break; case ReteNodeType.Negative: negative_node_right_activation(child as NegativeNode, w); break; default: throw new ApplicationException("???"); } }
/// <summary> /// Initializes a new instance of the <see cref="DummyTopToken"/> class. /// </summary> public DummyTopToken() { _wme = new WME("null"); }
/// <summary> /// Binds the RHS. /// </summary> private void BindRHS(List<Activation> items) { int lhsCnt = _lhs.Count - 1; foreach (Activation act in items) { foreach (RightHandSideCondition condition in _rhs) { WME newfact = new WME(); for (int f = 0; f < 3; f++) { Term term = condition.Fields[f]; if (term.TermType == TermType.Variable) { for (int i = lhsCnt; i >= 0; i--) { Condition rh = _lhs[i]; if (rh.ConditionType == ConditionType.Positive) { int pos = rh.Contains(term); if (pos >= 0) { newfact.Fields[f] = act.InferredFact[pos]; i = -1; } } } } else { newfact.Fields[f] = term; } } Activation newact = new Activation(newfact, condition.ConditionType); if (_inferredFacts.Contains(newact) == false) { _inferredFacts.Add(newact); } } } }
/// <summary> /// Initializes a new instance of the <see cref="Activation"/> class. /// </summary> /// <param name="prod">The prod.</param> /// <param name="tok">The tok.</param> public Activation(WME prod, ConditionType tok) { _fact = prod; _conditionType = tok; }
/// <summary> /// Sets the specified fact. /// </summary> /// <param name="fact">The fact.</param> private void Set(WME fact) { IFactProvider eo = fact.Identifier.Value as IFactProvider; if (eo == null) { return; } try { eo.SetProperty(fact.Attribute.Value.ToString(), fact.Value.Value); _actionsTaken.Add(fact); } catch { _actionsSkipped.Add(fact); } }
/// <summary> /// Retracts the specified fact. /// </summary> /// <param name="fact">The fact.</param> private void Retract(WME fact) { _inferredFacts.Remove(fact); _rete.RemoveWME(fact); }
/// <summary> /// Asserts the specified fact. /// </summary> /// <param name="fact">The fact.</param> private void Assert(WME fact) { _inferredFacts.Add(fact); _rete.AddWME(fact); }
/// <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> /// 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> /// Performs the specified tests. /// </summary> /// <param name="tests">The tests.</param> /// <param name="t">The t.</param> /// <param name="w">The w.</param> /// <returns></returns> private bool perform_join_tests(IEnumerable<TestAtJoinNode> tests, Token t, WME w) { foreach (TestAtJoinNode this_test in tests) { Term arg1 = w[this_test.FieldOfArg1]; WME wme2 = t[this_test.NumberOfLevelsUp]; Term arg2 = wme2[this_test.FieldOfArg2]; if (this_test.Evaluator.Evaluate(arg1, arg2) == false) return false; } return true; }
/// <summary> /// Left_activations the specified new_node. /// </summary> /// <param name="new_node">The new_node.</param> /// <param name="tok">The tok.</param> /// <param name="w">The w.</param> private void left_activation(ReteNode new_node, Token tok, WME w) { switch (new_node.Type) { case ReteNodeType.BetaMemory: beta_memory_left_activation(new_node as BetaMemory, tok, w); break; case ReteNodeType.Negative: negative_node_left_activation(new_node as NegativeNode, tok, w); break; case ReteNodeType.Builtin: builtin_node_left_activation(new_node as BuiltinMemory, tok, w); break; case ReteNodeType.NCCPartner: ncc_partner_node_left_activation(new_node as NCCPartnerNode, tok, w); break; case ReteNodeType.NCC: ncc_node_left_activation(new_node as NCCNode, tok, w); break; case ReteNodeType.Join: join_node_left_activation(new_node as JoinNode, tok); break; case ReteNodeType.Production: p_node_activation(new_node as ProductionNode, tok, w); break; case ReteNodeType.Mutex: mutex_node_activation(new_node as MutexNode, tok, w); break; case ReteNodeType.Aggregator: aggregator_node_activation(new_node as AggregatorNode, tok, w); break; default: throw new ApplicationException("Unknown left_activation type: " + new_node.GetType().Name); } }
/// <summary> /// Adds the WME. /// </summary> /// <param name="w">The WME.</param> public void AddWME(WME w) { int v1 = w.Fields[0].GetHashCode(); int v2 = w.Fields[1].GetHashCode(); int v3 = w.Fields[2].GetHashCode(); _working_memory.Add(w); AlphaMemory alpha_mem; alpha_mem = lookup_in_hash_table(0, 0, 0); if (alpha_mem != null) alpha_memory_activation(alpha_mem, w); alpha_mem = lookup_in_hash_table(0, 0, v3); if (alpha_mem != null) alpha_memory_activation(alpha_mem, w); alpha_mem = lookup_in_hash_table(0, v2, 0); if (alpha_mem != null) alpha_memory_activation(alpha_mem, w); alpha_mem = lookup_in_hash_table(0, v2, v3); if (alpha_mem != null) alpha_memory_activation(alpha_mem, w); alpha_mem = lookup_in_hash_table(v1, 0, 0); if (alpha_mem != null) alpha_memory_activation(alpha_mem, w); alpha_mem = lookup_in_hash_table(v1, 0, v3); if (alpha_mem != null) alpha_memory_activation(alpha_mem, w); alpha_mem = lookup_in_hash_table(v1, v2, 0); if (alpha_mem != null) alpha_memory_activation(alpha_mem, w); alpha_mem = lookup_in_hash_table(v1, v2, v3); if (alpha_mem != null) alpha_memory_activation(alpha_mem, w); }
/// <summary> /// Similarly, whenever a new token tok = ht;wi is added to a beta memory, we add tok to /// t.children and to w.tokens. We also fill in the new node field on the token. To simplify our /// pseudocode, it is convenient to define a "helper" function make-token which builds a new token /// and initializes its various fields as necessary for tree-based removal. Although we write this as /// a separate function, it would normally be coded "inline" for efficiency. /// </summary> /// <param name="node">The node.</param> /// <param name="parent">The parent.</param> /// <param name="w">The w.</param> /// <returns></returns> private Token make_token(ReteNode node, Token parent, WME w) { Token tok = new Token(); tok.Parent = parent; tok.WME = w; tok.Node = node; parent.Children.AddToFront(tok); if (w != null) { w.Tokens.AddToFront(tok); } return tok; }
/// <summary> /// Modifies an existing WME. /// </summary> /// <param name="oldWME">The old WME.</param> /// <param name="newWME">The new WME.</param> public virtual void ModifyWME(WME oldWME, WME newWME) { RemoveWME(oldWME); AddWME(newWME); }
/// <summary> /// Mutex_node_activations the specified node. /// </summary> /// <param name="node">The node.</param> /// <param name="tok">The tok.</param> /// <param name="w">The w.</param> private void mutex_node_activation(MutexNode node, Token tok, WME w) { Token new_token = make_token(node, tok, w); node.Items.Add(new_token); }
private void aggregator_node_activation(AggregatorNode node, Token tok, WME w) { Token new_token = make_token(node, tok, w); node.Items.AddToFront(new_token); }
/// <summary> /// Ncc_node_left_activations the specified node. /// </summary> /// <remarks> /// Our ncc-node-left-activation procedure is similar to the negative-node-left-activation procedure /// (page 42). In both cases, we need to find the join results for a new token. For negative /// nodes, we compute these join results by scanning the WMEs in an alpha memory and performing /// the join tests on them. For NCC nodes, the join results have already been computed by the /// subnetwork, so we simply look at the new-result-buffer in the NCC partner node to find them. /// </remarks> /// <param name="node">The node.</param> /// <param name="t">The t.</param> /// <param name="w">The w.</param> private void ncc_node_left_activation(NCCNode node, Token t, WME w) { Token new_token = make_token(node, t, w); node.Items.AddToFront(new_token); foreach (Token result in node.Partner.NewResultBuffer) { node.Partner.NewResultBuffer.Remove(result); new_token.NCCResults.AddToFront(result); result.Owner = new_token; } if (new_token.NCCResults.Count == 0) { foreach (ReteNode child in node.Children) { left_activation(child, new_token, null); } } }
/// <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); } }
/// <summary> /// Ncc_partner_node_left_activations the specified partner. /// </summary> /// <remarks> /// To handle an NCC partner node (left) activation, we take the new match from the subnetwork /// and build a "result" token to store it. (The pseudocode for this is shown in Figure 2.8.) Next we /// try to find the appropriate owner token in the NCC node's memory. (There might be one there, /// if this is a new subconditions match for an old preceding-conditions match, or there might not /// be one there, if this is an initial subconditions match for a new preceding-conditions match.) /// If we find an appropriate owner token, then we add the new result token to its local memory; /// if the number of results in the local memory changes from zero to one | indicating that the /// NCC 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 owner token. (This is /// similar to the negative-node-right-activation procedure on page 43.) On the other hand, if there /// isn't an appropriate owner token already in the NCC node's memory, then this new result token /// is placed in the new-result-buffer. (The NCC node will soon be activated and collect any new /// results from the buffer.) /// </remarks> /// <param name="partner">The partner.</param> /// <param name="t">The t.</param> /// <param name="w">The w.</param> private void ncc_partner_node_left_activation(NCCPartnerNode partner, Token t, WME w) { NCCNode nccNode = partner.NCCNode; Token new_result = make_token(partner, t, w); Token owners_t = t; WME owners_w = w; for (int i = 0; i < partner.NumberOfConjuncts; i++) { owners_w = owners_t.WME; owners_t = owners_t.Parent; } foreach (Token owner in nccNode.Items) { if (owner.Parent == owners_t && owner.WME == owners_w) { owner.NCCResults.Add(new_result); new_result.Owner = owner; delete_descendents_of_token(owner); } else { partner.NewResultBuffer.AddToFront(new_result); } } }
/// <summary> /// Check_constant_testses the specified w. /// </summary> /// <param name="w">The w.</param> /// <param name="c">The c.</param> /// <returns></returns> private bool check_constant_tests(WME w, Condition c) { foreach (Term o in c.Fields) { if ((o is Variable) == false) { if (w.Contains(o) == false) return false; } } return true; }