Пример #1
0
        /// <summary>
        /// Runs the algorithm until the problem is solved or memory/time is exhausted
        /// </summary>
        /// <returns>True if solved</returns>
        public virtual bool Solve()
        {
            int initialEstimate = ((WorldState)openList.Peek()).h;

            int        lastF    = -1;
            WorldState lastNode = null;
            bool       debug    = false;

            while (openList.Count > 0)
            {
                // Check if max time has been exceeded
                if (runner.ElapsedMilliseconds() > Constants.MAX_TIME)
                {
                    totalCost = Constants.TIMEOUT_COST;
                    Console.WriteLine("Out of time");
                    this.Clear();
                    return(false);
                }

                var currentNode = (WorldState)openList.Remove();

                Debug.Assert(currentNode.g + currentNode.h >= lastF,
                             "A* node with decreasing F: " + (currentNode.g + currentNode.h) + " < " + lastF + ".");
                // FIXME: Better to use the whole rich comparison. Save the last node and use compareTo.
                //        The only time a node is allowed to be smaller than the last one is if it's the goal.
                //        Is that even true? A child is smaller than its parent if it's on the heuristic path to the goal because its g i larger.
                lastF    = currentNode.g + currentNode.h;
                lastNode = currentNode;

                // Calculate expansion delay
                int expansionDelay = this.expanded - currentNode.expandedCountWhenGenerated - 1; // -1 to make the delay zero when a node is expanded immediately after being generated.
                maxExpansionDelay = Math.Max(maxExpansionDelay, expansionDelay);

                // Check if node is the goal, or knows how to get to it
                if (currentNode.GoalTest())
                {
                    this.totalCost     = currentNode.GetGoalCost();
                    this.singleCosts   = currentNode.GetSingleCosts();
                    this.solution      = currentNode.GetPlan();
                    this.singlePlans   = currentNode.GetSinglePlans();
                    this.solutionDepth = this.totalCost - initialEstimate;
                    this.Clear();
                    return(true);
                }

                // Expand
                Expand(currentNode);
                expanded++;
            }

            totalCost = Constants.NO_SOLUTION_COST;
            this.Clear();
            return(false);
        }
