アントコロニーの最適化

アリコロニーの最適化

1. 前書き

The aim of this seriesexplain the idea of genetic algorithms and show the most known implementationsになります。

このチュートリアルでは、describe the concept of the ant colony optimization(ACO)に続いて、コード例を示します。

2. ACOの仕組み

ACOは、アリの自然な行動に触発された遺伝的アルゴリズムです。 ACOアルゴリズムを完全に理解するには、その基本概念に精通する必要があります。

  • アリはフェロモンを使用して、家と食料源の間の最短経路を見つけます

  • フェロモンはすぐに蒸発する

  • アリは、より密度の高いフェロモンでより短い経路を使用することを好む

Traveling Salesman Problemで使用されるACOの簡単な例を示しましょう。 次の場合、グラフ内のすべてのノード間の最短パスを見つける必要があります。

 

image自然な行動に続いて、アリは探索中に新しい道を探索し始めます。 濃い青色は他のパスよりも頻繁に使用されるパスを示し、緑色は見つかった現在の最短パスを示します。

 

imageその結果、すべてのノード間の最短パスを実現します。

 

image ACOテスト用の優れたGUIベースのツールはhereにあります。

3. Java実装

3.1. ACOパラメータ

AntColonyOptimizationクラスで宣言されているACOアルゴリズムの主なパラメータについて説明しましょう。

private double c = 1.0;
private double alpha = 1;
private double beta = 5;
private double evaporation = 0.5;
private double Q = 500;
private double antFactor = 0.8;
private double randomFactor = 0.01;

パラメータcは、シミュレーション開始時の元のトレイル数を示します。 さらに、alphaはフェロモンの重要性を制御し、betaは距離の優先度を制御します。 In general, the beta parameter should be greater than alpha for the best results.

次に、evaporation変数は、反復ごとにフェロモンが蒸発する量のパーセントを示します。一方、Qは、各Antによってトレイルに残っているフェロモンの総量に関する情報を提供します。 (t3)sは、都市ごとに使用するアリの数を示します。

最後に、シミュレーションで少しランダムにする必要があります。これはrandomFactorでカバーされます。

3.2. アリを作成する

Antは、特定の都市を訪問し、訪問したすべての都市を記憶し、トレイルの長さを追跡することができます。

public void visitCity(int currentIndex, int city) {
    trail[currentIndex + 1] = city;
    visited[city] = true;
}

public boolean visited(int i) {
    return visited[i];
}

public double trailLength(double graph[][]) {
    double length = graph[trail[trailSize - 1]][trail[0]];
    for (int i = 0; i < trailSize - 1; i++) {
        length += graph[trail[i]][trail[i + 1]];
    }
    return length;
}

3.3. アリのセットアップ

最初に、トレイルとアリの行列を提供して、initialize our ACO code implementationにする必要があります。

graph = generateRandomMatrix(noOfCities);
numberOfCities = graph.length;
numberOfAnts = (int) (numberOfCities * antFactor);

trails = new double[numberOfCities][numberOfCities];
probabilities = new double[numberOfCities];
ants = new Ant[numberOfAnts];
IntStream.range(0, numberOfAnts).forEach(i -> ants.add(new Ant(numberOfCities)));

次に、ランダムな都市から開始するためにsetup the ants matrixを実行する必要があります。

public void setupAnts() {
    IntStream.range(0, numberOfAnts)
      .forEach(i -> {
          ants.forEach(ant -> {
              ant.clear();
              ant.visitCity(-1, random.nextInt(numberOfCities));
          });
      });
    currentIndex = 0;
}

ループの反復ごとに、次の操作を実行します。

IntStream.range(0, maxIterations).forEach(i -> {
    moveAnts();
    updateTrails();
    updateBest();
});

3.4. アリを動かす

moveAnts()メソッドから始めましょう。 各アリが他のアリの軌跡をたどろうとしていることを覚えておく必要があります。

public void moveAnts() {
    IntStream.range(currentIndex, numberOfCities - 1).forEach(i -> {
        ants.forEach(ant -> {
            ant.visitCity(currentIndex, selectNextCity(ant));
        });
        currentIndex++;
    });
}

The most important part is to properly select next city to visit.確率論理に基づいて次の町を選択する必要があります。 まず、Antがランダムな都市を訪問する必要があるかどうかを確認できます。

int t = random.nextInt(numberOfCities - currentIndex);
if (random.nextDouble() < randomFactor) {
    OptionalInt cityIndex = IntStream.range(0, numberOfCities)
      .filter(i -> i == t && !ant.visited(i))
      .findFirst();
    if (cityIndex.isPresent()) {
        return cityIndex.getAsInt();
    }
}

ランダムな都市を選択しなかった場合は、次の都市を選択する確率を計算する必要があります。アリは、より強く短い道をたどることを好むことを覚えておいてください。 これを行うには、配列内の各都市に移動する確率を保存します。

public void calculateProbabilities(Ant ant) {
    int i = ant.trail[currentIndex];
    double pheromone = 0.0;
    for (int l = 0; l < numberOfCities; l++) {
        if (!ant.visited(l)){
            pheromone
              += Math.pow(trails[i][l], alpha) * Math.pow(1.0 / graph[i][l], beta);
        }
    }
    for (int j = 0; j < numberOfCities; j++) {
        if (ant.visited(j)) {
            probabilities[j] = 0.0;
        } else {
            double numerator
              = Math.pow(trails[i][j], alpha) * Math.pow(1.0 / graph[i][j], beta);
            probabilities[j] = numerator / pheromone;
        }
    }
}

確率を計算した後、以下を使用して、どの都市に行くかを決定できます。

double r = random.nextDouble();
double total = 0;
for (int i = 0; i < numberOfCities; i++) {
    total += probabilities[i];
    if (total >= r) {
        return i;
    }
}

3.5. トレイルの更新

この手順では、トレイルと左フェロモンを更新する必要があります。

public void updateTrails() {
    for (int i = 0; i < numberOfCities; i++) {
        for (int j = 0; j < numberOfCities; j++) {
            trails[i][j] *= evaporation;
        }
    }
    for (Ant a : ants) {
        double contribution = Q / a.trailLength(graph);
        for (int i = 0; i < numberOfCities - 1; i++) {
            trails[a.trail[i]][a.trail[i + 1]] += contribution;
        }
        trails[a.trail[numberOfCities - 1]][a.trail[0]] += contribution;
    }
}

3.6. 最適なソリューションを更新する

これは、各反復の最後のステップです。 参照を維持するには、最適なソリューションを更新する必要があります。

private void updateBest() {
    if (bestTourOrder == null) {
        bestTourOrder = ants[0].trail;
        bestTourLength = ants[0].trailLength(graph);
    }
    for (Ant a : ants) {
        if (a.trailLength(graph) < bestTourLength) {
            bestTourLength = a.trailLength(graph);
            bestTourOrder = a.trail.clone();
        }
    }
}

すべての反復の後、最終結果はACOによって検出された最適なパスを示します。 Please note that by increasing the number of cities, the probability of finding the shortest path decreases.

4. 結論

このチュートリアルintroduces the Ant Colony Optimization algorithm。 この分野の遺伝的アルゴリズムwithout any previous knowledgeについては、基本的なコンピュータープログラミングスキルしか持っていないので学ぶことができます。

このチュートリアルのコードスニペットの完全なソースコードは、in the GitHub projectで入手できます。

遺伝的アルゴリズムの他の例を含むこのシリーズのすべての記事については、次のリンクをご覧ください。