Beispiel #1
0
        private static string GetNodeLabel(ReteNode reteNode)
        {
            var labelParts = new List <object>();

            labelParts.Add(reteNode.NodeType.ToString());
            switch (reteNode.NodeType)
            {
            case NodeType.Type:
                labelParts.Add(reteNode.OutputType.Name);
                break;

            case NodeType.Selection:
                labelParts.AddRange(reteNode.Expressions.Select(x => $"{x.Value.Body}"));
                break;

            case NodeType.Join:
                labelParts.AddRange(reteNode.Expressions.Select(x => $"{x.Value.Body}"));
                break;

            case NodeType.Aggregate:
                labelParts.Add(reteNode.Properties.Single(x => x.Key == "Name").Value);
                labelParts.AddRange(reteNode.Expressions.Select(x => $"{x.Key}={x.Value.Body}"));
                break;

            case NodeType.Binding:
                labelParts.AddRange(reteNode.Expressions.Select(x => $"{x.Value.Body}"));
                break;

            case NodeType.Rule:
                labelParts.Add(reteNode.Rules.Single().Name);
                labelParts.AddRange(reteNode.Expressions.Select(x => $"{x.Key}={x.Value.Body}"));
                break;
            }

            var label = string.Join("\n", labelParts);

            return(label);
        }
Beispiel #2
0
        /// <summary>
        /// To remove an existing production from the network, we start down at the bottom of the
        /// beta network, at the p-node for that production. The basic idea is to start walking from there
        /// up to the top of the net. At each node, we clean up any tokens it contains, and then get rid of
        /// the node | i.e., remove it from the children or successors lists on its predecessors (its parent
        /// and, for some nodes, its alpha memory as well), and deallocate it. We then move up to the
        /// predecessors. If the alpha memory is not being shared by another production, we deallocate it
        /// too. If the parent is not being shared by another production, then we apply the same procedure
        /// to it | clean up its tokens, etc. | and repeat this until we reach either a node being shared by
        /// some other production, or the top of the beta network.
        /// </summary>
        /// <param name="node">The node.</param>
        private void delete_node_and_any_unused_ancestors(ReteNode node)
        {
            if (node.Type == ReteNodeType.NCC)
            {
                delete_node_and_any_unused_ancestors(node);
            }
            if (node.Type == ReteNodeType.BetaMemory)
            {
                while (((BetaMemory) node).Items.Count > 0)
                {
                    delete_token_and_descendents(((BetaMemory) node).Items[0]);
                }
            }
            if (node.Type == ReteNodeType.Negative)
            {
                while (((NegativeNode) node).Items.Count > 0)
                {
                    delete_token_and_descendents(((NegativeNode) node).Items[0]);
                }
            }
            if (node.Type == ReteNodeType.NCC)
            {
                while (((NCCNode) node).Items.Count > 0)
                {
                    delete_token_and_descendents(((NCCNode) node).Items[0]);
                }
            }
            if (node.Type == ReteNodeType.NCCPartner)
            {
                while (((NCCPartnerNode) node).NewResultBuffer.Count > 0)
                {
                    delete_token_and_descendents(((NCCPartnerNode) node).NewResultBuffer[0]);
                }
            }

            if (node.Type == ReteNodeType.Production)
            {
                ProductionNode pNode = (ProductionNode) node;
                while (pNode.Items.Count > 0)
                {
                    delete_token_and_descendents(pNode.Items[0]);
                    //pNode.items.RemoveFirst();
                }

                //_rules_that_fired.Remove(pNode);
            }

            if (node.Type == ReteNodeType.Join)
            {
                if (((JoinNode) node).IsRightUnlinked == false)
                {
                    ((JoinNode) node).AlphaMemory.Successors.Remove(node);
                }

                if (((JoinNode) node).IsLeftUnlinked == false)
                {
                    node.Parent.Children.Remove(node);
                }

                --((JoinNode) node).AlphaMemory.ReferenceCount;
                if (((JoinNode) node).AlphaMemory.ReferenceCount == 0)
                {
                    delete_alpha_memory(((JoinNode) node).AlphaMemory);
                }
            }

            if (node.Type == ReteNodeType.Negative)
            {
                if (((NegativeNode) node).IsRightUnlinked == false)
                {
                    ((NegativeNode) node).AlphaMemory.Successors.Remove(node);
                }
                --((NegativeNode) node).AlphaMemory.ReferenceCount;
                if (((NegativeNode) node).AlphaMemory.ReferenceCount == 0)
                {
                    delete_alpha_memory(((NegativeNode) node).AlphaMemory);
                }
            }

            if (node.Type == ReteNodeType.Join)
            {
                JoinNode tmpNode = (JoinNode) node;
                ((BetaMemory) tmpNode.Parent).AllChildren.Remove(node);
                if (((BetaMemory) tmpNode.Parent).AllChildren.Count == 0)
                {
                    delete_node_and_any_unused_ancestors(((JoinNode) node).Parent);
                }
            }
            else if (node.Parent.Children.Count == 0)
            {
                delete_node_and_any_unused_ancestors(node.Parent);
            }
        }
