1. 程式人生 > >幹貨 | 自適應大鄰域搜索(Adaptive Large Neighborhood Search)入

幹貨 | 自適應大鄰域搜索(Adaptive Large Neighborhood Search)入

是把 文獻 數據 png 等等 指數 pair current ssi

01 首先來區分幾個概念

關於neighborhood serach,這裏有好多種衍生和變種出來的胡裏花俏的算法。大家在上網搜索的過程中可能看到什麽Large Neighborhood Serach,也可能看到Very Large Scale Neighborhood Search或者今天介紹的Adaptive Large Neighborhood Search。

對於這種名字相近,實則大有不同的概念,很是讓小編這樣的新手頭疼。不過,小編喜歡凡事都要弄得清清楚楚明明白白的。為了防止大家混淆這些相近的概念,今天這裏一並介紹了吧。

總體關系可以看下圖:
技術分享圖片

當一個鄰域搜索算法搜索的鄰域隨著搜索的數據規模大小而呈指數增長,或者鄰域太大而不能在實際中明確搜索時,我們把這類鄰域搜索算法歸類為Very Large-Scale Neighborhood Search(VLSN)。

VLSN又可以分為三類:

  • Variable-depth methods
  • Network-flows based improvement algorithms
  • Efficiently solvable special cases

而Large Neighborhood Search(LNS) 則不屬於以上三種類型,但是它是屬於VLSN這種類型的,因為它搜索的是一個非常大的鄰域。

最後呢,是Adaptive Large Neighborhood Search(ALNS),它是根據Large Neighborhood Search(LNS) 算法擴展和延伸而來(嗯,相當於爸爸和兒子的關系……)。

由於文章篇幅呢,小編這裏就不給大家一一介紹了。具體內容可以看文章後面給出的參考文獻。下面給大家科普幾個必要的概念。

1.0 什麽是Neighborhood Search(NS)

鄰域搜索算法(或稱為局部搜索算法)是一類非常廣泛的改進算法,其在每次叠代時通過搜索當前解的“鄰域”找到更優的解。 鄰域搜索算法設計中的關鍵是鄰域結構的選擇,即鄰域定義的方式。 根據以往的經驗,鄰域越大,局部最優解就越好,這樣獲得的全局最優解就越好。 但是,與此同時,鄰域越大,每次叠代搜索鄰域所需的時間也越長。 出於這個原因,除非能夠以非常有效的方式搜索較大的鄰域,否則啟發式搜索也得不到很好的效果。

什麽又是鄰域呢?小編不得不再次帶大家回顧一下以前的知識:

官方一點:所謂鄰域,簡單的說即是給定點附近其它點的集合。在距離空間中,鄰域一般被定義為以給定點為圓心的一個圓;而在組合優化問題中,鄰域一般定義為由給定轉化規則對給定的問題域上每結點進行轉化所得到的問題域上結點的集合 (太難懂了 嗚嗚嗚.....)。

通俗一點:鄰域就是指對當前解進行一個操作(這個操作可以稱之為鄰域動作)可以得到的所有解的集合。那麽不同鄰域的本質區別就在於鄰域動作的不同了。

鄰域動作又是什麽鬼?沒關系,咱們在回顧一下:

鄰域動作是一個函數,通過這個函數,對當前解s,產生其相應的鄰居解集合。例如:對於一個bool型問題,其當前解為:s = 1001,當將鄰域動作定義為翻轉其中一個bit時,得到的鄰居解的集合N(s)={0001,1101,1011,1000},其中N(s) ∈ S。同理,當將鄰域動作定義為互換相鄰bit時,得到的鄰居解的集合N(s)={0101,1001,1010}。

礙於文章篇幅,小編就不再深入介紹了。不過小編給大家找了一個比較詳細的定義,大家可以看看:

技術分享圖片

1.1 什麽是Very Large Scale Neighborhood Search (VLSN)

