为了账号安全,请及时绑定邮箱和手机立即绑定

如何在大空间尺度上加速A *算法?

/ 猿问

如何在大空间尺度上加速A *算法?

如何在大空间尺度上加速A *算法?

从http://ccl.northwestern.edu/netlogo/models/community/Astardemo,我通过使用网络中的节点来定义最低成本路径来编码A *算法。代码似乎有效,但是当我在大空间尺度上使用它时它太慢了。我的景观有1000个补丁x 1000个补丁,1个补丁= 1个像素。即使我减少400补丁x 400补丁1补丁= 1像素,它仍然太慢(我不能修改我的景观低于400补丁x 400补丁)。这是代码:


to find-path [ source-node destination-node] 


let search-done? false

let search-path []

let current-node 0

set list-open []

set list-closed []  

let list-links-with-nodes-in-list-closed []

let list-links []


set list-open lput source-node list-open

while [ search-done? != true]

[    

ifelse length list-open != 0

[

  set list-open sort-by [[f] of ?1 < [f] of ?2] list-open 

  set current-node item 0 list-open 

  set list-open remove-item 0 list-open 

  set list-closed lput current-node list-closed

  ask current-node

  [  

    if parent-node != 0[

    set list-links-with-nodes-in-list-closed lput link-with parent-node list-links-with-nodes-in-list-closed 

    ]

    ifelse any? (nodes-on neighbors4) with [ (xcor = [ xcor ] of destination-node) and (ycor = [ycor] of destination-node)]

    [

      set search-done? true 

    ]

    [        

      ask (nodes-on neighbors4) with [ (not member? self list-closed) and (self != parent-node) ]  

      [  

        if not member? self list-open and self != source-node and self != destination-node

        [

          set list-open lput self list-open

          set parent-node current-node

          set list-links sentence (list-links-with-nodes-in-list-closed) (link-with parent-node)

          set g sum (map [ [link-cost] of ? ] list-links)

          set h distance destination-node 

          set f (g + h)

        ]

      ]

    ]

  ]

]


[

  user-message( "A path from the source to the destination does not exist." )

  report []

 ]

]

set search-path lput current-node search-path

let temp first search-path

while [ temp != source-node ]