Пример #2
0
        public bool Solve()
        {
            //this.SetGlobals(); // Again, because we might be resuming a search that was stopped.

            int initialEstimate = 0;

            if (openList.Count > 0)
            {
                initialEstimate = ((CbsNode)openList.Peek()).totalCost;
            }

            int maxExpandedNodeCostPlusH = -1;
            int currentCost = -1;

            while (openList.Count > 0)
            {
                // Check if max time has been exceeded
                if (runner.ElapsedMilliseconds() > Constants.MAX_TIME)
                {
                    this.totalCost = Constants.TIMEOUT_COST;
                    Console.WriteLine("Out of time");
                    this.solutionDepth = ((CbsNode)openList.Peek()).totalCost - initialEstimate; // A minimum estimate
                    this.Clear();                                                                // Total search time exceeded - we're not going to resume this search.
                    this.CleanGlobals();
                    return(false);
                }

                var currentNode = (CbsNode)openList.Remove();
                currentNode.ChooseConflict();

                // A cardinal conflict may have been found, increasing the h of the node.
                // Check if the node needs to be pushed back into the open list.
                if (this.openList.Count != 0 &&
                    currentNode.f > ((CbsNode)this.openList.Peek()).f)
                {
                    if (this.debug)
                    {
                        Debug.Print("Pushing back the node into the open list with an increased h.");
                    }
                    this.openList.Add(currentNode);
                    this.nodesPushedBack++;
                    continue;
                    // Notice that even though we may iterate over conflicts later,
                    // even there is a conflict that we can identify as cardinal,
                    // then the first conflict chosen _will_ be cardinal, so this is
                    // the only place we need allow pushing nodes back.
                    // We may discover cardinal conflicts in hindsight later, but there
                    // would be no point in pushing their node back at that point,
                    // as we would've already made the split by then.
                }

                this.addToGlobalConflictCount(currentNode.GetConflict()); // TODO: Make CBS_GlobalConflicts use nodes that do this automatically after choosing a conflict

                if (debug)
                {
                    currentNode.Print();
                }

                if (currentNode.totalCost > currentCost) // Needs to be here because the goal may have a cost unseen before
                {
                    currentCost = currentNode.totalCost;
                    this.nodesExpandedWithGoalCost = 0;
                }
                else if (currentNode.totalCost == currentCost) // check needed because macbs node cost isn't exactly monotonous
                {
                    this.nodesExpandedWithGoalCost++;
                }

                // Check if node is the goal
                if (currentNode.GoalTest())
                {
                    //Debug.Assert(currentNode.totalCost >= maxExpandedNodeCostPlusH, "CBS goal node found with lower cost than the max cost node ever expanded: " + currentNode.totalCost + " < " + maxExpandedNodeCostPlusH);
                    // This is subtle, but MA-CBS may expand nodes in a non non-decreasing order:
                    // If a node with a non-optimal constraint is expanded and we decide to merge the agents,
                    // the resulting node can have a lower cost than before, since we ignore the non-optimal constraint
                    // because the conflict it addresses is between merged nodes.
                    // The resulting lower-cost node will have other constraints, that will raise the cost of its children back to at least its original cost,
                    // since the node with the non-optimal constraint was only expanded because its competitors that had an optimal
                    // constraint to deal with the same conflict apparently found the other conflict that I promise will be found,
                    // and so their cost was not smaller than this sub-optimal node.
                    // To make MA-CBS costs non-decreasing, we can choose not to ignore constraints that deal with conflicts between merged nodes.
                    // That way, the sub-optimal node will find a sub-optimal merged solution and get a high cost that will push it deep into the open list.
                    // But the cost would be to create a possibly sub-optimal merged solution where an optimal solution could be found instead, and faster,
                    // since constraints make the low-level heuristic perform worse.
                    // For an example for this subtle case happening, see problem instance 63 of the random grid with 4 agents,
                    // 55 grid cells and 9 obstacles.

                    if (debug)
                    {
                        Debug.WriteLine("-----------------");
                    }
                    this.totalCost     = currentNode.totalCost;
                    this.solution      = currentNode.CalculateJointPlan();
                    this.solutionDepth = this.totalCost - initialEstimate;
                    this.goalNode      = currentNode; // Saves the single agent plans and costs
                    // The joint plan is calculated on demand.
                    this.Clear();                     // Goal found - we're not going to resume this search
                    this.CleanGlobals();
                    return(true);
                }

                if (currentNode.totalCost >= this.targetCost || // Node is good enough
                    //(this.targetCost != int.MaxValue &&
                    //this.lowLevelGenerated > Math.Pow(Constants.NUM_ALLOWED_DIRECTIONS, this.instance.m_vAgents.Length))
                    this.solver.GetAccumulatedGenerated() > this.lowLevelGeneratedCap || // Stop because this is taking too long.
                                                                                         // We're looking at _generated_ low level nodes since that's an indication to the amount of work done,
                                                                                         // while expanded nodes is an indication of the amount of good work done.
                                                                                         // b**k is the maximum amount of nodes we'll generate if we expand this node with A*.
                    (this.milliCap != int.MaxValue &&                                    // (This check is much cheaper than the method call)
                     this.runner.ElapsedMilliseconds() > this.milliCap))                 // Search is taking too long.
                {
                    if (debug)
                    {
                        Debug.WriteLine("-----------------");
                    }
                    this.totalCost = maxExpandedNodeCostPlusH; // This is the min possible cost so far.
                    this.openList.Add(currentNode);            // To be able to continue the search later
                    this.CleanGlobals();
                    return(false);
                }

                if (maxExpandedNodeCostPlusH < currentNode.totalCost + currentNode.h)
                {
                    maxExpandedNodeCostPlusH = currentNode.totalCost + currentNode.h;
                    if (debug)
                    {
                        Debug.Print("New max F: {0}", maxExpandedNodeCostPlusH);
                    }
                }

                // Expand
                bool wasUnexpandedNode = (currentNode.agentAExpansion == CbsNode.ExpansionState.NOT_EXPANDED &&
                                          currentNode.agentBExpansion == CbsNode.ExpansionState.NOT_EXPANDED);
                Expand(currentNode);
                if (wasUnexpandedNode)
                {
                    highLevelExpanded++;
                }
                // Consider moving the following into Expand()
                if (currentNode.agentAExpansion == CbsNode.ExpansionState.EXPANDED &&
                    currentNode.agentBExpansion == CbsNode.ExpansionState.EXPANDED) // Fully expanded
                {
                    currentNode.Clear();
                }
            }

            this.totalCost = Constants.NO_SOLUTION_COST;
            this.Clear(); // unsolvable problem - we're not going to resume it
            this.CleanGlobals();
            return(false);
        }
