예제 #1
0
        private bool ChangeEdgeTailNodeWithoutCleanup(T edgeId, T newTailNodeId)
        {
            // Do not attend this unless all dependencies are satisfied.
            if (!AllDependenciesSatisfied)
            {
                return(false);
            }
            // Retrieve the activity edge.
            if (!EdgeLookup.TryGetValue(edgeId, out Edge <T, TEdgeContent> _))
            {
                return(false);
            }
            // Retrieve the new tail event node.
            if (!NodeLookup.TryGetValue(newTailNodeId, out Node <T, TNodeContent> newTailNode))
            {
                return(false);
            }

            // Remove the connection from the current tail node.
            Node <T, TNodeContent> oldTailNode = EdgeTailNodeLookup[edgeId];

            oldTailNode.OutgoingEdges.Remove(edgeId);
            EdgeTailNodeLookup.Remove(edgeId);

            // Attach to the new tail node.
            newTailNode.OutgoingEdges.Add(edgeId);
            EdgeTailNodeLookup.Add(edgeId, newTailNode);
            return(true);
        }
예제 #2
0
        //private void RemoveParallelIncomingEdges(Node<T, TActivity> node)
        //{
        //    if (node is null)
        //    {
        //        throw new ArgumentNullException(nameof(node));
        //    }
        //    // Clean up any dummy edges that are parallel coming into the head node.
        //    if (node.NodeType == NodeType.Start || node.NodeType == NodeType.Isolated)
        //    {
        //        return;
        //    }
        //    // First, find the tail nodes that connect to this node via ALL edges.
        //    // In a vertex graph, all edges should be removable.
        //    var tailNodeParallelEdgesLookup = new Dictionary<T, HashSet<T>>();
        //    IEnumerable<T> removableIncomingEdgeIds =
        //        node.IncomingEdges.Select(x => EdgeLookup[x])
        //        .Where(x => x.Content.CanBeRemoved)
        //        .Select(x => x.Id);

        //    foreach (T incomingEdgeId in removableIncomingEdgeIds)
        //    {
        //        T tailNodeId = EdgeTailNodeLookup[incomingEdgeId].Id;
        //        if (!tailNodeParallelEdgesLookup.TryGetValue(tailNodeId, out HashSet<T> edgeIds))
        //        {
        //            edgeIds = new HashSet<T>();
        //            tailNodeParallelEdgesLookup.Add(tailNodeId, edgeIds);
        //        }
        //        if (!edgeIds.Contains(incomingEdgeId))
        //        {
        //            edgeIds.Add(incomingEdgeId);
        //        }
        //    }

        //    // Now find the tail nodes that connect to this node via multiple edges.
        //    IList<T> setsOfMoreThanOneEdge =
        //        tailNodeParallelEdgesLookup
        //        .Where(x => x.Value.Count > 1)
        //        .Select(x => x.Key)
        //        .ToList();

        //    foreach (T tailNodeId in setsOfMoreThanOneEdge)
        //    {
        //        Node<T, TActivity> tailNode = EdgeTailNodeLookup[tailNodeId];
        //        IList<T> edgeIds = tailNodeParallelEdgesLookup[tailNodeId].ToList();
        //        int length = edgeIds.Count;
        //        // Leave one edge behind.
        //        for (int i = 1; i < length; i++)
        //        {
        //            T edgeId = edgeIds[i];

        //            // Remove the edge from the tail node.
        //            tailNode.OutgoingEdges.Remove(edgeId);
        //            EdgeTailNodeLookup.Remove(edgeId);

        //            // Remove the edge from the head node.
        //            node.IncomingEdges.Remove(edgeId);
        //            EdgeHeadNodeLookup.Remove(edgeId);

        //            // Remove the edge completely.
        //            EdgeLookup.Remove(edgeId);
        //        }
        //    }
        //}

        private void RemoveRedundantIncomingEdges(T nodeId, IDictionary <T, HashSet <T> > nodeIdAncestorLookup)
        {
            if (nodeIdAncestorLookup is null)
            {
                throw new ArgumentNullException(nameof(nodeIdAncestorLookup));
            }
            Node <T, TActivity> node = NodeLookup[nodeId];

            if (node.NodeType == NodeType.Start || node.NodeType == NodeType.Isolated)
            {
                return;
            }

            // Go through all the incoming edges and collate the
            // ancestors of their tail nodes.
            var tailNodeAncestors = new HashSet <T>(node.IncomingEdges
                                                    .Select(x => EdgeTailNodeLookup[x].Id)
                                                    .SelectMany(x => nodeIdAncestorLookup[x]));

            // Go through the incoming edges and remove any that connect
            // directly to any ancestors of the edges' tail nodes.
            // In a vertex graph, all edges should be removable.
            foreach (T edgeId in node.IncomingEdges.Select(x => EdgeLookup[x]).Where(x => x.Content.CanBeRemoved).Select(x => x.Id).ToList())
            {
                Node <T, TActivity> tailNode = EdgeTailNodeLookup[edgeId];
                T edgeTailNodeId             = tailNode.Id;
                if (tailNodeAncestors.Contains(edgeTailNodeId))
                {
                    // Remove the edge from the tail node.
                    tailNode.OutgoingEdges.Remove(edgeId);
                    EdgeTailNodeLookup.Remove(edgeId);

                    // Remove the edge from the node itself.
                    node.IncomingEdges.Remove(edgeId);
                    EdgeHeadNodeLookup.Remove(edgeId);

                    // Remove the edge completely.
                    EdgeLookup.Remove(edgeId);
                }
            }

            // Go through all the remaining incoming edges and repeat.
            foreach (T tailNodeId in node.IncomingEdges.Select(x => EdgeTailNodeLookup[x].Id).ToList())
            {
                RemoveRedundantIncomingEdges(tailNodeId, nodeIdAncestorLookup);
            }
        }
