detailed hungarian algorithm(assignment problem) question - algorithm

I have implemented the hungarian algorithm, a solution to the assignment problem, as described by this article, but it fails on a few percent of random costs matrices.
I've spent weeks debugging it(I started when I asked this question, not full time though). I took random cost matrices for which the algorithm fails and performed the algorithm with good old pen and paper, and compared that with my implementation to see what went wrong. This led me to a few bugs which I've corrected now, but I have encountered an example for which I do not get the right solution when solving it by hand. For anyone who is interested: the costmatrix of that example is {{0,6,4,3},{3,2,1,2},{0,7,6,4},{3,8,5,3}}, for which the correct solution has the sum of 9=4+2+0+3(in that order). In that example there is eventually a matched edge not on the equality subgraph, and I think that is impossible, indicating something is wrong.
Either I don't fully understand the solution, which is a viable option, or an extremely subtle bug in the presented solution, which I will elaborate on below.
I realize I have to introduce some terminology, but since this is a detailed question I am not going to explain all concepts in full detail, as anyone needing that explanation probably wouldn't be able to answer my question anyway.
The input of the problem is a weighted complete bipartite graph with n nodes on each partition.
The presented method specifies to find n augmenting paths.
An augmenting path is an alternating path starting and ending at a unmatched nodes.
An alternating path is a path alternating between matched an unmatched edges on the equality subgraph.
These alternating paths are grown in a breadth-first manner, stopping only when either:
An augmenting path is found or
the alternating paths cannot be grown any further.
And a crucial fact to the possible bug: the algorithm remembers what nodes the alternating paths have encountered, which affects the algorithm in a part irrelevant to this question.
When an augmented path is found, the presented method says to stop growing the alternating paths. I believe this is incorrect. I think all alternating paths need to be grown up to the cost of the found augmented path. Notice that the alternating paths are grown in a breadth first manner, so this only grows paths whose costs can tie with the found path. This small change might result in some nodes being marked as 'visited by alternating path' which otherwise wouldn't have been marked, which affect the algorithm further on.
The actual question:
Should I consider alternating paths with costs equal to the costs of the augmented path (and starting at the same node) explored? This is contrary to the presented method, which says to stop as soon as an augmented path is found, regardless of any ties in costs with other paths.

Looking at the presentation of the Hungarian algorithm in "The Stanford GraphBase" you can track its progress towards a solution as adding a constant to every cell in a row of the cost matrix, or every cell in a column of the cost matrix, and see that you have a solution when you have a complete set of independent zeros in the altered matrix.
I have read just once the paper you refer to. Is it the case that finding an augmenting path allows you to increase the number of independent zeros in the altered matrix? If so, then finding n augmenting paths, as in their Figure 3 step 2, will find a good solution, because you must then have n independent zeros. If so, then you can check your implementation of the algorithm by checking that each augmenting path found adds an independent zero, even in the case when there are other paths that it could have found but stopped short of finding.

Related

Dijkstra's bi-directional implementation

I am implementing a bidirectional Dijkstra's algorithm and having issues understanding how the various implementations of the stopping condition work out.
Take this graph for example, where we're starting from node A, targetting node J. Below the graph I have listed the cluster (processed) and relaxed (fringes) nodes at the time the algorithm stops:
The accepted answer to “Bidirectional Dijkstra” by NetworkX explains that the algorithm stops when the same node has been processed in both directions. In my graph that will be Node F. If that were the case, the algorithm stops after finding the shortest path of length 9 going from A-B-C...H-I-J. But this wouldn't be the shortest path because A-J have a direct edge of length 8 which is never taken because the weight 8 is never popped from the priority queue.
Even in this Java implementation on github of Dijksta's bi-directional algorithm, the stopping condition is:
double mtmp = DISTANCEA.get(OPENA.min()) +
DISTANCEB.get(OPENB.min());
if (mtmp >= bestPathLength) return PATH;
This algorithm stops when the top node weights -- from each front and backward queue -- add up to at least the best path length so far. But this wouldn't return the correct shortest path either. Because in that case it will be node G(6) and E(5) totalling to 11, which is greater than the best path so far of length 9.
I don't understand that seemingly both of these stopping conditions yield an incorrect shortest path. I am not sure what I am misunderstanding.
What is a good stopping condition for Dijkstra's bidirectional algorithm? Also, what would be a stopping condition for bidirectional A*?
Conceptually the stopping condition for Dijkstra's algorithm, whether bidirectional or not, is that you stop when the best path you've found is as good as any path you might find if you continue. Only closed paths (the ones in your "cluster" sets above) count as found.
For bidirectional Dijkstra's, a path is "found" whenever the same vertex exists in both the forward and reverse closed sets. That part is easy, but how good is the best path you might find in the future?
To make sure the answer you get is correct, you evaluation of the best path you might find needs to be accurate, or an underestimate. Lets consider the possibilities:
A path might be made with a vertex that is open in both directions.
A vertex that is open in one direction might make a path with one that is already closed in the other direction.
The problem is case (2). The sets and priority queues we use for Dijkstra's algorithm do not allow us to make a very useful underestimate of the best path in this case. The smallest distance in a closed set is always 0, and if we add this to the minimum open from the other direction, then we come up with:
double mtmp = min ( DISTANCEA.get(OPENA.min()) , DISTANCEB.get(OPENB.min()) );
This works, and will produce the correct answer, but it will make the algorithm run until the best complete path is found in at least one direction. Unidirectional Dijkstra's would be faster in many cases.
I think this "bidirectonal Dijkstra's" idea needs significant rework in order to be really good.