Пример #3
0
        /// <summary>
        /// Runs the algorithm until the problem is solved or memory/time is exhausted
        /// </summary>
        /// <returns>True if solved</returns>
        public virtual bool Solve()
        {
            int initialEstimate = ((WorldState)openList.Peek()).h; // g=0 initially

            int        lastF    = -1;
            WorldState lastNode = null;

            while (openList.Count > 0)
            {
                // Check if max time has been exceeded
                if (runner.ElapsedMilliseconds() > Constants.MAX_TIME)
                {
                    totalCost = Constants.TIMEOUT_COST;
                    Console.WriteLine("Out of time");
                    this.solutionDepth = ((WorldState)openList.Peek()).f - initialEstimate; // A minimum estimate
                    this.Clear();
                    return(false);
                }

                var currentNode = (WorldState)openList.Remove();

                if (debug)
                {
                    Debug.WriteLine("");
                    Debug.WriteLine("Expanding node: " + currentNode);
                }



                lastF    = currentNode.f;
                lastNode = currentNode;

                // Calculate expansion delay
                int expansionDelay = this.expanded - currentNode.expandedCountWhenGenerated - 1; // -1 to make the delay zero when a node is expanded immediately after being generated.
                maxExpansionDelay = Math.Max(maxExpansionDelay, expansionDelay);

                // Check if node is the goal, or knows how to get to it
                if (currentNode.GoalTest())
                {
                    //((IReadOnlyDictionary<TimedMove, List<int>>)instance.parameters[CBS_LocalConflicts.CAT]), conflictRange);

                    /*List<TimedMove> newList = new List<TimedMove>();
                     * WorldState current = currentNode;
                     * while(current != null)
                     * {
                     *  newList.Add(current.)
                     * }*/
                    this.conflictTimes = currentNode.conflictTimes;

                    this.totalCost      = currentNode.GetGoalCost();
                    this.singleCosts    = currentNode.GetSingleCosts();
                    this.solution       = currentNode.GetPlan();
                    this.singlePlans    = currentNode.GetSinglePlans();
                    this.conflictCounts = currentNode.cbsInternalConflicts; // TODO: Technically, could be IndependenceDetection's count. Merge them.
                    this.conflictTimes  = currentNode.conflictTimes;
                    this.solutionDepth  = this.totalCost - initialEstimate;
                    this.Clear();
                    return(true);
                }


                Expand(currentNode);
                expanded++;
            }

            totalCost = Constants.NO_SOLUTION_COST;
            this.Clear();
            return(false);
        }
