private bool ChangeEdgeHeadNodeWithoutCleanup(T edgeId, T newHeadNodeId) { // 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 head event node. if (!NodeLookup.TryGetValue(newHeadNodeId, out Node <T, TNodeContent> newHeadNode)) { return(false); } // Remove the connection from the current head node. Node <T, TNodeContent> currentHeadNode = EdgeHeadNodeLookup[edgeId]; currentHeadNode.IncomingEdges.Remove(edgeId); EdgeHeadNodeLookup.Remove(edgeId); // Attach to the new head node. newHeadNode.IncomingEdges.Add(edgeId); EdgeHeadNodeLookup.Add(edgeId, newHeadNode); return(true); }
//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); } }
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); }
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); }
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); }