Why do we need to handle blossoms when finding maximum matchings?

We know the standard algorithm for finding maximum matching in general graph.
https://en.wikipedia.org/wiki/Blossom_algorithm
What I am trying to understand is that what is the need to handle blossom separately?
I think finding augmenting path and complementing it is enough. It works with odd cycle as well.
You are correct that you can form a maximum matching by using the following general algorithm:
If such a path exists, augment along that path to increase the size of the matching by one. Repeat.
If no such path exists, your matching is maximum and you're done.
The challenge, though, is determining whether such an augmenting path exists in the graph. With a small graph it might not be all that hard to find a path, but as the graphs get larger and larger and the partial matchings increase in size it can become pretty challenging. Brute-force searching through all the possible paths is not feasible at this scale.
In the case where the graph is bipartite (there are no odd-length cycles), there are nice algorithms that do this that are based on a modification of breadth-first or depth-first search. They work nicely because you can classify nodes as being either at an odd or even distance from a start node. With odd cycles, this breaks down, and these simple algorithms don't work.
The reason the blossom algorithm exists - and the reason why blossoms are there in the first place - is that they provide a mechanism for efficiently searching the graph for augmenting paths even in the presence of blossoms. The intuition is that every time you see a blossom, you can contract it down to a point in a way that doesn't mess up your ability to find augmenting paths. Contracting an odd cycle reduces the size of the graph, and through recursion you'll either end a graph where it's easy to find an augmenting path or you'll find that there aren't any.
So in a sense, the reason we use blossoms is that it enables us to efficiently (in polynomial time) check whether augmenting paths exist and, if so, find them and augment across them.

Pathfinding - A path of less than or equal to n turns

Most of the time when implementing a pathfinding algorithm such as A*, we seek to minimize the travel cost along the path. We could also seek to find the optimal path with the fewest number of turns. This could be done by, instead of having a grid of location states, having a grid of location-direction states. For any given location in the old grid, we would have 4 states in that spot representing that location moving left, right, up, or down. That is, if you were expanding to a node above you, you would actually be adding the 'up' state of that node to the priority queue, since we've found the quickest route to this node when going UP. If you were going that direction anyway, we wouldnt add anything to the weight. However, if we had to turn from the current node to get to the expanded node, we would add a small epsilon to the weight such that two shortest paths in distance would not be equal in cost if their number of turns differed. As long as epsilon is << cost of moving between nodes, its still the shortest path.
I now pose a similar problem, but with relaxed constraints. I no longer wish to find the shortest path, not even a path with the fewest turns. My only goal is to find a path of ANY length with numTurns <= n. To clarify, the goal of this algorithm would be to answer the question:
"Does there exist a path P from locations A to B such that there are fewer than or equal to n turns?"
I'm asking whether using some sort of greedy algorithm here would be helpful, since I do not require minimum distance nor turns. The problem is, if I'm NOT finding the minimum, the algorithm may search through more squares on the board. That is, normally a shortest path algorithm searches the least number of squares it has to, which is key for performance.
Are there any techniques that come to mind that would provide an efficient way (better or same as A*) to find such a path? Again, A* with fewest turns provides the "optimal" solution for distance and #turns. But for my problem, "optimal" is the fastest way the function can return whether there is a path of <=n turns between A and B. Note that there can be obstacles in the path, but other than that, moving from one square to another is the same cost (unless turning, as mentioned above).
I've been brainstorming, but I can not think of anything other than A* with the turn states . It might not be possible to do better than this, but I thought there may be a clever exploitation of my relaxed conditions. I've even considered using just numTurns as the cost of moving on the board, but that could waste a lot of time searching dead paths. Thanks very much!
Edit: Final clarification - Path does not have to have least number of turns, just <= n. Path does not have to be a shortest path, it can be a huge path if it only has n turns. The goal is for this function to execute quickly, I don't even need to record the path. I just need to know whether there exists one. Thanks :)