Пример #4
0
        public bool Solve()
        {
            this.SetGlobals(); // Again, because we might be resuming a search that was stopped.

            //Debug.WriteLine("Solving Sub-problem On Level - " + mergeThreshold);
            int initialEstimate = 0;

            if (openList.Count > 0)
            {
                initialEstimate = ((CbsNode)openList.Peek()).totalCost;
            }

            int maxExpandedCost = -1;

            while (openList.Count > 0)
            {
                // Check if max time has been exceeded
                if (runner.ElapsedMilliseconds() > Constants.MAX_TIME)
                {
                    totalCost = Constants.TIMEOUT_COST;
                    Console.WriteLine("Out of time");
                    this.Clear(); // Total search time exceeded - we're not going to resume this search.
                    this.CleanGlobals();
                    return(false);
                }
                var currentNode = (CbsNode)openList.Remove();

                if (debug)
                {
                    Debug.WriteLine("");
                    Debug.WriteLine("");
                    Debug.WriteLine("Node hash: " + currentNode.GetHashCode());
                    Debug.WriteLine("Total cost so far: " + currentNode.totalCost);
                    Debug.WriteLine("Expansion state: " + currentNode.agentAExpansion + ", " + currentNode.agentBExpansion);
                    Debug.WriteLine("Node depth: " + currentNode.depth);
                    var constraints = currentNode.GetConstraints();
                    Debug.WriteLine(constraints.Count.ToString() + " internal constraints so far: ");
                    foreach (CbsConstraint constraint in constraints)
                    {
                        Debug.WriteLine(constraint);
                    }
                    var externalConstraints = (HashSet_U <CbsConstraint>) this.instance.parameters[CBS_LocalConflicts.CONSTRAINTS];
                    Debug.WriteLine(externalConstraints.Count.ToString() + " external constraints: ");
                    foreach (CbsConstraint constraint in externalConstraints)
                    {
                        Debug.WriteLine(constraint);
                    }
                    Debug.WriteLine("Conflict: " + currentNode.GetConflict());
                    Debug.Write("Agent group assignments: ");
                    for (int i = 0; i < currentNode.agentsGroupAssignment.Length; i++)
                    {
                        Debug.Write(" " + currentNode.agentsGroupAssignment[i]);
                    }
                    Debug.WriteLine("");
                    Debug.Write("Single agent costs: ");
                    for (int i = 0; i < currentNode.allSingleAgentCosts.Length; i++)
                    {
                        Debug.Write(" " + currentNode.allSingleAgentCosts[i]);
                    }
                    Debug.WriteLine("");
                    currentNode.CalculateJointPlan().PrintPlan();
                    Debug.WriteLine("");
                    Debug.WriteLine("");
                }

                maxExpandedCost = Math.Max(maxExpandedCost, currentNode.totalCost);

                // Check if node is the goal
                if (currentNode.GoalTest())
                {
                    Debug.Assert(currentNode.totalCost >= maxExpandedCost, "CBS goal node found with lower cost than the max cost node ever expanded: " + currentNode.totalCost + " < " + maxExpandedCost);
                    // This is subtle, but MA-CBS may expand nodes in a non non-decreasing order:
                    // If a node with a non-optimal constraint is expanded and we decide to merge the agents,
                    // the resulting node can have a lower cost than before, since we ignore the non-optimal constraint
                    // because the conflict it addresses is between merged nodes.
                    // The resulting lower-cost node will have other constraints, that will raise the cost of its children back to at least its original cost,
                    // since the node with the non-optimal constraint was only expanded because its competitors that had an optimal
                    // constraint to deal with the same conflict apparently found the other conflict that I promise will be found,
                    // and so their cost was not smaller than this sub-optimal node.
                    // To make MA-CBS costs non-decreasing, we can choose not to ignore constraints that deal with conflicts between merged nodes.
                    // That way, the sub-optimal node will find a sub-optimal merged solution and get a high cost that will push it deep into the open list.
                    // But the cost would be to create a possibly sub-optimal merged solution where an optimal solution could be found instead, and faster,
                    // since constraints make the low-level heuristic perform worse.
                    // For an example for this subtle case happening, see problem instance 63 of the random grid with 4 agents,
                    // 55 grid cells and 9 obstacles.

                    if (debug)
                    {
                        Debug.WriteLine("-------------------------");
                    }
                    this.totalCost     = currentNode.totalCost;
                    this.solutionDepth = this.totalCost - initialEstimate;
                    this.goalNode      = currentNode; // Saves the single agent plans and costs
                    // The joint plan is calculated on demand.
                    this.Clear();                     // Goal found - we're not going to resume this search
                    this.CleanGlobals();
                    return(true);
                }

                if (currentNode.totalCost >= this.targetCost || // Node is good enough
                    //(this.targetCost != int.MaxValue &&
                    //this.lowLevelGenerated > Math.Pow(Constants.NUM_ALLOWED_DIRECTIONS, this.instance.m_vAgents.Length))
                    this.solver.GetAccumulatedGenerated() > this.lowLevelGeneratedCap || // Stop because this is taking too long.
                                                                                         // We're looking at _generated_ low level nodes since that's an indication to the amount of work done,
                                                                                         // while expanded nodes is an indication of the amount of good work done.
                                                                                         // b**k is the maximum amount of nodes we'll generate if we expand this node with A*.
                    (this.milliCap != int.MaxValue &&                                    // (This check is much cheaper than the method call)
                     this.runner.ElapsedMilliseconds() > this.milliCap))                 // Search is taking too long.
                {
                    if (debug)
                    {
                        Debug.WriteLine("-------------------------");
                    }
                    this.totalCost = maxExpandedCost; // This is the min possible cost so far.
                    this.openList.Add(currentNode);   // To be able to continue the search later
                    this.CleanGlobals();
                    return(false);
                }

                // Expand
                bool wasUnexpandedNode = (currentNode.agentAExpansion == CbsNode.ExpansionState.NOT_EXPANDED &&
                                          currentNode.agentBExpansion == CbsNode.ExpansionState.NOT_EXPANDED);
                Expand(currentNode);
                if (wasUnexpandedNode)
                {
                    highLevelExpanded++;
                }
                // Consider moving the following into Expand()
                if (currentNode.agentAExpansion == CbsNode.ExpansionState.EXPANDED &&
                    currentNode.agentBExpansion == CbsNode.ExpansionState.EXPANDED) // Fully expanded
                {
                    currentNode.Clear();
                }
            }

            this.totalCost = Constants.NO_SOLUTION_COST;
            this.Clear(); // unsolvable problem - we're not going to resume it
            this.CleanGlobals();
            return(false);
        }