正如前面所說的一樣,對於一個鄰域搜索算法,當其鄰域大小隨著輸入數據的規模大小呈指數增長的時候,那麽我們就可以稱該鄰域搜索算法為超大規模鄰域搜索算法(Very Large Scale Neighborhood Search Algorithm,VLSNA )。

一些超大規模的鄰域搜索方法已經運用於運籌學之中了,並且取得了不錯的效果。 例如,如果將求解線性規劃的單純形算法看成鄰域搜索算法的話,那麽列生成算法就是一種超大規模的鄰域搜索方法。 此外,用於解決許多網絡流問題的方法也可以歸類為超大規模的鄰域搜索方法。 用於求解最小費用流問題的negative cost cycle canceling algorithm和用於求解分配問題的augmenting path algorithm就是兩個例子。

有關於VLSN我們就介紹這麽多啦。不過小編還是把Wikipedia上關於VLSN的定義也放上來給大家看看吧:

In?mathematical optimization,?neighborhood search?is a technique that tries to find good or near-optimal solutions to a combinatorial optimisation problem by repeatedly transforming a current solution into a different solution in the neighborhood?of the current solution. The neighborhood of a solution is a set of similar solutions obtained by relatively simple modifications to the original solution. For a?very large-scale neighborhood search, the neighborhood is large and possibly exponentially sized.

The resulting algorithms can outperform algorithms using small neighborhoods because the local improvements are larger. If neighborhood searched is limited to just one or a very small number of changes from the current solution, then it can be difficult to escape from local minima, even with additional meta-heuristic techniques such as?Simulated Annealing?or?Tabu search. In large neighborhood search techniques, the possible changes from one solution to its neighbor may allow tens or hundreds of values to change, and this means that the size of the neighborhood may itself be sufficient to allow the search process to avoid or escape local minima, though additional meta-heuristic techniques can still improve performance.

1.2 什麽是Large Neighborhood Serach(LNS)

大多數鄰域搜索算法都明確定義它們的鄰域,如在上面1.0 節小編給出的詳細定義中描述的那樣。 在LNS中,鄰域是由destroy和repair方法隱式定義的。destroy方法會破壞當前解的一部分,而後repair方法會對被破壞的解進行重建。destroy方法通常包含隨機性的元素,以便在每次調用destroy方法時破壞解的不同部分。 那麽,解x的鄰域N(x)就可以定義為:首先通過利用destroy方法破壞解x,然後利用repair方法重建解x,從而得到的一系列解的集合。

1.3 什麽是Adaptive Large Neighborhood Search (ALNS)

我們前面說過,ALNS是從LNS發展擴展而來的,在了解了LNS以後,我們現在來看看ALNS。ALNS在LSN的基礎上,允許在同一個搜索中使用多個destroy和repair方法來獲得當前解的鄰域。

ALNS會為每個destroy和repair方法分配一個權重,通過該權重從而控制每個destroy和repair方法在搜索期間使用的頻率。 在搜索的過程中,ALNS會對各個destroy和repair方法的權重進行動態調整,以便獲得更好的鄰域和解。簡單點解釋,ALNS和LNS不同的是,ALNS通過使用多種destroy和repair方法,然後再根據這些destroy和repair方法生成的解的質量,選擇那些表現好的destroy和repair方法,再次生成鄰域進行搜索。

02 ALNS具體過程

2.1 你們一定想知道destroy和repair方法是什麽?

關於destroy和repair方法,這兩個小老弟在LNS和ALSN中是要組合在一起使用的,待會你們就明白了。其實,一個解x經過destroy和repair方法以後,實則是相當於經過了一個鄰域動作的變換。如下圖所示:
技術分享圖片

上圖是三個CVRP問題的解(別問我什麽是CVRP問題!!!),上左表示的是當前解,上右則是經過了destroy方法以後的解(移除了6個customers),下面表示由上右的解經過repair方法以後最終形成的解(重新插入了一些customers)。

哎哎哎!等等,小編剛剛不是說當前解x經過destroy和repair方法以後生成的是一個鄰域(鄰居解的集合)嗎?上面才生成一個解呀!

