Exemplo n.º 1
0
        internal static bool CalculateEventEarliestFinishTimes <T, TResourceId, TActivity, TEvent>
            (this ArrowGraphBuilderBase <T, TResourceId, TActivity, TEvent> arrowGraphBuilder)
            where TActivity : IActivity <T, TResourceId>
            where TEvent : IEvent <T>
            where T : struct, IComparable <T>, IEquatable <T>
            where TResourceId : struct, IComparable <TResourceId>, IEquatable <TResourceId>
        {
            if (arrowGraphBuilder is null)
            {
                throw new ArgumentNullException(nameof(arrowGraphBuilder));
            }
            if (!arrowGraphBuilder.AllDependenciesSatisfied)
            {
                return(false);
            }
            if (arrowGraphBuilder.FindInvalidConstraints().Any())
            {
                return(false);
            }

            var completedNodeIds = new HashSet <T>();
            var remainingNodeIds = new HashSet <T>(arrowGraphBuilder.NodeIds);

            // Make sure the remainingNodeIds contain the Start node.
            if (!remainingNodeIds.Contains(arrowGraphBuilder.StartNode.Id))
            {
                return(false);
            }

            // Complete the Start node first to ensure the completed node IDs
            // contains something.
            Node <T, TEvent> startNode = arrowGraphBuilder.StartNode;

            // Earliest Start Time.
            startNode.Content.EarliestFinishTime = 0;

            completedNodeIds.Add(startNode.Id);
            remainingNodeIds.Remove(startNode.Id);

            // Forward flow algorithm.
            while (remainingNodeIds.Any())
            {
                bool progress = false;

                foreach (T nodeId in remainingNodeIds.ToList())
                {
                    Node <T, TEvent> node = arrowGraphBuilder.Node(nodeId);

                    // Get the incoming edges and the dependency nodes IDs.
                    HashSet <T> incomingEdges     = node.IncomingEdges;
                    var         dependencyNodeIds = new HashSet <T>(incomingEdges.Select(arrowGraphBuilder.EdgeTailNode).Select(x => x.Id));

                    // If calculations for all the dependency nodes have been completed, then use them
                    // to complete the calculations for this node.
                    if (dependencyNodeIds.IsSubsetOf(completedNodeIds))
                    {
                        int earliestFinishTime = 0;

                        foreach (T incomingEdgeId in incomingEdges)
                        {
                            Edge <T, TActivity> incomingEdge         = arrowGraphBuilder.Edge(incomingEdgeId);
                            Node <T, TEvent>    incomingEdgeTailNode = arrowGraphBuilder.EdgeTailNode(incomingEdgeId);

                            if (incomingEdgeTailNode.Content.EarliestFinishTime.HasValue)
                            {
                                int proposedEarliestFinishTime = incomingEdgeTailNode.Content.EarliestFinishTime.Value + incomingEdge.Content.Duration;

                                proposedEarliestFinishTime += incomingEdge.Content.MinimumFreeSlack.GetValueOrDefault();

                                // Augment the earliest finish time artificially (if required).
                                if (proposedEarliestFinishTime > earliestFinishTime)
                                {
                                    earliestFinishTime = proposedEarliestFinishTime;
                                }
                            }

                            if (incomingEdge.Content.MinimumEarliestStartTime.HasValue)
                            {
                                int proposedEarliestFinishTime = incomingEdge.Content.MinimumEarliestStartTime.Value + incomingEdge.Content.Duration;

                                // Augment the earliest finish time artificially (if required).
                                if (proposedEarliestFinishTime > earliestFinishTime)
                                {
                                    earliestFinishTime = proposedEarliestFinishTime;
                                }
                            }

                            if (incomingEdge.Content.MaximumLatestFinishTime.HasValue)
                            {
                                int proposedLatestFinishTime = incomingEdge.Content.MaximumLatestFinishTime.Value;

                                // Diminish the earliest finish time artificially (if required).
                                if (proposedLatestFinishTime < earliestFinishTime)
                                {
                                    earliestFinishTime = proposedLatestFinishTime;
                                }
                            }
                        }

                        node.Content.EarliestFinishTime = earliestFinishTime;
                        completedNodeIds.Add(nodeId);
                        remainingNodeIds.Remove(nodeId);

                        // Note we are making progress.
                        progress = true;
                    }
                }

                // If we have not made any progress then a cycle must exist in
                // the graph and we will not be able to calculate the earliest
                // finish times.
                if (!progress)
                {
                    throw new InvalidOperationException(Properties.Resources.CannotCalculateEarliestFinishTimesDueToCyclicDependency);
                }
            }
            return(true);
        }