예제 #3
0
        public bool RemoveDummyActivity(T activityId)
        {
            // Retrieve the activity's edge.
            if (!EdgeLookup.TryGetValue(activityId, out Edge <T, TActivity> edge))
            {
                return(false);
            }
            if (!edge.Content.IsDummy)
            {
                return(false);
            }
            if (!edge.Content.CanBeRemoved)
            {
                return(false);
            }

            Node <T, TEvent> tailNode = EdgeTailNodeLookup[activityId];
            Node <T, TEvent> headNode = EdgeHeadNodeLookup[activityId];

            // Check to make sure that no other edges will be made parallel
            // by removing this edge.
            if (HaveDecendantOrAncestorOverlap(tailNode, headNode) &&
                !ShareMoreThanOneEdge(tailNode, headNode))
            {
                return(false);
            }

            // Remove the edge from the tail node.
            tailNode.OutgoingEdges.Remove(activityId);
            EdgeTailNodeLookup.Remove(activityId);

            // Remove the edge from the head node.
            headNode.IncomingEdges.Remove(activityId);
            EdgeHeadNodeLookup.Remove(activityId);

            // Remove the edge completely.
            EdgeLookup.Remove(activityId);

            // If the head node is not the End node, and it has no more incoming
            // edges, then transfer the head node's outgoing edges to the tail node.
            if (headNode.NodeType != NodeType.End &&
                headNode.NodeType != NodeType.Isolated &&
                !headNode.IncomingEdges.Any())
            {
                IList <T> headNodeOutgoingEdgeIds = headNode.OutgoingEdges.ToList();
                foreach (T headNodeOutgoingEdgeId in headNodeOutgoingEdgeIds)
                {
                    bool changeTailSuccess = ChangeEdgeTailNode(headNodeOutgoingEdgeId, tailNode.Id);
                    if (!changeTailSuccess)
                    {
                        throw new InvalidOperationException($@"Unable to change tail node of edge {headNodeOutgoingEdgeId} to node {tailNode.Id} when removing dummy activity {activityId}");
                    }
                }
            }
            else if (tailNode.NodeType != NodeType.Start &&
                     tailNode.NodeType != NodeType.Isolated &&
                     !tailNode.OutgoingEdges.Any())
            {
                // If the tail node is not the Start node, and it has no more outgoing
                // edges, then transfer the tail node's incoming edges to the head node.
                IList <T> tailNodeIncomingEdgeIds = tailNode.IncomingEdges.ToList();
                foreach (T tailNodeIncomingEdgeId in tailNodeIncomingEdgeIds)
                {
                    bool changeHeadSuccess = ChangeEdgeHeadNode(tailNodeIncomingEdgeId, headNode.Id);
                    if (!changeHeadSuccess)
                    {
                        throw new InvalidOperationException($@"Unable to change head node of edge {tailNodeIncomingEdgeId} to node {headNode.Id} when removing dummy activity {activityId}");
                    }
                }
            }
            return(true);
        }
