最近由于畢設在研究OMNet++,一頭霧水,主要過去學習不認真,現在發現不但新知識學習的亂七八糟,主要是過去的東西也亂七八糟,所以學習和人生都是一個慢慢積累慢慢豐富的過程。
  發現了個螞蟻算法,相關內容附上,做個筆記。
蟻群算法(ant colony optimization, ACO),又稱螞蟻算法,是一種用來在圖中尋找優化路徑的機率型技術。它由Marco Dorigo于1992年在他的博士論文中引入,其靈感來源于螞蟻在尋找食物過程中發現路徑的行為。
為什么小小的螞蟻能夠找到食物?他們具有智能么?設想,如果我們要為螞蟻設計一個人工智能的程 序,那么這個程序要多么復雜呢?首先,你要讓螞蟻能夠避開障礙物,就必須根據適當的地形給它編進指令讓他們能夠巧妙的避開障礙物,其次,要讓螞蟻找到食 物,就需要讓他們遍歷空間上的所有點;再次,如果要讓螞蟻找到最短的路徑,那么需要計算所有可能的路徑并且比較它們的大小,而且更重要的是,你要小心翼翼 的編程,因為程序的錯誤也許會讓你前功盡棄。這是多么不可思議的程序!太復雜了,恐怕沒人能夠完成這樣繁瑣冗余的程序。
然而,事實并沒有你想得那么復雜,上面這個程序每個螞蟻的核心程序編碼不過100多行!為什么 這么簡單的程序會讓螞蟻干這樣復雜的事情?答案是:簡單規則的涌現。事實上,每只螞蟻并不是像我們想象的需要知道整個世界的信息,他們其實只關心很小范圍 內的眼前信息,而且根據這些局部信息利用幾條簡單的規則進行決策,這樣,在蟻群這個集體里,復雜性的行為就會凸現出來。這就是人工生命、復雜性科學解釋的 規律!那么,這些簡單規則是什么呢?下面詳細說明:
1、范圍:
螞蟻觀察到的范圍是一個方格世界,螞蟻有一個參數為速度半徑(一般是3),那么它能觀察到的范圍就是3*3個方格世界,并且能移動的距離也在這個范圍之內。
2、環境:
螞蟻所在的環境是一個虛擬的世界,其中有障礙物,有別的螞蟻,還有信息素,信息素有兩種,一種是找到食物的螞蟻灑下的食物信息素,一種是找到窩的螞蟻灑下的窩的信息素。每個螞蟻都僅僅能感知它范圍內的環境信息。環境以一定的速率讓信息素消失。
3、覓食規則:
在每只螞蟻能感知的范圍內尋找是否有食物,如果有就直接過去。否則看是否有信息素,并且比較在 能感知的范圍內哪一點的信息素最多,這樣,它就朝信息素多的地方走,并且每只螞蟻多會以小概率犯錯誤,從而并不是往信息素最多的點移動。螞蟻找窩的規則和 上面一樣,只不過它對窩的信息素做出反應,而對食物信息素沒反應。
4、移動規則:
每只螞蟻都朝向信息素最多的方向移,并且,當周圍沒有信息素指引的時候,螞蟻會按照自己原來運 動的方向慣性的運動下去,并且,在運動的方向有一個隨機的小的擾動。為了防止螞蟻原地轉圈,它會記住最近剛走過了哪些點,如果發現要走的下一點已經在最近 走過了,它就會盡量避開。
5、避障規則:
如果螞蟻要移動的方向有障礙物擋住,它會隨機的選擇另一個方向,并且有信息素指引的話,它會按照覓食的規則行為。
7、播撒信息素規則:
每只螞蟻在剛找到食物或者窩的時候撒發的信息素最多,并隨著它走遠的距離,播撒的信息素越來越少。
根據這幾條規則,螞蟻之間并沒有直接的關系,但是每只螞蟻都和環境發生交互,而通過信息素這個 紐帶,實際上把各個螞蟻之間關聯起來了。比如,當一只螞蟻找到了食物,它并沒有直接告訴其它螞蟻這兒有食物,而是向環境播撒信息素,當其它的螞蟻經過它附 近的時候,就會感覺到信息素的存在,進而根據信息素的指引找到了食物。
說了這么多,螞蟻究竟是怎么找到食物的呢?
在沒有螞蟻找到食物的時候,環境沒有有用的信息素,那么螞蟻為什么會相對有效的找到食物呢?這 要歸功于螞蟻的移動規則,尤其是在沒有信息素時候的移動規則。首先,它要能盡量保持某種慣性,這樣使得螞蟻盡量向前方移動(開始,這個前方是隨機固定的一 個方向),而不是原地無謂的打轉或者震動;其次,螞蟻要有一定的隨機性,雖然有了固定的方向,但它也不能像粒子一樣直線運動下去,而是有一個隨機的干擾。 這樣就使得螞蟻運動起來具有了一定的目的性,盡量保持原來的方向,但又有新的試探,尤其當碰到障礙物的時候它會立即改變方向,這可以看成一種選擇的過程, 也就是環境的障礙物讓螞蟻的某個方向正確,而其他方向則不對。這就解釋了為什么單個螞蟻在復雜的諸如迷宮的地圖中仍然能找到隱蔽得很好的食物。
當然,在有一只螞蟻找到了食物的時候,其他螞蟻會沿著信息素很快找到食物的。
螞蟻如何找到最短路徑的?這一是要歸功于信息素,另外要歸功于環境,具體說是計算機時鐘。信息 素多的地方顯然經過這里的螞蟻會多,因而會有更多的螞蟻聚集過來。假設有兩條路從窩通向食物,開始的時候,走這兩條路的螞蟻數量同樣多(或者較長的路上螞 蟻多,這也無關緊要)。當螞蟻沿著一條路到達終點以后會馬上返回來,這樣,短的路螞蟻來回一次的時間就短,這也意味著重復的頻率就快,因而在單位時間里走 過的螞蟻數目就多,灑下的信息素自然也會多,自然會有更多的螞蟻被吸引過來,從而灑下更多的信息素……;而長的路正相反,因此,越來越多地螞蟻聚集到較短 的路徑上來,最短的路徑就近似找到了。也許有人會問局部最短路徑和全局最短路的問題,實際上螞蟻逐漸接近全局最短路的,為什么呢?這源于螞蟻會犯錯誤,也 就是它會按照一定的概率不往信息素高的地方走而另辟蹊徑,這可以理解為一種創新,這種創新如果能縮短路途,那么根據剛才敘述的原理,更多的螞蟻會被吸引過 來。
引申:
跟著螞蟻的蹤跡,你找到了什么?通過上面的原理敘述和實際操作,我們不難發現螞蟻之所以具有智能行為,完全歸功于它的簡單行為規則,而這些規則綜合起來具有下面兩個方面的特點:
1、多樣性
2、正反饋
多樣性保證了螞蟻在覓食的時候不置走進死胡同而無限循環,正反饋機制則保證了相對優良的信息能 夠被保存下來。我們可以把多樣性看成是一種創造能力,而正反饋是一種學習強化能力。正反饋的力量也可以比喻成權威的意見,而多樣性是打破權威體現的創造 性,正是這兩點小心翼翼的巧妙結合才使得智能行為涌現出來了。
引申來講,大自然的進化,社會的進步、人類的創新實際上都離不開這兩樣東西,多樣性保證了系統 的創新能力,正反饋保證了優良特性能夠得到強化,兩者要恰到好處的結合。如果多樣性過剩,也就是系統過于活躍,這相當于螞蟻會過多的隨機運動,它就會陷入 混沌狀態;而相反,多樣性不夠,正反饋機制過強,那么系統就好比一潭死水。這在蟻群中來講就表現為,螞蟻的行為過于僵硬,當環境變化了,螞蟻群仍然不能適 當的調整。
既然復雜性、智能行為是根據底層規則涌現的,既然底層規則具有多樣性和正反饋特點,那么也許你 會問這些規則是哪里來的?多樣性和正反饋又是哪里來的?我本人的意見:規則來源于大自然的進化。而大自然的進化根據剛才講的也體現為多樣性和正反饋的巧妙 結合。而這樣的巧妙結合又是為什么呢?為什么在你眼前呈現的世界是如此栩栩如生呢?答案在于環境造就了這一切,之所以你看到栩栩如生的世界,是因為那些不 能夠適應環境的多樣性與正反饋的結合都已經死掉了,被環境淘汰了!
參數說明:
最大信息素:螞蟻在一開始擁有的信息素總量,越大表示程序在較長一段時間能夠存在信息素。信息素消減的速度:隨著時間的流逝,已經存在于世界上的信息素會消減,這個數值越大,那么消減的越快。
錯誤概率表示這個螞蟻不往信息素最大的區域走的概率,越大則表示這個螞蟻越有創新性。
速度半徑表示螞蟻一次能走的最大長度,也表示這個螞蟻的感知范圍。
記憶能力表示螞蟻能記住多少個剛剛走過點的坐標,這個值避免了螞蟻在本地打轉,停滯不前。而這個值越大那么整個系統運行速度就慢,越小則螞蟻越容易原地轉圈。
-----例子-----
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>蟻群算法js版</title>
<style>
.ant{
position:absolute;
background-color:#000000;
overflow:hidden;
width:2px;
height:2px;
}
.food{
position:absolute;
background-color:#0000ff;
overflow:hidden;
width:2px;
height:2px;
}
.nest{
position:absolute;
background-color:#ff0000;
overflow:hidden;
width:2px;
height:2px;
}
</style>
<script type="text/JavaScript">
//============================
//系統參數初始化
//----------------------------
//生命體數量與軌跡長度
Unit=10;Path=30;
//生命體速度上下限
v0=2;vM=10;
//生命體加速度變化范圍
Kr=0.1;Kv=0.1*(vM-v0);
//生命體運動范圍
x0=0;xM=document.documentElement.clientWidth;
y0=0;yM=document.documentElement.clientHeight;
//生命體出生地(巢穴)
xi0=x0+(xM-x0)*Math.random();
yi0=y0+(yM-y0)*Math.random();
str0='<div class="ant" style="left:'+xi0+';top:'+yi0+';"></div>';
//食物所在地
xf=x0+(xM-x0)*Math.random();
yf=y0+(yM-y0)*Math.random();
//氣味感知范圍
R_2=5*5;
//============================
var r=new Array();
var v=new Array();
var dr=new Array();
var dv=new Array();
var x=new Array();
var y=new Array();
var life=new Array();
//單擊暫停
var xi0,yi0,xf,yf;
var Time0,str0;
window.status='pause';
function document.onclick(){
        if(window.status=='pause'){
                window.status=0;
                nest.style.left=xi0;
                nest.style.top=yi0;
                food.style.left=xf;
                food.style.top=yf;
                //測試初始化時間用
                Time0=(new Date()).getTime();
                init(0);
        }else{
                window.status='pause';
        }
}
//窗口大小調整后刷新頁面以調整系統參數
function window.onresize(){
//        window.location.href=document.location;
}
//初始化函數
function init(i){
        if(window.status!='pause'&&i<Unit){
                if(!life){
                          document.body.appendChild(life=document.createElement(str0));
                          x=xi0;
                          y=yi0;
                          r=Math.random();
                          v=1/Math.random();
                          dr=Kr*Math.random();
                          dv=Kv*Math.random();
                  }
                  Move(i);
                  window.status=i+1;
                  setTimeout('init('+(i+1)+')',i);
  //        }else{
  //                alert('生成耗時:'+((new Date()).getTime()-Time0)+'ms');
          }
  }
  //運動函數
  Total=Unit*Path;
  P2=2*Math.PI;
  function Move(i){
          if(window.status!='pause'){
                  k=i%Unit;
                  X=x[k];
                  Y=y[k];
                  R=r[k];
                  V=v[k];               
                  if(!life){
                          str='<div class="ant" style="left:'+X+';top:'+Y+';"></div>';
                          document.body.appendChild(life=document.createElement(str));
                  }
                  obj=life;
                  R+=dr[k]*(2*Math.random()-1);
                  V+=dv[k]*(2*Math.random()-1);
                  X+=Math.sin(P2*R)*V;
                  Y+=Math.cos(P2*R)*V;
                  //遇到食物原路返回并減小角度變化
                  distance=(X-xf)*(X-xf)+(Y-yf)*(Y-yf);
                  if(distance<R_2){
                          R+=0.5;
                          r/=2;
                          v*=2;
                  }
                  distance=(X-xi0)*(X-xi0)+(Y-yi0)*(Y-yi0);
                  if(distance<R_2){
                          R+=0.5;
                          r/=2;
                          v*=2;
                  }
                  /*----------------------------------
                  /*================================*/
                  //碰撞邊界反彈
                  R=(X<x0||X>xM)?-R:R;
                  R=(Y<y0||Y>yM)?0.5-R:R;
                  X=x[k]+Math.sin(P2*R)*V;
                  Y=y[k]+Math.cos(P2*R)*V;
                  /*================================*/
                  //溢出邊界重生(類似流星效果)
                  if(X<x0||X>xM||Y<y0||Y>yM){
                          X=xi0;
                          Y=yi0;
                  }
                  /*----------------------------------
                  /*================================*/
                  //邊界限制
                  x[k]=X=(X<x0)?x0:(X>xM)?xM-2:X;
                  y[k]=Y=(Y<y0)?y0:(Y>yM)?yM-2:Y;
                  r[k]=R>1?R-1:R<0?R+1:R;
                  v[k]=V=(V<v0)?v0:((V<vM)?V:vM);
                  /*================================*/
                  obj.style.left=x[k]=X;
                  obj.style.top=y[k]=Y;
                  setTimeout('Move('+(i+Unit)%Total+')',Unit);
          }
  }
  //根據瀏覽器自動加載動畫
  switch(navigator.appName.toLowerCase()){
          case "netscape":
                  window.addEventListener("load",document.onclick,false);
          break;
          case "microsoft internet explorer":
          default:
                  window.attachEvent("onload",document.onclick);
          break;
  }
  </script>
  </head>
  <body scroll="no">
  <div id="food" class="food"></div>
  <div id="nest" class="nest"></div>
  </body>
  </html>