Generating a tower defense maze (longest maze with limited walls) - near-optimal heuristic?

In a tower defense game, you have an NxM grid with a start, a finish, and a number of walls.
Enemies take the shortest path from start to finish without passing through any walls (they aren't usually constrained to the grid, but for simplicity's sake let's say they are. In either case, they can't move through diagonal "holes")
The problem (for this question at least) is to place up to K additional walls to maximize the path the enemies have to take. For example, for K=14
My intuition tells me this problem is NP-hard if (as I'm hoping to do) we generalize this to include waypoints that must be visited before moving to the finish, and possibly also without waypoints.
But, are there any decent heuristics out there for near-optimal solutions?
[Edit] I have posted a related question here.
I present a greedy approach and it's maybe close to the optimal (but I couldn't find approximation factor). Idea is simple, we should block the cells which are in critical places of the Maze. These places can help to measure the connectivity of maze. We can consider the vertex connectivity and we find minimum vertex cut which disconnects the start and final: (s,f). After that we remove some critical cells.
To turn it to the graph, take dual of maze. Find minimum (s,f) vertex cut on this graph. Then we examine each vertex in this cut. We remove a vertex its deletion increases the length of all s,f paths or if it is in the minimum length path from s to f. After eliminating a vertex, recursively repeat the above process for k time.
But there is an issue with this, this is when we remove a vertex which cuts any path from s to f. To prevent this we can weight cutting node as high as possible, means first compute minimum (s,f) cut, if cut result is just one node, make it weighted and set a high weight like n^3 to that vertex, now again compute the minimum s,f cut, single cutting vertex in previous calculation doesn't belong to new cut because of waiting.
But if there is just one path between s,f (after some iterations) we can't improve it. In this case we can use normal greedy algorithms like removing node from a one of a shortest path from s to f which doesn't belong to any cut. after that we can deal with minimum vertex cut.
The algorithm running time in each step is:
min-cut + path finding for all nodes in min-cut
O(min cut) + O(n^2)*O(number of nodes in min-cut)
And because number of nodes in min cut can not be greater than O(n^2) in very pessimistic situation the algorithm is O(kn^4), but normally it shouldn't take more than O(kn^3), because normally min-cut algorithm dominates path finding, also normally path finding doesn't takes O(n^2).
I guess the greedy choice is a good start point for simulated annealing type algorithms.
P.S: minimum vertex cut is similar to minimum edge cut, and similar approach like max-flow/min-cut can be applied on minimum vertex cut, just assume each vertex as two vertex, one Vi, one Vo, means input and outputs, also converting undirected graph to directed one is not hard.
it can be easily shown (proof let as an exercise to the reader) that it is enough to search for the solution so that every one of the K blockades is put on the current minimum-length route. Note that if there are multiple minimal-length routes then all of them have to be considered. The reason is that if you don't put any of the remaining blockades on the current minimum-length route then it does not change; hence you can put the first available blockade on it immediately during search. This speeds up even a brute-force search.
But there are more optimizations. You can also always decide that you put the next blockade so that it becomes the FIRST blockade on the current minimum-length route, i.e. you work so that if you place the blockade on the 10th square on the route, then you mark the squares 1..9 as "permanently open" until you backtrack. This saves again an exponential number of squares to search for during backtracking search.
You can then apply heuristics to cut down the search space or to reorder it, e.g. first try those blockade placements that increase the length of the current minimum-length route the most. You can then run the backtracking algorithm for a limited amount of real-time and pick the best solution found thus far.
I believe we can reduce the contained maximum manifold problem to boolean satisifiability and show NP-completeness through any dependency on this subproblem. Because of this, the algorithms spinning_plate provided are reasonable as heuristics, precomputing and machine learning is reasonable, and the trick becomes finding the best heuristic solution if we wish to blunder forward here.
Consider a board like the following:
..S........
#.#..#..###
...........
...........
..........F
This has many of the problems that cause greedy and gate-bound solutions to fail. If we look at that second row:
#.#..#..###
Our logic gates are, in 0-based 2D array ordered as [row][column]:
[1][4], [1][5], [1][6], [1][7], [1][8]
We can re-render this as an equation to satisfy the block:
if ([1][9] AND ([1][10] AND [1][11]) AND ([1][12] AND [1][13]):
traversal_cost = INFINITY; longest = False # Infinity does not qualify
Excepting infinity as an unsatisfiable case, we backtrack and rerender this as:
if ([1][14] AND ([1][15] AND [1][16]) AND [1][17]:
traversal_cost = 6; longest = True
And our hidden boolean relationship falls amongst all of these gates. You can also show that geometric proofs can't fractalize recursively, because we can always create a wall that's exactly N-1 width or height long, and this represents a critical part of the solution in all cases (therefore, divide and conquer won't help you).
Furthermore, because perturbations across different rows are significant:
..S........
#.#........
...#..#....
.......#..#
..........F
We can show that, without a complete set of computable geometric identities, the complete search space reduces itself to N-SAT.
By extension, we can also show that this is trivial to verify and non-polynomial to solve as the number of gates approaches infinity. Unsurprisingly, this is why tower defense games remain so fun for humans to play. Obviously, a more rigorous proof is desirable, but this is a skeletal start.
Do note that you can significantly reduce the n term in your n-choose-k relation. Because we can recursively show that each perturbation must lie on the critical path, and because the critical path is always computable in O(V+E) time (with a few optimizations to speed things up for each perturbation), you can significantly reduce your search space at a cost of a breadth-first search for each additional tower added to the board.
Because we may tolerably assume O(n^k) for a deterministic solution, a heuristical approach is reasonable. My advice thus falls somewhere between spinning_plate's answer and Soravux's, with an eye towards machine learning techniques applicable to the problem.
The 0th solution: Use a tolerable but suboptimal AI, in which spinning_plate provided two usable algorithms. Indeed, these approximate how many naive players approach the game, and this should be sufficient for simple play, albeit with a high degree of exploitability.
The 1st-order solution: Use a database. Given the problem formulation, you haven't quite demonstrated the need to compute the optimal solution on the fly. Therefore, if we relax the constraint of approaching a random board with no information, we can simply precompute the optimum for all K tolerable for each board. Obviously, this only works for a small number of boards: with V! potential board states for each configuration, we cannot tolerably precompute all optimums as V becomes very large.
The 2nd-order solution: Use a machine-learning step. Promote each step as you close a gap that results in a very high traversal cost, running until your algorithm converges or no more optimal solution can be found than greedy. A plethora of algorithms are applicable here, so I recommend chasing the classics and the literature for selecting the correct one that works within the constraints of your program.
The best heuristic may be a simple heat map generated by a locally state-aware, recursive depth-first traversal, sorting the results by most to least commonly traversed after the O(V^2) traversal. Proceeding through this output greedily identifies all bottlenecks, and doing so without making pathing impossible is entirely possible (checking this is O(V+E)).
Putting it all together, I'd try an intersection of these approaches, combining the heat map and critical path identities. I'd assume there's enough here to come up with a good, functional geometric proof that satisfies all of the constraints of the problem.
At the risk of stating the obvious, here's one algorithm
1) Find the shortest path
2) Test blocking everything node on that path and see which one results in the longest path
3) Repeat K times
Naively, this will take O(K*(V+ E log E)^2) but you could with some little work improve 2 by only recalculating partial paths.
As you mention, simply trying to break the path is difficult because if most breaks simply add a length of 1 (or 2), its hard to find the choke points that lead to big gains.
If you take the minimum vertex cut between the start and the end, you will find the choke points for the entire graph. One possible algorithm is this
1) Find the shortest path
2) Find the min-cut of the whole graph
3) Find the maximal contiguous node set that intersects one point on the path, block those.
4) Wash, rinse, repeat
3) is the big part and why this algorithm may perform badly, too. You could also try
the smallest node set that connects with other existing blocks.
finding all groupings of contiguous verticies in the vertex cut, testing each of them for the longest path a la the first algorithm
The last one is what might be most promising
If you find a min vertex cut on the whole graph, you're going to find the choke points for the whole graph.
Here is a thought. In your grid, group adjacent walls into islands and treat every island as a graph node. Distance between nodes is the minimal number of walls that is needed to connect them (to block the enemy).
In that case you can start maximizing the path length by blocking the most cheap arcs.
I have no idea if this would work, because you could make new islands using your points. but it could help work out where to put walls.
I suggest using a modified breadth first search with a K-length priority queue tracking the best K paths between each island.
i would, for every island of connected walls, pretend that it is a light. (a special light that can only send out horizontal and vertical rays of light)
Use ray-tracing to see which other islands the light can hit
say Island1 (i1) hits i2,i3,i4,i5 but doesn't hit i6,i7..
then you would have line(i1,i2), line(i1,i3), line(i1,i4) and line(i1,i5)
Mark the distance of all grid points to be infinity. Set the start point as 0.
Now use breadth first search from the start. Every grid point, mark the distance of that grid point to be the minimum distance of its neighbors.
But.. here is the catch..
every time you get to a grid-point that is on a line() between two islands, Instead of recording the distance as the minimum of its neighbors, you need to make it a priority queue of length K. And record the K shortest paths to that line() from any of the other line()s
This priority queque then stays the same until you get to the next line(), where it aggregates all priority ques going into that point.
You haven't showed the need for this algorithm to be realtime, but I may be wrong about this premice. You could then precalculate the block positions.
If you can do this beforehand and then simply make the AI build the maze rock by rock as if it was a kind of tree, you could use genetic algorithms to ease up your need for heuristics. You would need to load any kind of genetic algorithm framework, start with a population of non-movable blocks (your map) and randomly-placed movable blocks (blocks that the AI would place). Then, you evolve the population by making crossovers and transmutations over movable blocks and then evaluate the individuals by giving more reward to the longest path calculated. You would then simply have to write a resource efficient path-calculator without the need of having heuristics in your code. In your last generation of your evolution, you would take the highest-ranking individual, which would be your solution, thus your desired block pattern for this map.
Genetic algorithms are proven to take you, under ideal situation, to a local maxima (or minima) in reasonable time, which may be impossible to reach with analytic solutions on a sufficiently large data set (ie. big enough map in your situation).
You haven't stated the language in which you are going to develop this algorithm, so I can't propose frameworks that may perfectly suit your needs.
Note that if your map is dynamic, meaning that the map may change over tower defense iterations, you may want to avoid this technique since it may be too intensive to re-evolve an entire new population every wave.
I'm not at all an algorithms expert, but looking at the grid makes me wonder if Conway's game of life might somehow be useful for this. With a reasonable initial seed and well-chosen rules about birth and death of towers, you could try many seeds and subsequent generations thereof in a short period of time.
You already have a measure of fitness in the length of the creeps' path, so you could pick the best one accordingly. I don't know how well (if at all) it would approximate the best path, but it would be an interesting thing to use in a solution.

