A* 实现总是返回相同的值
我似乎要么失去了理智,要么错误地实现了 A* 算法:
下面是我的代码,似乎无论我输入什么值,它总是会返回 360。我在这里错过了一些关键信息吗?另外,在有人问“是”之前,这与我收到的机器学习作业有关。
公开课A_Star{
private ArrayList<SearchNode> closedNodes = new ArrayList<SearchNode>();
private ArrayList<SearchNode> openNodes = new ArrayList<SearchNode>();
private ArrayList<SearchNode> siblingNodes = new ArrayList<SearchNode>();
private ArrayList<SearchNode> obstacleNodes;
final SearchNode START_NODE = new SearchNode(0,115,655);
final SearchNode END_NODE = new SearchNode(0,380,560);
final int HEURISTIC = 1 * Math.abs((END_NODE.getxCoordinate() - START_NODE.getxCoordinate()) + (START_NODE.getyCoordinate() - END_NODE.getyCoordinate())) ;
private int cost = 0;
//Start: (115, 655) End: (380, 560)
public int starSearch(SearchNode currentNode, Set<SearchNode> obstacleNodes) throws Exception {
//h(n) = D * (abs(n.x-goal.x) + abs(n.y-goal.y))
boolean isMaxY = false;
boolean isMaxX = false;
int currentY = currentNode.getyCoordinate();
int currentX = currentNode.getxCoordinate();
System.out.println(currentNode.getxCoordinate() + " " + currentNode.getyCoordinate() + " Current Coordinates");
int currentGScore = Math.abs(currentNode.getxCoordinate() - END_NODE.getxCoordinate()) + (currentNode.getyCoordinate() - END_NODE.getyCoordinate());
currentNode.setgScore(currentGScore);
System.out.println("Current node G score at entry: " + currentNode.getgScore());
if(!closedNodes.contains(currentNode)){
closedNodes.add(currentNode);
}
if(currentNode.getyCoordinate() == END_NODE.getyCoordinate()){
isMaxY=true;
}
if(currentNode.getxCoordinate() == END_NODE.getxCoordinate()) {
isMaxX =true;
}
SearchNode bottomCenter = new SearchNode(0,currentNode.getxCoordinate(), currentNode.getyCoordinate() -1);
SearchNode middleRight = new SearchNode(0,currentNode.getxCoordinate() +1, currentNode.getyCoordinate() );
SearchNode middleLeft = new SearchNode(0,currentNode.getxCoordinate() -1, currentNode.getyCoordinate());
SearchNode topCenter = new SearchNode(0,currentNode.getxCoordinate(), currentNode.getyCoordinate()+1);
int middleRightGScore = Math.abs(middleRight.getxCoordinate() - END_NODE.getxCoordinate()) + (middleRight.getyCoordinate() - END_NODE.getyCoordinate());
int bottomCenterGScore = Math.abs(bottomCenter.getxCoordinate() - END_NODE.getxCoordinate()) + (bottomCenter.getyCoordinate() - END_NODE.getyCoordinate());
int middleLeftGScore = Math.abs(middleLeft.getxCoordinate() - END_NODE.getxCoordinate()) + (middleLeft.getyCoordinate() - END_NODE.getyCoordinate());
int topCenterGScore = Math.abs(topCenter.getxCoordinate() - END_NODE.getxCoordinate()) + (topCenter.getyCoordinate() - END_NODE.getyCoordinate());
middleRight.setgScore(middleRightGScore);
middleLeft.setgScore(middleLeftGScore);
bottomCenter.setgScore(bottomCenterGScore);
topCenter.setgScore(topCenterGScore);
for(SearchNode obstacleNode:obstacleNodes){
int obstacleX = obstacleNode.getxCoordinate();
int obstacleY = obstacleNode.getyCoordinate();
if((middleRight != null) && (middleRight.getxCoordinate() == obstacleX)){
if(middleRight.getyCoordinate() == obstacleY){
// throw new Exception();
System.out.println("REMOVING AND NULLING: " + middleRight.toString());
siblingNodes.remove(middleRight);
middleRight = null;
}
}
if((middleLeft!=null)&&(middleLeft.getxCoordinate() == obstacleX)){
if(middleLeft.getyCoordinate() == obstacleY){
System.out.println("REMOVING AND NULLING: " + middleLeft.toString());
siblingNodes.remove(middleLeft);
middleLeft=null;
}
} if((bottomCenter!=null) &&(bottomCenter.getxCoordinate() == obstacleX)){
if(bottomCenter.getyCoordinate() == obstacleY){
System.out.println("REMOVING AND NULLING: " + bottomCenter.toString());
siblingNodes.remove(bottomCenter);
bottomCenter = null;
}
} if((topCenter!=null) && (topCenter.getxCoordinate() == obstacleX)){
if(topCenter.getyCoordinate() == obstacleY){
System.out.println("REMOVING AND NULLING: " + topCenter.toString());
siblingNodes.remove(topCenter);
topCenter=null;
}
}
if((middleRight != null) && (middleRight.getxCoordinate() != obstacleX)){
if(middleRight.getyCoordinate() != obstacleY){
System.out.println("ADDING THE FOLLOWING: " + middleRight.toString());
siblingNodes.add(middleRight);
}
}
if((middleLeft != null) && (middleLeft.getxCoordinate() != obstacleX)){
if(middleLeft.getyCoordinate() != obstacleY){
siblingNodes.add(middleLeft);
}
} if((bottomCenter != null) && (bottomCenter.getxCoordinate() != obstacleX)){
if(bottomCenter.getyCoordinate() != obstacleY){
siblingNodes.add(bottomCenter);
}
} if((topCenter !=null) && (topCenter.getxCoordinate() != obstacleX)){
if(topCenter.getyCoordinate() != obstacleY){
siblingNodes.add(topCenter);
}
}
}
int highestScore = currentNode.getgScore();
for(SearchNode node: siblingNodes){
if(node == null){
continue;
}
if(node.getxCoordinate() == END_NODE.getxCoordinate() && node.getyCoordinate() == END_NODE.getyCoordinate()){
System.out.println("Returning cost: " + ++cost + " of: " + node.toString());
return cost;
}
// System.out.println("Current node size: " + siblingNodes.size());
if(node.getgScore() < highestScore){
highestScore = node.getgScore();
currentNode=node;
cost++;
System.out.println("Changed highest score: " + highestScore);
System.out.println("Removing node: " + node.toString());
siblingNodes.remove(node);
System.out.println("Incrementing cost the Current Cost: " + cost);
starSearch(currentNode,obstacleNodes);
break;
}
if(isMaxY && isMaxX){
return cost;
}
}
return cost;
//Always move diagonal right downwards
}
public static void main(String[] args) throws Exception{
System.out.println("Hello");
A_Star star = new A_Star();
HashSet<SearchNode> obstacles = new HashSet<SearchNode>();
obstacles.add(new SearchNode(0,311,530));
obstacles.add(new SearchNode(0,311,559));
obstacles.add(new SearchNode(0,339,578));
obstacles.add(new SearchNode(0,361,560));
obstacles.add(new SearchNode(0,361,528));
obstacles.add(new SearchNode(0,116, 655));
int cost = star.starSearch(star.START_NODE, obstacles);
System.out.println(cost);
//((311, 530), (311, 559), (339, 578), (361, 560), (361, 528), (336, 516))
}
}
和
公共类SearchNode {
private int xCoordinate;
private int yCoordinate;
private int cost;
public int getfScore() {
return fScore;
}
public void setfScore(int fScore) {
this.fScore = fScore;
}
private int fScore;
public int getgScore() {
return gScore;
}
public void setgScore(int gScore) {
this.gScore = gScore;
}
private int gScore;
公共SearchNode(int成本,int x坐标,int y坐标){
this.cost=成本;
this.x坐标=x坐标;
this.y坐标 = y坐标;
}
公共 int getCost() { 退货费用; }
public void setCost(int cost) {
this.cost = cost;
}
public int getxCoordinate() {
return xCoordinate;
}
public void setxCoordinate(int xCoordinate) {
this.xCoordinate = xCoordinate;
}
public int getyCoordinate() {
return yCoordinate;
}
public void setyCoordinate(int yCoordinate) {
this.yCoordinate = yCoordinate;
}
public String toString(){
return "Y Coordinate: " + this.yCoordinate + " X Coordinate: " + this.xCoordinate + " G Score: " + this.gScore;
}
}
I seem to be either losing my mind or misimplementing the A* algorithm:
Below is my code, it seems that no matter what values I enter it will always return 360. Am I missing some critical piece of information here? Also before anyone asks yes this is related to a machine learning assignment I received.
public class A_Star {
private ArrayList<SearchNode> closedNodes = new ArrayList<SearchNode>();
private ArrayList<SearchNode> openNodes = new ArrayList<SearchNode>();
private ArrayList<SearchNode> siblingNodes = new ArrayList<SearchNode>();
private ArrayList<SearchNode> obstacleNodes;
final SearchNode START_NODE = new SearchNode(0,115,655);
final SearchNode END_NODE = new SearchNode(0,380,560);
final int HEURISTIC = 1 * Math.abs((END_NODE.getxCoordinate() - START_NODE.getxCoordinate()) + (START_NODE.getyCoordinate() - END_NODE.getyCoordinate())) ;
private int cost = 0;
//Start: (115, 655) End: (380, 560)
public int starSearch(SearchNode currentNode, Set<SearchNode> obstacleNodes) throws Exception {
//h(n) = D * (abs(n.x-goal.x) + abs(n.y-goal.y))
boolean isMaxY = false;
boolean isMaxX = false;
int currentY = currentNode.getyCoordinate();
int currentX = currentNode.getxCoordinate();
System.out.println(currentNode.getxCoordinate() + " " + currentNode.getyCoordinate() + " Current Coordinates");
int currentGScore = Math.abs(currentNode.getxCoordinate() - END_NODE.getxCoordinate()) + (currentNode.getyCoordinate() - END_NODE.getyCoordinate());
currentNode.setgScore(currentGScore);
System.out.println("Current node G score at entry: " + currentNode.getgScore());
if(!closedNodes.contains(currentNode)){
closedNodes.add(currentNode);
}
if(currentNode.getyCoordinate() == END_NODE.getyCoordinate()){
isMaxY=true;
}
if(currentNode.getxCoordinate() == END_NODE.getxCoordinate()) {
isMaxX =true;
}
SearchNode bottomCenter = new SearchNode(0,currentNode.getxCoordinate(), currentNode.getyCoordinate() -1);
SearchNode middleRight = new SearchNode(0,currentNode.getxCoordinate() +1, currentNode.getyCoordinate() );
SearchNode middleLeft = new SearchNode(0,currentNode.getxCoordinate() -1, currentNode.getyCoordinate());
SearchNode topCenter = new SearchNode(0,currentNode.getxCoordinate(), currentNode.getyCoordinate()+1);
int middleRightGScore = Math.abs(middleRight.getxCoordinate() - END_NODE.getxCoordinate()) + (middleRight.getyCoordinate() - END_NODE.getyCoordinate());
int bottomCenterGScore = Math.abs(bottomCenter.getxCoordinate() - END_NODE.getxCoordinate()) + (bottomCenter.getyCoordinate() - END_NODE.getyCoordinate());
int middleLeftGScore = Math.abs(middleLeft.getxCoordinate() - END_NODE.getxCoordinate()) + (middleLeft.getyCoordinate() - END_NODE.getyCoordinate());
int topCenterGScore = Math.abs(topCenter.getxCoordinate() - END_NODE.getxCoordinate()) + (topCenter.getyCoordinate() - END_NODE.getyCoordinate());
middleRight.setgScore(middleRightGScore);
middleLeft.setgScore(middleLeftGScore);
bottomCenter.setgScore(bottomCenterGScore);
topCenter.setgScore(topCenterGScore);
for(SearchNode obstacleNode:obstacleNodes){
int obstacleX = obstacleNode.getxCoordinate();
int obstacleY = obstacleNode.getyCoordinate();
if((middleRight != null) && (middleRight.getxCoordinate() == obstacleX)){
if(middleRight.getyCoordinate() == obstacleY){
// throw new Exception();
System.out.println("REMOVING AND NULLING: " + middleRight.toString());
siblingNodes.remove(middleRight);
middleRight = null;
}
}
if((middleLeft!=null)&&(middleLeft.getxCoordinate() == obstacleX)){
if(middleLeft.getyCoordinate() == obstacleY){
System.out.println("REMOVING AND NULLING: " + middleLeft.toString());
siblingNodes.remove(middleLeft);
middleLeft=null;
}
} if((bottomCenter!=null) &&(bottomCenter.getxCoordinate() == obstacleX)){
if(bottomCenter.getyCoordinate() == obstacleY){
System.out.println("REMOVING AND NULLING: " + bottomCenter.toString());
siblingNodes.remove(bottomCenter);
bottomCenter = null;
}
} if((topCenter!=null) && (topCenter.getxCoordinate() == obstacleX)){
if(topCenter.getyCoordinate() == obstacleY){
System.out.println("REMOVING AND NULLING: " + topCenter.toString());
siblingNodes.remove(topCenter);
topCenter=null;
}
}
if((middleRight != null) && (middleRight.getxCoordinate() != obstacleX)){
if(middleRight.getyCoordinate() != obstacleY){
System.out.println("ADDING THE FOLLOWING: " + middleRight.toString());
siblingNodes.add(middleRight);
}
}
if((middleLeft != null) && (middleLeft.getxCoordinate() != obstacleX)){
if(middleLeft.getyCoordinate() != obstacleY){
siblingNodes.add(middleLeft);
}
} if((bottomCenter != null) && (bottomCenter.getxCoordinate() != obstacleX)){
if(bottomCenter.getyCoordinate() != obstacleY){
siblingNodes.add(bottomCenter);
}
} if((topCenter !=null) && (topCenter.getxCoordinate() != obstacleX)){
if(topCenter.getyCoordinate() != obstacleY){
siblingNodes.add(topCenter);
}
}
}
int highestScore = currentNode.getgScore();
for(SearchNode node: siblingNodes){
if(node == null){
continue;
}
if(node.getxCoordinate() == END_NODE.getxCoordinate() && node.getyCoordinate() == END_NODE.getyCoordinate()){
System.out.println("Returning cost: " + ++cost + " of: " + node.toString());
return cost;
}
// System.out.println("Current node size: " + siblingNodes.size());
if(node.getgScore() < highestScore){
highestScore = node.getgScore();
currentNode=node;
cost++;
System.out.println("Changed highest score: " + highestScore);
System.out.println("Removing node: " + node.toString());
siblingNodes.remove(node);
System.out.println("Incrementing cost the Current Cost: " + cost);
starSearch(currentNode,obstacleNodes);
break;
}
if(isMaxY && isMaxX){
return cost;
}
}
return cost;
//Always move diagonal right downwards
}
public static void main(String[] args) throws Exception{
System.out.println("Hello");
A_Star star = new A_Star();
HashSet<SearchNode> obstacles = new HashSet<SearchNode>();
obstacles.add(new SearchNode(0,311,530));
obstacles.add(new SearchNode(0,311,559));
obstacles.add(new SearchNode(0,339,578));
obstacles.add(new SearchNode(0,361,560));
obstacles.add(new SearchNode(0,361,528));
obstacles.add(new SearchNode(0,116, 655));
int cost = star.starSearch(star.START_NODE, obstacles);
System.out.println(cost);
//((311, 530), (311, 559), (339, 578), (361, 560), (361, 528), (336, 516))
}
}
and
public class SearchNode {
private int xCoordinate;
private int yCoordinate;
private int cost;
public int getfScore() {
return fScore;
}
public void setfScore(int fScore) {
this.fScore = fScore;
}
private int fScore;
public int getgScore() {
return gScore;
}
public void setgScore(int gScore) {
this.gScore = gScore;
}
private int gScore;
public SearchNode(int cost, int xCoordinate,int yCoordinate){
this.cost=cost;
this.xCoordinate =xCoordinate;
this.yCoordinate = yCoordinate;
}
public int getCost() {
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
public int getxCoordinate() {
return xCoordinate;
}
public void setxCoordinate(int xCoordinate) {
this.xCoordinate = xCoordinate;
}
public int getyCoordinate() {
return yCoordinate;
}
public void setyCoordinate(int yCoordinate) {
this.yCoordinate = yCoordinate;
}
public String toString(){
return "Y Coordinate: " + this.yCoordinate + " X Coordinate: " + this.xCoordinate + " G Score: " + this.gScore;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我假设该图是一个规则的矩形网格,其中有障碍节点,任何解决方案都不应通过这些节点。此外,我假设从一个节点到邻居节点的旅行为 1。我还意识到曼哈顿距离被用作启发式。
鉴于这些,我担心您的实现是错误的。
首先,您应该使用迭代方法而不是递归方法。考虑到你的图表的大小,如果它是正确的实现,你肯定会得到 Stackoverflows。
其次,GValue、HValue、FValue 和/或成本的概念似乎存在问题。我觉得有必要对这些术语进行非正式的描述。
A* 使用的简单公式是 F = G + H,其中
G 是当前计算的从起始节点到当前节点的行驶成本。因此,对于起始节点,G 值应为 0,从起始节点可到达的任何节点的 G 值应为 1(我的假设是这样,从一个节点移动到邻居节点)我想强调“当前”术语这里,因为节点的gValue在算法运行过程中可能会发生变化。
H是成本的启发部分,表示从当前节点到结束节点的成本。与 G 部分不同,节点的 H 值根本不会改变(好吧,我在这里有疑问,可能有这样的启发式吗?,你的没有,所以让我们继续),它应该只计算一次。您的实现似乎使用曼哈顿距离作为启发式,这绝对是此类图的最佳启发式。但请注意我的朋友,那里似乎也存在一个小问题:应该单独取差异的绝对值,然后再求和。
F 是这些值的总和,表示从当前节点传递解决方案的可能成本(考虑到您的图表和启发式,任何计算出的 F 值都应该等于或小于实际成本,这很好)。
有了这些,我就可以使用这样的 SearchNode:
那么该算法可以这样实现:
关于上述实现,我想到的唯一问题是行
即使开放集实现为最小二叉堆,也没有简单的方法检查非最小 f 值节点的方法。我现在不记得细节了,但我记得用 logN 的复杂度来实现这个。此外,我的实现是在一次调用中访问和更改该节点的 g 值(如果有必要),因此您不必花时间再次检索它。无论g值是否改变,如果存在给定坐标的节点,则返回true,因此不会生成新节点。
当我写完所有这些之后,我意识到了最后一件事。您说过,对于给定的任何输入,您的实现都会计算出相同的结果。好吧,如果您提到的输入是障碍物节点,那么大多数情况下,无论它是什么实现,它都会找到相同的距离,因为它正在寻找最短的可能距离。在下图中我试图解释这一点。
I am assuming the graph is a regular rectangular grid that has obstacle nodes in it through which none of the solutions should pass. Moreover I am assuming traveling from a node to a neighbour node is 1. Also I realized that Manhattan Distance is used as the heuristic.
Given these, I am afraid yours is a misimplementation.
First of all instead of a recursive one you should use an iterative approach. Given the size of your graph, you would definitely get Stackoverflows if it was a correct implementation.
Secondly, there seems to be a problem about the concepts of GValue, HValue, FValue and/or cost. I feel obliged to give an informal description of these terms.
The simple formula A* uses is F = G + H where
G is the currently calculated cost of travelling from the start node to the current node. So, for the start node the Gvalue should be 0, any node reachable from the startNode should have a G value of 1 (my assumption was so, traveling from a node to a neighbour node) I would like to stress the 'currently' term here, because the gValue of a node may change during the run of the algorithm.
H is the heuristic part of the cost, denoting the cost from the current node to the end node. Unlike the G part, H value of a node does not change at all (well I have a doubt here, may there be such a heuristic?, yours does not so let's continue), it should be computed only once. Your implementation seems to be using the Manhattan Distance as the heuristic which is definitely the best heuristic for such a graph. But beware my friend, there seems to be a small problem there as well: the absolute values of the differences should be taken seperately and then be summed.
And the F is the sum of these values denoting the possible cost of having a solution passing from the current node (Given your graph and heuristic any calculated F value should be equal or less than the actual cost, which is good).
With these at hand I would have used a SearchNode like this:
Then the algorithm may be implemented like :
The only question pops to my mind about the above implementation is the line
Even if the open set is implemented as Min Binary Heap there is no easy way to check the non-minimum f valued nodes. I cant remember the details now but I remember implementing this one with logN complexity. Moreover my implementation was accessing and changing the g value of that node (if it is necessary) in one call, so you dont spent time retrieving it again. No matter if g value is changed, if there is a node with the given coordinates, it was returning true so no new node is generated.
One last thing I realized when I finished writing all these. You said, with any input given your implementation was calculating the same result. Well if the input you are mentioning is the obstacle nodes, then it will most of the time be the case that it will find, no matter what implementation it is, the same distance since it is looking for the shortest possible distance. In the below image I tried to explain that.
我的第一个猜测是每个节点都有固定的启发式成本。那么360可能是从哪里来的呢?
假设您使用曼哈顿距离启发式,(380-115) + (655-560) = 265 + 95 = 360
由于其格式,代码有点难以阅读。但我的猜测是您计算了起始节点的 h 值,并且您将其用于此后的每个节点。请记住 h(x) <= d(x,y) + h(y) 并为每个节点扩展计算它。
My first guess is that you have a fixed heuristic cost for each node. So might that 360 come from?
Assuming you're using a Manhattan Distance heuristic, (380-115) + (655-560) = 265 + 95 = 360
The code is a little difficult to read because of its formatting. But my guess is you calculated the h-value for the start node and you are using that for every node thereafter. Remember that h(x) <= d(x,y) + h(y) and calculate it for each node expansion.