[

 ask temp

[

  set color red

]

不幸的是,我不知道如何加快这段代码。是否有解决方案在大空间尺度上快速计算最低成本路径?


查看完整描述

3 回答

?
拉莫斯之舞

很好奇所以我测试了我的A *,这是我的结果

迷宫1280 x 800 x 32位像素

  • 你可以看到花了~23ms

  • 没有多线程(AMD 3.2GHz)

  • C ++ 32位应用程序(如果你愿意,可以使用BDS2006 Turbo C ++或Borland C ++ builder 2006)

  • 我找到的最慢路径是~44ms(几乎填满整个地图)

我觉得这够快了......

这是我的A *类的来源:

//---------------------------------------------------------------------------

//---------------------------------------------------------------------------

//---------------------------------------------------------------------------

const DWORD A_star_space=0xFFFFFFFF;

const DWORD A_star_wall =0xFFFFFFFE;

//---------------------------------------------------------------------------

class A_star

    {

public:

    // variables

    DWORD **map;        // map[ys][xs]

    int xs,ys;          // map esolution   xs*ys<0xFFFFFFFE !!!

    int *px,*py,ps;     // output points px[ps],py[ps] after compute()


    // internals

    A_star();

    ~A_star();

    void _freemap();                                    // release map memory

    void _freepnt();                                    // release px,py memory


    // inteface

    void resize(int _xs,int _ys);                       // realloc map to new resolution

    void set(Graphics::TBitmap *bmp,DWORD col_wall);    // copy bitmap to map

    void get(Graphics::TBitmap *bmp);                   // draw map to bitmap for debuging

    void compute(int x0,int y0,int x1,int y1);          // compute path from x0,y0 to x1,y1 output to px,py

    };

//---------------------------------------------------------------------------

     A_star::A_star()   { map=NULL; xs=0; ys=0; px=NULL; py=NULL; ps=0; }

     A_star::~A_star()  { _freemap(); _freepnt(); }

void A_star::_freemap() { if (map) delete[] map; map=NULL; xs=0; ys=0; }

void A_star::_freepnt() { if (px) delete[] px; px=NULL; if (py) delete[] py; py=NULL; ps=0; }

//---------------------------------------------------------------------------

void A_star::resize(int _xs,int _ys)

    {

    if ((xs==_xs)&&(ys==_ys)) return;

    _freemap();

    xs=_xs; ys=_ys;

    map=new DWORD*[ys];

    for (int y=0;y<ys;y++)

     map[y]=new DWORD[xs];

    }

//---------------------------------------------------------------------------

void A_star::set(Graphics::TBitmap *bmp,DWORD col_wall)

    {

    int x,y;

    DWORD *p,c;

    resize(bmp->Width,bmp->Height);

    for (y=0;y<ys;y++)

     for (p=(DWORD*)bmp->ScanLine[y],x=0;x<xs;x++)

        {

        c=A_star_space;

        if (p[x]==col_wall) c=A_star_wall;

        map[y][x]=c;

        }

    }

//---------------------------------------------------------------------------

void A_star::get(Graphics::TBitmap *bmp)

    {

    int x,y;

    DWORD *p,c;

    bmp->SetSize(xs,ys);

    for (y=0;y<ys;y++)

     for (p=(DWORD*)bmp->ScanLine[y],x=0;x<xs;x++)

        {

        c=map[y][x];

             if (c==A_star_wall ) c=0x00000000;

        else if (c==A_star_space) c=0x00FFFFFF;

        else                      c=((c>>1)&0x7F)+0x00404040;

        p[x]=c;

        }

    }

//---------------------------------------------------------------------------

void A_star::compute(int x0,int y0,int x1,int y1)

    {

    int x,y,xmin,xmax,ymin,ymax,xx,yy;

    DWORD i,j,e;

    // [clear previous paths]

    for (y=0;y<ys;y++)

     for (x=0;x<xs;x++)

      if (map[y][x]!=A_star_wall)

       map[y][x]=A_star_space;

/*

    // [A* no-optimizatims]

    xmin=x0; xmax=x0; ymin=y0; ymax=y0;

    if (map[y0][x0]==A_star_space)

     for (i=0,j=1,e=1,map[y0][x0]=i;(e)&&(map[y1][x1]==A_star_space);i++,j++)

      for (e=0,y=ymin;y<=ymax;y++)

       for (   x=xmin;x<=xmax;x++)

        if (map[y][x]==i)

        {

        yy=y-1; xx=x; if ((yy>=0)&&(map[yy][xx]==A_star_space)){ map[yy][xx]=j; e=1; if (ymin>yy) ymin=yy; }

        yy=y+1; xx=x; if ((yy<ys)&&(map[yy][xx]==A_star_space)){ map[yy][xx]=j; e=1; if (ymax<yy) ymax=yy; }

        yy=y; xx=x-1; if ((xx>=0)&&(map[yy][xx]==A_star_space)){ map[yy][xx]=j; e=1; if (xmin>xx) xmin=xx; }

        yy=y; xx=x+1; if ((xx<xs)&&(map[yy][xx]==A_star_space)){ map[yy][xx]=j; e=1; if (xmax<xx) xmax=xx; }

        }

*/

    // [A* changed points list]

    // init space for 2 points list

    _freepnt();

    int i0=0,i1=xs*ys,n0=0,n1=0,ii;

    px=new int[i1*2];

    py=new int[i1*2];

    // if start is not on space then stop

    if (map[y0][x0]==A_star_space)

        {

        // init start position to first point list

        px[i0+n0]=x0; py[i0+n0]=y0; n0++; map[y0][x0]=0;

        // search until hit the destination (swap point lists after each iteration and clear the second one)

        for (j=1,e=1;(e)&&(map[y1][x1]==A_star_space);j++,ii=i0,i0=i1,i1=ii,n0=n1,n1=0)

         // test neibours of all points in first list and add valid new points to second one

         for (e=0,ii=i0;ii<i0+n0;ii++)

            {

            x=px[ii]; y=py[ii];

            yy=y-1; xx=x; if ((yy>=0)&&(map[yy][xx]==A_star_space)){ map[yy][xx]=j; e=1; px[i1+n1]=xx; py[i1+n1]=yy; n1++; map[yy][xx]=j; }

            yy=y+1; xx=x; if ((yy<ys)&&(map[yy][xx]==A_star_space)){ map[yy][xx]=j; e=1; px[i1+n1]=xx; py[i1+n1]=yy; n1++; map[yy][xx]=j; }

            yy=y; xx=x-1; if ((xx>=0)&&(map[yy][xx]==A_star_space)){ map[yy][xx]=j; e=1; px[i1+n1]=xx; py[i1+n1]=yy; n1++; map[yy][xx]=j; }

            yy=y; xx=x+1; if ((xx<xs)&&(map[yy][xx]==A_star_space)){ map[yy][xx]=j; e=1; px[i1+n1]=xx; py[i1+n1]=yy; n1++; map[yy][xx]=j; }

            }

        }

    // [reconstruct path]

    _freepnt();

    if (map[y1][x1]==A_star_space) return;

    if (map[y1][x1]==A_star_wall) return;

    ps=map[y1][x1]+1;

    px=new int[ps];

    py=new int[ps];

    for (i=0;i<ps;i++) { px[i]=x0; py[i]=y0; }

    for (x=x1,y=y1,i=ps-1,j=i-1;i>=0;i--,j--)

        {

        px[i]=x;

        py[i]=y;

        if ((y>   0)&&(map[y-1][x]==j)) { y--; continue; }

        if ((y<ys-1)&&(map[y+1][x]==j)) { y++; continue; }

        if ((x>   1)&&(map[y][x-1]==j)) { x--; continue; }

        if ((x<xs-0)&&(map[y][x+1]==j)) { x++; continue; }

        break;

        }

    }

//---------------------------------------------------------------------------

//---------------------------------------------------------------------------

//---------------------------------------------------------------------------

我知道它有点太多代码但它已经完成了。重要的是在成员函数中compute搜索[A* changed points list]。未经优化A*(重新编写)的速度大约慢100倍。


代码使用来自Borland VCL的位图,所以如果你没有它忽略函数get,set并将它们重写为输入/输出gfx样式。他们只是加载map从bitmap和借鉴计算map回bitmap


用法:


// init

A_star map;

Graphics::TBitmap *maze=new Graphics::TBitmap;

maze->LoadFromFile("maze.bmp");

maze->HandleType=bmDIB;

maze->PixelFormat=pf32bit;

map.set(maze,0); // walls are 0x00000000 (black)

// this can be called repetitive without another init

map.compute(x0,y0,x1,y1); // map.px[map.ps],map.py[map.ps] holds the path

map.get(maze,0); // this is just for drawing the result map back to bitmap for viewing


查看完整回答
反对 回复 2019-07-31
?
慕标5265247

A *是两种启发式方法; Djikstra的算法和贪婪搜索。Djikstra的算法搜索最短路径。贪婪搜索寻找最便宜的路径。Djikstra的算法非常慢,因为它没有冒险。将贪婪搜索的效果倍增以承担更多风险。

例如,如果A* = Djikstra + Greedy,则更快A* = Djikstra + 1.1 * Greedy。无论您如何优化内存访问或代码,都无法解决问题的不良方法。让你的A *更贪婪,它将专注于寻找解决方案,而不是一个完美的解决方案。

注意:

Greedy Search = distance from endDjikstra's Algorithm = distance from start

在标准A *中,它将寻求完美的解决方案,直到遇到障碍。该视频显示了不同的搜索启发式操作; 注意贪婪搜索的速度有多快(对于A *,请跳至2:22,对于贪婪,请跳至4:40)。当我第一次开始使用A *时,我自己也遇到了类似的问题,上面修改的A * I概述以指数方式提高了我的表现。故事的道德启示; 使用正确的工具来完成工作。


查看完整回答
反对 回复 2019-07-31
?
RISEBY

仅在您的节点列表(图表)中包含重要的补丁(或代理)!

加快速度的一种方法是不搜索每个网格空间。A *是图搜索,但似乎大多数编码器只是将网格中的每个点都转储到图中。这不是必需的。使用稀疏搜索图,而不是搜索屏幕上的每个点,可以加快速度。

即使在复杂的迷宫中,只需在图表中包含角点和交汇点,您就可以加快速度。不要在打开的列表中添加走廊网格 - 提前寻找下一个角落或交叉点。这是预处理屏幕/网格/地图以构建搜索图形的地方,可以节省时间。

正如你在turtlezero.com上我的(相当低效的)A *模型中所看到的那样,一种天真的方法会产生许多额外的步骤。在长直道中创建的任何开放节点都被浪费了:

通过从图中消除这些步骤,可以更快地找到解决方案数百倍。

另一种稀疏图形技术是使用距离步行者越来越密集的图形。也就是说,让你的搜索空间在助行器附近细化,并且远离助行器的稀疏(更少的节点,对障碍更不准确)。当步行者在正在改变的地图上移动或者朝向正在移动的目标移动并且无论如何都必须重新计算路线时,这尤其有用。

例如,在交通模拟中,道路可能会堵塞,或发生事故。同样,模拟一个代理人在不断变化的环境中追求另一个代理人。在这些情况下,只需准确绘制下几个步骤。到目的地的一般路线可以是近似的。

实现此目的的一种简单方法是随着路径变长而逐渐增加助行器的步长。忽视障碍物或进行快速线交叉或切线测试。这让步行者大致了解了去哪里。

可以使用每个步骤或周期性地或在遇到障碍物时重新计算改进的路径。

它可能只有几毫秒的节省,但在路径即将改变的末端浪费的毫秒可以更好地用于为更多的步行者提供大脑,或更好的图形,或与家人更多的时间。

有关不同密度的稀疏图的示例,请参阅APress的David Wallace Croft的高级Java编程的第8章:http//www.apress.com/game-programming/java/9781590591239

他在一个演示坦克游戏中使用了一个增加稀疏度的圆形图表,其中一个*算法驱动了敌人的坦克。

另一种稀疏图方法是仅使用感兴趣的点来填充图形。例如,要在简单的建筑物校园中绘制路线,只有入口,出口和拐角才是重要的。沿建筑物侧面或开放空间之间的点不重要,可以从搜索图中省略。更详细的地图可能需要更多的路点 - 例如喷泉或雕像周围的一圈节点,或铺砌路径相交的地方。

这是一个显示航点之间路径的图表。

这是由我在turtlezero.com上的校园建筑路径图模型生成的:http://www.turtlezero.com/models/view.php?model =campus-buildings-path-graph

它使用简单的netlogo补丁查询来查找感兴趣的点,如外角和内角。我确信一组更复杂的查询可以处理像对角墙这样的事情。但即使没有这种花哨的进一步优化,A *搜索空间也会减少几个数量级。

不幸的是,由于现在Java 1.7不允许使用未签名的applet,因此如果不调整java安全设置,则无法在网页中运行该模型。对于那个很抱歉。但请阅读说明。


查看完整回答
反对 回复 2019-07-31
  • 3 回答
  • 0 关注
  • 186 浏览
我要回答

相关问题推荐

慕课专栏
更多

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信