Beispiel #3
0
        /// <summary>
        /// The build-or-share-network-for-conditions helper function takes a list of conditions, builds
        /// or shares a network structure for them underneath the given parent node, and returns the
        /// lowermost node in the new-or-shared network. Note that the list of conditions can contain
        /// negative conditions or NCC's, not just positive conditions.
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="conds">The conds.</param>
        /// <param name="earlier_conds">The earlier_conds.</param>
        /// <returns></returns>
        private ReteNode build_or_share_network_for_conditions(ReteNode parent, IEnumerable<LeftHandSideCondition> conds, List<LeftHandSideCondition> earlier_conds)
        {
            List<LeftHandSideCondition> conds_higher_up;

            ReteNode current_node = parent;

            if (earlier_conds == null)
                conds_higher_up = new List<LeftHandSideCondition>();
            else
                conds_higher_up = earlier_conds;

            foreach (LeftHandSideCondition cond in conds)
            {
                if (cond.ConditionType == ConditionType.Positive)
                {
                    current_node = build_or_share_beta_memory_node(current_node);
                    List<TestAtJoinNode> tests = get_join_tests_from_condition(cond, conds_higher_up);
                    AlphaMemory am = build_or_share_alpha_memory(cond);
                    current_node = build_or_share_join_node(current_node as BetaMemory, am, tests);
                }
                else if (cond.ConditionType == ConditionType.Negative)
                {
                    List<TestAtJoinNode> tests = get_join_tests_from_condition(cond, conds_higher_up);
                    AlphaMemory am = build_or_share_alpha_memory(cond);
                    current_node = build_or_share_negative_node(current_node, am, tests);
                }
                else if (cond.ConditionType == ConditionType.NCC)
                {
                    current_node = build_or_share_ncc_nodes(current_node as JoinNode, cond, conds_higher_up);
                }
                else if (cond.ConditionType == ConditionType.Function)
                {
                    current_node = build_builtin_node(current_node, cond, conds_higher_up);
                }
                conds_higher_up.Add(cond);
            }
            return current_node;
        }
Beispiel #4
0
        /// <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 &lt;v&gt; 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;
        }
Beispiel #5
0
        /// <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;
        }
Beispiel #6
0
        /// <summary>
        /// Build_builtin_nodes the specified parent.
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="c">The c.</param>
        /// <param name="earlier_conds">The earlier_conds.</param>
        /// <returns></returns>
        private BuiltinMemory build_builtin_node(ReteNode parent, Condition c, IList<LeftHandSideCondition> earlier_conds)
        {
            BuiltinMemory new_node = new BuiltinMemory(c.ToString());
            new_node.Type = ReteNodeType.Builtin;
            new_node.Parent = parent;

            parent.Children.AddToFront(new_node);

            new_node.Builtin = ((FuncTerm) c.Attribute).Builtin;

            int cntOfEarlierConditions = earlier_conds.Count - 1;

            if (c.Id.TermType == TermType.Variable)
            {
                for (int i = cntOfEarlierConditions; i >= 0; i--)
                {
                    Condition earlier_cond = earlier_conds[i];
                    if (earlier_cond.ConditionType == ConditionType.Positive)
                    {
                        for (int f2 = 0; f2 < 3; f2++)
                        {
                            Variable o = earlier_cond.Fields[f2] as Variable;
                            if (o != null && o.Equals(c.Id))
                            {
                                VariableSubstituter vs = new VariableSubstituter();
                                vs.FieldNumber = f2;
                                vs.NumberOfLevelsUp = (cntOfEarlierConditions - i);
                                vs.BindingPair.Variable = o;
                                new_node.LeftArgument = vs;
                                f2 = 3;
                                i = -1; //escape loop of cntOfEarlierConditions
                            }
                        }
                    }
                }
            }
            else
            {
                new_node.LeftArgument = new ConstantSubstitutor(c.Id);
            }

            if (c.Value.TermType == TermType.Variable)
            {
                for (int i = cntOfEarlierConditions; i >= 0; i--)
                {
                    Condition earlier_cond = earlier_conds[i];
                    if (earlier_cond.ConditionType == ConditionType.Positive)
                    {
                        for (int f2 = 0; f2 < 3; f2++)
                        {
                            Variable o = earlier_cond.Fields[f2] as Variable;
                            if (o != null && o.Equals(c.Value))
                            {
                                VariableSubstituter vs = new VariableSubstituter();
                                vs.FieldNumber = f2;
                                vs.NumberOfLevelsUp = (cntOfEarlierConditions - i);
                                vs.BindingPair.Variable = o;
                                new_node.RightArgument = vs;
                                f2 = 3;
                                i = -1; //escape loop of cntOfEarlierConditions
                            }
                        }
                    }
                }
            }
            else
            {
                new_node.RightArgument = new ConstantSubstitutor(c.Value);
            }

            update_new_node_with_matches_from_above(new_node);
            return new_node;
        }