예제 #4
0
        public override bool RemoveActivityDependencies(T activityId, HashSet <T> dependencies)
        {
            if (dependencies is null)
            {
                throw new ArgumentNullException(nameof(dependencies));
            }
            if (!NodeLookup.TryGetValue(activityId, out Node <T, TActivity> node))
            {
                return(false);
            }
            if (!dependencies.Any())
            {
                return(true);
            }

            RemoveUnsatisfiedSuccessorActivityDependencies(activityId, dependencies);

            if (node.NodeType == NodeType.Start ||
                node.NodeType == NodeType.Isolated)
            {
                return(true);
            }

            // If any dependencies currently exist, remove them.
            var       existingDependencyLookup = new HashSet <T>(NodeLookup.Keys.Intersect(dependencies));
            IList <T> incomingEdgeIds          = node.IncomingEdges.ToList();
            int       length = incomingEdgeIds.Count;

            for (int i = 0; i < length; i++)
            {
                T edgeId = incomingEdgeIds[i];
                Node <T, TActivity> tailNode = EdgeTailNodeLookup[edgeId];

                if (!existingDependencyLookup.Contains(tailNode.Id))
                {
                    continue;
                }

                // Remove the edge from the tail node.
                tailNode.OutgoingEdges.Remove(edgeId);
                EdgeTailNodeLookup.Remove(edgeId);

                if (!tailNode.OutgoingEdges.Any())
                {
                    if (tailNode.NodeType == NodeType.Normal)
                    {
                        tailNode.SetNodeType(NodeType.End);
                    }
                    else if (tailNode.NodeType == NodeType.Start)
                    {
                        tailNode.SetNodeType(NodeType.Isolated);
                    }
                }

                // Remove the edge from the head node.
                node.IncomingEdges.Remove(edgeId);
                EdgeHeadNodeLookup.Remove(edgeId);

                // Remove the edge completely.
                EdgeLookup.Remove(edgeId);
            }

            if (!node.IncomingEdges.Any())
            {
                if (node.NodeType == NodeType.Normal)
                {
                    node.SetNodeType(NodeType.Start);
                }
                else if (node.NodeType == NodeType.End)
                {
                    node.SetNodeType(NodeType.Isolated);
                }
            }

            return(true);
        }
예제 #5
0
        public override bool RemoveActivity(T activityId)
        {
            // Retrieve the activity's node.
            if (!NodeLookup.TryGetValue(activityId, out Node <T, TActivity> node))
            {
                return(false);
            }
            if (!node.Content.CanBeRemoved)
            {
                return(false);
            }

            RemoveUnsatisfiedSuccessorActivity(activityId);
            NodeLookup.Remove(node.Id);

            if (node.NodeType == NodeType.Isolated)
            {
                return(true);
            }

            if (node.NodeType == NodeType.End ||
                node.NodeType == NodeType.Normal)
            {
                IList <T> incomingEdgeIds = node.IncomingEdges.ToList();
                int       length          = incomingEdgeIds.Count;
                for (int i = 0; i < length; i++)
                {
                    T edgeId = incomingEdgeIds[i];
                    Node <T, TActivity> tailNode = EdgeTailNodeLookup[edgeId];

                    // Remove the edge from the tail node.
                    tailNode.OutgoingEdges.Remove(edgeId);
                    EdgeTailNodeLookup.Remove(edgeId);

                    if (!tailNode.OutgoingEdges.Any())
                    {
                        if (tailNode.NodeType == NodeType.Normal)
                        {
                            tailNode.SetNodeType(NodeType.End);
                        }
                        else if (tailNode.NodeType == NodeType.Start)
                        {
                            tailNode.SetNodeType(NodeType.Isolated);
                        }
                    }

                    // Remove the edge from the head node.
                    node.IncomingEdges.Remove(edgeId);
                    EdgeHeadNodeLookup.Remove(edgeId);

                    if (!node.IncomingEdges.Any())
                    {
                        if (node.NodeType == NodeType.Normal)
                        {
                            node.SetNodeType(NodeType.Start);
                        }
                        else if (node.NodeType == NodeType.End)
                        {
                            node.SetNodeType(NodeType.Isolated);
                        }
                    }

                    // Remove the edge completely.
                    EdgeLookup.Remove(edgeId);
                }
            }

            if (node.NodeType == NodeType.Start ||
                node.NodeType == NodeType.Normal)
            {
                IList <T> outgoingEdgeIds = node.OutgoingEdges.ToList();
                int       length          = outgoingEdgeIds.Count;
                for (int i = 0; i < length; i++)
                {
                    T edgeId = outgoingEdgeIds[i];
                    Node <T, TActivity> headNode = EdgeHeadNodeLookup[edgeId];

                    // Remove the edge from the head node.
                    headNode.IncomingEdges.Remove(edgeId);
                    EdgeHeadNodeLookup.Remove(edgeId);

                    if (!headNode.IncomingEdges.Any())
                    {
                        if (headNode.NodeType == NodeType.Normal)
                        {
                            headNode.SetNodeType(NodeType.Start);
                        }
                        else if (headNode.NodeType == NodeType.End)
                        {
                            headNode.SetNodeType(NodeType.Isolated);
                        }
                    }

                    // Remove the edge from the tail node.
                    node.OutgoingEdges.Remove(edgeId);
                    EdgeTailNodeLookup.Remove(edgeId);

                    if (!node.OutgoingEdges.Any())
                    {
                        if (node.NodeType == NodeType.Normal)
                        {
                            node.SetNodeType(NodeType.End);
                        }
                        else if (node.NodeType == NodeType.Start)
                        {
                            node.SetNodeType(NodeType.Isolated);
                        }
                    }

                    // Remove the edge completely.
                    EdgeLookup.Remove(edgeId);
                }
            }
            return(true);
        }