How to find shortest path in dynamic situation

Some days ago, Someone ask me, If we have some agents in our environment, and they want go from their sources to their destinations, how we can find the total shortest path for all of them such that they shouldn't have conflict during their walk.
The point of problem is all agents simultaneously walking in environment (which can be modeled by undirected weighted graph), and we shouldn't have any collision. I thought about this but I couldn't find optimum path for all of them. But sure there are too many heuristic ideas for this problem.
Assume input is graph G(V,E), m agents which are in: S1, S2,...,Sm nodes of graph in startup and they should go to nodes D1,...Dm at the end. Also may be there is conflict in nodes Si or Di,... but these conflicts are not important they shouldn't have conflict when they are in their internal nodes of their path.
If their path shouldn't have same internal node, It will be kind of k-disjoint paths problem which is NPC, but in this case paths can have same nodes, but agent shouldn't be in same node in same time. I don't know I can tell the exact problem statement or not. If is confusing tell me in comments to edit it.
Is there any optimal and fast algorithm (by optimal I mean sum of length of all paths be as smallest as possible, and by fast I mean good polynomial time algorithm).
A Google search reveals two links that might be helpful:
Cooperative path planning for multi-robot systems in dynamic domains
Optimizing schedules for prioritized path planning of multi-robot systems
Edit: From the book chapter (first link):
There are various approaches to path planning in multi-robot system [sic], however, finding the
optimal solution is NP-hard. Hopcraft et al. (1984) simplify the planning problem to the
problem of moving rectangles in a rectangular container. They proved the NP-hardness of
finding a plan from a given configuration to a goal configuration with the least amount of
steps. Hence, all feasible approaches to path planning are a compromise between efficiency
and accuracy of the result.
I can't find the original paper by Hopcroft online, but given that quote, I suspect the problem they reduced the navigation task to is similar to Rush Hour, which is PSPACE-complete.
If it's just a matter of getting from point a to point b for each robot, you could just use a search algorithm like A* (A Star) or Best-First.
Give it a simple heuristic like the sum of distances from goal.

Resources