Beispiel #7
0
 /// <summary>
 /// Adds the production.
 /// </summary>
 /// <param name="new_production">The new_production.</param>
 /// <param name="lhs">The LHS.</param>
 private void AddProduction(ReteNode new_production, IEnumerable<LeftHandSideCondition> lhs)
 {
     ReteNode current_node = build_or_share_network_for_conditions(_dummy_top_node, lhs, null);
     new_production.Parent = current_node;
     current_node.Children.AddToFront(new_production);
     update_new_node_with_matches_from_above(new_production);
 }
 /// <summary>
 /// Called when [rete node] is visited.
 /// </summary>
 /// <param name="node">The node.</param>
 public virtual void OnReteNode(ReteNode node)
 {
 }
Beispiel #9
0
 /// <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("???");
     }
 }
Beispiel #10
0
 /// <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;
 }
Beispiel #11
0
 /// <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);
     }
 }
Beispiel #12
0
 /// <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);
 }
Beispiel #13
0
 private string Id(ReteNode reteNode)
 {
     return($"{reteNode.Id}");
 }
Beispiel #14
0
 /// <summary>
 /// Called when [rete node] is visited.
 /// </summary>
 /// <param name="node">The node.</param>
 public override void OnReteNode(ReteNode node)
 {
     _sb.AppendLine(node.ToString());
 }
 /// <summary>
 /// Called when [rete node] is visited.
 /// </summary>
 /// <param name="node">The node.</param>
 public override void OnReteNode(ReteNode node)
 {
     _sb.AppendLine(node.ToString());
 }
Beispiel #16
0
        /// <summary>
        /// The update-new-node-with-matches-from-above procedure initializes the memory node to store
        /// tokens for any existing matches for the earlier conditions.
        /// </summary>
        /// <remarks>
        /// Finally, we give the update-new-node-with-matches-from-above procedure. This is needed
        /// to ensure that newly added productions are immediately matched against the current working
        /// memory. The procedure's job is to ensure that the given new-node's left-activation procedure is
        /// called with all the existing matches for the previous conditions, so that the new-node can take
        /// any appropriate actions (e.g., a beta memory stores the matches as new tokens, and a p-node
        /// signals new complete matches for the production). How update-new-node-with-matches-from-
        /// above achieves this depends on what kind of node the new-node's parent is. If the parent is a
        /// beta memory (or a node for a negated condition, as we will discuss later), this is straightforward,
        /// since the parent has a list (items) of exactly the matches we want. But if the parent node is a
        /// join node, we want to find these matches, we iterate over the WMEs and tokens in the join node's alpha
        /// and beta memories and perform the join tests on each pair. The pseudocode below uses a trick to
        /// do this: while temporarily pretending the new-node is the only child of the join node, it runs the
        /// join node's right-activation procedure for all the WMEs in its alpha memory; any new matches
        /// will automatically be propagated to the new-node. For a variation of this implementation, see
        /// (Tambe et al., 1988); for a general discussion, see (Lee and Schor, 1992).
        /// </remarks>
        /// <param name="newNode">The new node.</param>
        private void update_new_node_with_matches_from_above(ReteNode newNode)
        {
            ReteNode parent = newNode.Parent;

            switch (parent.Type)
            {
                case ReteNodeType.BetaMemory:
                    BetaMemory tmpBetaMem = (BetaMemory) parent;
                    foreach (Token tok in tmpBetaMem.Items)
                    {
                        left_activation(newNode, tok, new WME());
                    }
                    break;
                case ReteNodeType.Builtin:
                    BuiltinMemory tmpBiMem = (BuiltinMemory) parent;
                    foreach (Token tok in tmpBiMem.Items)
                    {
                        left_activation(newNode, tok, new WME());
                    }
                    break;
                case ReteNodeType.Join:
                    BigList<ReteNode> saved_list_of_children = parent.Children.Clone();
                    parent.Children.Clear();
                    parent.Children.AddToFront(newNode);
                    JoinNode tmpJNode = (JoinNode) parent;
                    if (tmpJNode.AlphaMemory != null)
                    {
                        foreach (ItemInAlphaMemory item in tmpJNode.AlphaMemory.Items)
                        {
                            right_activation(parent, item.WME);
                        }
                    }
                    parent.Children.Clear();
                    parent.Children.AddRange(saved_list_of_children);
                    break;
                case ReteNodeType.Negative:
                    NegativeNode tmpNNode = (NegativeNode) parent;
                    foreach (Token tok in tmpNNode.Items)
                    {
                        if (tok.JoinResults.Count == 0)
                        {
                            left_activation(newNode, tok, null);
                        }
                    }
                    break;
                case ReteNodeType.NCC:
                    NCCNode tmpNCCNode = (NCCNode) parent;
                    foreach (Token tok in tmpNCCNode.Items)
                    {
                        if (tok.NCCResults.Count == 0)
                        {
                            left_activation(newNode, tok, null);
                        }
                    }
                    break;
            }
        }
 /// <summary>
 /// Called when [rete node] is visited.
 /// </summary>
 /// <param name="node">The node.</param>
 public virtual void OnReteNode(ReteNode node)
 {
 }
Beispiel #18
0
 internal ReteLink(ReteNode source, ReteNode target)
 {
     Source = source;
     Target = target;
 }