其實,上面展示的只是生成鄰域中一個解的過程而已,實際整個鄰域還有很多其他可能的解。比如在一個CVRP問題中,將destroy方法定義為:移除當前解x中15%的customers。假如當前的解x中有100名customers,那麽就有C(100,15)= 100!/(15!×85!) =2.5×10的17次方 種移除的方式。並且,根據每一種移除方式,又可以有很多種修復的方法。這樣下來,一對destroy和repair方法能生成非常多的鄰居解,而這些鄰居解的集合,就是鄰域了。

2.2 LNS具體流程

我們說過,ALNS是由LNS擴展而來的,在了解ALNS之前,我們不妨來了解一下LNS的具體流程。下面是LNS的偽代碼:

技術分享圖片

LNS算法中包含三個變量。變量xb記錄目前為止獲得的最優解,x則表示當前解,而xt是臨時解(便於回退到之前解的狀態)。函數d(·)是destroy方法,而r(·)是repair方法。詳細點就是,d(x)表示破壞解x的部分,而r(x)則表示對破壞的解進行重新修復。

在第2行中,初始化了全局最優解。在第4行中,算法首先用destroy方法,然後再用repair方法來獲得新的解xt。在第5行中,評估新解xt的好壞,並以此確定該新解xt是否應該成為當前新的解決x(第6行)。評估的方式因具體程序而異,可以有很多種。最簡單的評估方式就只接受那些變得更優的解。

第8行檢查新解x是否優於全局最優解xb。此處 c(x)表示解x的目標函數值。如果新獲得的解x更優,那麽第9行將會更新全局最優解xb。在第11行中,檢查終止條件。

在第12行中,返回找到的全局最優解xb。

從偽代碼可以註意到,LNS算法不會搜索解的整個鄰域,而只是對該鄰域進行采樣搜索。

2.3 ALNS的具體流程

好了,介紹完了LNS的具體流程,終於到今天的主角ALSN了。在理解了LNS的基礎上,理解ALSN也非常easy了。前面說過,ALSN對LNS進行了擴展,它允許在一次搜索中搜索多個鄰域(使用多組不同的destroy和repair方法)。至於搜索哪個鄰域呢,ALSN會根據鄰域解的質量好壞,動態進行選擇調整。好啦,來看偽代碼:
技術分享圖片

上面就是ALNS偽代碼。相對於LNS來說,新增了第4行和第12行,修改了第2行。

??和?+分別表示destroy和repair方法的集合。

第2行中的ρ?和ρ+分別表示各個destroy和repair方法的權重集合。一開始時,所有的方法都設置相同的權重。

第4行根據ρ?和ρ+選擇destroy和repair方法。至於選擇哪個方法的可能性大小,是由下面公式算出的:
技術分享圖片

總的來說,權重越大,被選中的可能性越大。

除此之外,權重大小是根據destroy和repair方法的在搜索過程中的表現進行動態調整的(第12行)。具體是怎麽調整的呢?這裏也給大家說一說:
在ALNS完成一次叠代搜索以後,我們使用下面的函數為每組destroy和repair方法的好壞進行一個評估:
技術分享圖片

其中,ω1≥ω2≥ω3≥ω4≥0。

假如,a和b是上次叠代中使用的destroy和repair方法。那麽其權重更新如下所示:

技術分享圖片

其中,λ∈[0,1],為參數。再給大家看個圖:
技術分享圖片

在一個ALNS算法中,有很多個鄰域,每個鄰域都可以看做是一組destroy和repair方法生成的。

礙於文章篇幅原因,今天就先不上代碼了。大家先把這些概念好好理解消化了先。後面小編會把代碼和詳細解釋做成一篇篇文章推送給大家的。謝謝!

喜歡的話可以掃碼關註我們的公眾號【程序猿聲】哦,更多精彩盡在微信公眾號【程序猿聲】

幹貨 | 自適應大鄰域搜索(Adaptive Large Neighborhood Search)入