Exemplo n.º 2
0
        internal static bool CalculateEventLatestFinishTimes <T, TResourceId, TActivity, TEvent>
            (this ArrowGraphBuilderBase <T, TResourceId, TActivity, TEvent> arrowGraphBuilder)
            where TActivity : IActivity <T, TResourceId>
            where TEvent : IEvent <T>
            where T : struct, IComparable <T>, IEquatable <T>
            where TResourceId : struct, IComparable <TResourceId>, IEquatable <TResourceId>
        {
            if (arrowGraphBuilder is null)
            {
                throw new ArgumentNullException(nameof(arrowGraphBuilder));
            }
            if (!arrowGraphBuilder.AllDependenciesSatisfied)
            {
                return(false);
            }
            if (arrowGraphBuilder.FindInvalidConstraints().Any())
            {
                return(false);
            }
            // Only perform if all events a have earliest finish times.
            if (!arrowGraphBuilder.Nodes.All(x => x.Content.EarliestFinishTime.HasValue))
            {
                return(false);
            }

            var completedNodeIds     = new HashSet <T>();
            var remainingNodeIds     = new HashSet <T>(arrowGraphBuilder.NodeIds);
            Node <T, TEvent> endNode = arrowGraphBuilder.EndNode;

            // Make sure the remainingNodeIds contain the End node.
            if (!remainingNodeIds.Contains(endNode.Id))
            {
                return(false);
            }

            endNode.Content.LatestFinishTime = endNode.Content.EarliestFinishTime;

            if (!endNode.Content.LatestFinishTime.HasValue)
            {
                return(false);
            }

            int endNodeLatestFinishTime = endNode.Content.LatestFinishTime.Value;

            // Complete the End node first to ensure the completed node IDs contains something.
            completedNodeIds.Add(endNode.Id);
            remainingNodeIds.Remove(endNode.Id);

            // Backward flow algorithm.
            while (remainingNodeIds.Any())
            {
                bool progress = false;
                foreach (T nodeId in remainingNodeIds.ToList())
                {
                    Node <T, TEvent> node = arrowGraphBuilder.Node(nodeId);

                    // Get the outgoing edges and the successor nodes IDs.
                    HashSet <T> outgoingEdges    = node.OutgoingEdges;
                    var         successorNodeIds = new HashSet <T>(outgoingEdges.Select(arrowGraphBuilder.EdgeHeadNode).Select(x => x.Id));

                    if (successorNodeIds.IsSubsetOf(completedNodeIds))
                    {
                        int latestFinishTime = endNodeLatestFinishTime;

                        foreach (T outgoingEdgeId in outgoingEdges)
                        {
                            Edge <T, TActivity> outgoingEdge         = arrowGraphBuilder.Edge(outgoingEdgeId);
                            Node <T, TEvent>    outgoingEdgeHeadnode = arrowGraphBuilder.EdgeHeadNode(outgoingEdgeId);

                            if (outgoingEdgeHeadnode.Content.LatestFinishTime.HasValue)
                            {
                                int proposedLatestFinishTime = outgoingEdgeHeadnode.Content.LatestFinishTime.Value - outgoingEdge.Content.Duration;

                                if (proposedLatestFinishTime < latestFinishTime)
                                {
                                    latestFinishTime = proposedLatestFinishTime;
                                }
                            }

                            if (outgoingEdge.Content.MaximumLatestFinishTime.HasValue)
                            {
                                int proposedLatestFinishTime = outgoingEdge.Content.MaximumLatestFinishTime.Value - outgoingEdge.Content.Duration;

                                // Diminish the latest finish time artificially (if required).
                                if (proposedLatestFinishTime < latestFinishTime)
                                {
                                    latestFinishTime = proposedLatestFinishTime;
                                }
                            }
                        }

                        node.Content.LatestFinishTime = latestFinishTime;
                        completedNodeIds.Add(nodeId);
                        remainingNodeIds.Remove(nodeId);

                        // Note we are making progress.
                        progress = true;
                    }
                }
                // If we have not made any progress then a cycle must exist in
                // the graph and we will not be able to calculate the latest
                // finish times.
                if (!progress)
                {
                    throw new InvalidOperationException(Properties.Resources.CannotCalculateLatestFinishTimesDueToCyclicDependency);
                }
            }
            return(true);
        }