八皇后問題和八數碼問題的最陡上升爬山法、首選爬山法、隨機重啓爬山法、模擬退火算法的分析和實現

源起

人工智能的第二次作業課後的某題要求對八皇后問題和八數碼問題分別用最陡上升爬山法、首選爬山法、隨機重啓爬山法、模擬退火算法來實現,並且分析他們的性能。


分析

我們發現要求實現的各個算法是有共同點的,比如,八皇后問題相關算法擁有相同的狀態空間,每個算法都有從當前狀態獲取下一狀態的需求,各個算法細節不同,共同點是,它們都是算法。
基於這樣的想法,我們可以將代碼劃分爲3層:
這裏寫圖片描述


運行示例

代碼比較長,附在最後面,讀者基於上述的思路是不難看懂的。
我們默認讀者已經知道這幾個算法的思路,代碼直接給出實現。如果不懂,請翻閱人工智能課本,裏面有講。

圖1,八數碼問題的交互界面
這裏寫圖片描述
圖2,八皇后問題的交互界面
這裏寫圖片描述
圖3 輸出界面示例
這裏寫圖片描述


結果分析

爲了便於研究,我們首先定義三個指標,分別是:
①因變1:算法找到解的成功率;
②因變2:算法找到的解的平均路徑長度
③因變3:算法找到解的平均耗散,用搜索的結點數衡量

對八皇后的結果分析

這裏寫圖片描述
觀察表1,我們可以發現如下對八皇后問題的有趣結論:
(1)在八皇后問題中,當隨機測例數增加,最陡上升爬山法和首選爬山法的成功率都收斂到0.142左右,與書本結論吻合。
(2)最陡上升爬山法的解的平均路徑長度收斂到0.58左右,而首選爬山是0.83左右。這說明最陡爬山法的平均走了更短的路徑到達全局最優解。
(3)雖然最陡上山法的平均路徑長度更短,但是搜索耗散卻比首選爬山法多,原因是,爲了得到最陡的子結點,需要探查所有的相鄰子節點。反應在數據上是,最陡上山法的解的平均耗散率收斂到32左右,而首選爬山法僅爲19左右。
(4)隨機重啓爬山法比最陡上升法和首選爬山法的成功率兜大大提高,重啓次數爲5,隨機測例10000時,成功率高達0.6,約爲前二者算法的4倍。但是也付出了更大的代價,平均解長度是最陡上升法的18.4倍,是首選爬山法的12.7倍;解的平均耗散度是最陡爬山法的17倍,是首選爬山法的28.4倍。
(5)隨機重啓爬山法的成功率隨初始溫度的增加而上升。當重啓次數爲0時,退化爲首選爬山法,成功率、解長度、解耗散度都和首選爬山法接近。隨着重啓次數增加,成功率也大大上升,當重啓次數爲7時,成功率爲0.7092,是重啓次數爲0的4.96倍,相應地,解長度和解耗散也大大增加。
(6)模擬退火算法隨起始溫度上升,成功率也上升。理論上分析,當起始溫度足夠高,退火過程足夠長的時候,成功率可以接近1。但是其開銷也會變得極大,0.43成功率的退火算法的解長度是0.46成功率退火算法的3706倍,而解耗散是146.5倍。

對八數碼問題的結果分析

這裏寫圖片描述
觀察表2,我們可以發現如下對八數碼問題的有趣結論:
(1)與八皇后問題類似,最陡上升和首選爬山法收斂到了接近的成功率,此處是0.4左右。但是解長度和解耗散並沒有八皇后問題大,可能的原因是,八數碼問題的相鄰子結點空間遠比八皇后問題大。
(2)這裏沒有使用隨機重啓算法,因爲八數碼問題關心解路徑,如果使用了隨機重啓算法,則違反了規則。
(3)初始狀態是通過目標隨機打亂得來的,先隨機取上限次數一下的打亂數x,然後隨機方向移動白塊x次。我們發現,打亂步數上限的多少,對成功率的影響並不大,無論最陡爬山算法,首選爬山算法,模擬退火算法都如此。可能的原因是,在打亂次數上限很小的時候,成功率就已經收斂了。
(4)模擬退火算法在八數碼問題和八皇后問題的表現類似。都隨着初始溫度的上升而上升,同時解長度和解耗散急劇增大。理論上,當初始溫度足夠高,成功率會逼近1。

代碼

由於實在太多,我就不逐行解釋。讀者把握分析時的思路,應該不難讀懂。

//*****************************************************
// eightQueue.hpp
// 包括八皇后問題的eightQueueNode類和eightQueueNodeFactory的實現
//*****************************************************
#include <iostream>
#include <stdlib.h> 
#include <time.h> 

class eightQueueNode {
public:
    int arr[8];
    eightQueueNode(int a,int b, int c, int d, int e, int f, int g, int h){
        arr[0] = a;
        arr[1] = b;
        arr[2] = c;
        arr[3] = d;
        arr[4] = e;
        arr[5] = f;
        arr[6] = g;
        arr[7] = h;
    }
    eightQueueNode(const eightQueueNode& node) {
        arr[0] = node.arr[0];
        arr[1] = node.arr[1];
        arr[2] = node.arr[2];
        arr[3] = node.arr[3];
        arr[4] = node.arr[4];
        arr[5] = node.arr[5];
        arr[6] = node.arr[6];
        arr[7] = node.arr[7];
    }
    ~eightQueueNode(){}
    bool operator==(const eightQueueNode& node) {
        return (this->arr[0] == node.arr[0]) && (this->arr[1] == node.arr[1]) && (this->arr[2] == node.arr[2])
                && (this->arr[3] == node.arr[3]) && (this->arr[4] == node.arr[4]) && (this->arr[5] == node.arr[5])
                && (this->arr[6] == node.arr[6]) && (this->arr[7] == node.arr[7]);
    }
};

class eightQueueNodeFactory{
    private:
        int ranNum(){
            return rand() % 8;
        }

        bool isTheArrayAllTrue(bool isAllCheck[64]) {
            for(int i = 0; i < 64; i++) {
                if(isAllCheck[i] == false) {
                    return false;
                }
            }
            return true;
        }

    public:
    eightQueueNodeFactory(){
        srand((unsigned)time(NULL));
    }

    eightQueueNode getARandomNode() {
        return eightQueueNode(ranNum(),ranNum(),ranNum(),ranNum(),ranNum(),ranNum(),ranNum(),ranNum());
    }

    int evaluate(const eightQueueNode& node) {
        int numOfAttack = 0;
        for(int i = 0; i < 7; i++) {
            for(int j = i + 1; j < 8; j++) {
                if (node.arr[i] == node.arr[j] || (node.arr[i]-node.arr[j]) == (i-j) || (node.arr[i]-node.arr[j]) == (j-i)) {
                    numOfAttack++;
                }
            }
        }
        return numOfAttack;
    }

    int getBestNextNode(eightQueueNode& node) {
        eightQueueNode ans = node;
        eightQueueNode tmp = node;
        int costOfSearch = 0;
        for(int i = 0; i < 64; i++) {
            tmp = node;
            tmp.arr[i/8] = i % 8;
            if(evaluate(tmp) < evaluate(ans)) {
                ans = tmp;
            } else if(evaluate(tmp) == evaluate(ans)) {
                if(rand() / double(RAND_MAX) > 0.5) {
                    ans = tmp;
                }
            }
        }
        node = ans;
        return 56;
    }

    // the input node is confirmed to be not the best
    int getNextBetterNode(eightQueueNode& node) {
        bool isAllCheck[64];
        for(int i = 0; i < 64; i++) isAllCheck[i] = false;

        eightQueueNode tmp = node;
        int costOfSearch = 1;
        while(evaluate(tmp) >= evaluate(node)) {
            // 子節點全部搜索過,都比當前差
            if(isTheArrayAllTrue(isAllCheck)) return costOfSearch;
            // 初始化,找下一鄰居
            tmp = node;
            int a = rand() % 64;
            isAllCheck[a] = true;
            tmp.arr[a/8] = a % 8;
            costOfSearch++;
            if(tmp == node) {
                continue;
            }
        }
        node = tmp;
        return costOfSearch;
    }

    int getARandomNeighbour(eightQueueNode& node) {
        eightQueueNode tmp = node;
        int cost = 0;
        while(node == tmp) {
            cost++;
            int a = rand() % 64;
            tmp.arr[a/8] = a % 8;
        }
        node = tmp;
        return cost;
    }
};
//***************************************
// eightQueueRunner.cpp
// 包括八皇后問題的各個算法和簡單交互界面實現
//***************************************
#include "eightQueue.hpp"
#include <iostream>
#include <math.h>

using namespace std;
eightQueueNodeFactory factory;

#define NUM_OF_LOOP 10000
#define NUM_OF_REBOOT 0
#define BEGIN_TEMP 10000
#define STOP_TEMP 1

void mostSteepClimbing();
void firstSeclectionClimbing();
void randomRebootClimbing();
void simulatedAnnealing();

int main() {

    int choice = 0;
    do{
        cout << endl;
        cout << "The Eight Queue Problem:" << endl;
        cout << "   0 -- most steep climbing" << endl;
        cout << "   1 -- first selection climbing" << endl;
        cout << "   2 -- random reboot climbing" << endl;
        cout << "   3 -- stimulated annealing" << endl;
        cout << "please input your choice: ";
        cin >> choice;
        if (choice == -1) break;
        switch(choice) {
            case 0:
                mostSteepClimbing();
                break;
            case 1:
                firstSeclectionClimbing();
                break;
            case 2:
                randomRebootClimbing();
                break;
            case 3:
                simulatedAnnealing();
                break;
            default:
                break;
        }
    }while(true);
    return 0;
}

void mostSteepClimbing() {
    int sumOfsuccess = 0, sumOfFailure = 0;
    double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;
    for(int i = 0; i < NUM_OF_LOOP; i++) {
        bool success = false;
        int cost = 0, lenOfRoute = 0;
        eightQueueNode curState = factory.getARandomNode();
        eightQueueNode tmp = curState;
        while(true) {
            // if satisfied, then break
            if (factory.evaluate(curState) == 0) {
                success = true;
                break;
            }

            lenOfRoute++;
            cost += factory.getBestNextNode(tmp);
            if(factory.evaluate(tmp) >= factory.evaluate(curState)) {
                break;
            } else {
                curState = tmp;
            }
        }

        if(success) {
            sumOfsuccess++;
            theSumOfCostOfSearchOfSuccess += cost;
            theSumLengthOfSolutionOfSuccess += lenOfRoute;
        } else {
            sumOfFailure++;
        }

        // output
        cout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";
        if(success){
            cout << "success ";
        } else {
            cout << "failure ";
        }
        cout << endl;
    }
    cout << "Sum of success: " << sumOfsuccess << endl;
    cout << "Sum of failure " << sumOfFailure << endl;
    cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  
    cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;
    cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  
    return;
}

void firstSeclectionClimbing() {
    int sumOfsuccess = 0, sumOfFailure = 0;
    double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;
    for(int i = 0; i < NUM_OF_LOOP; i++) {
        bool success = false;
        int cost = 0, lenOfRoute = 0;
        eightQueueNode curState = factory.getARandomNode();
        eightQueueNode tmp = curState;
        while(true) {
            // if satisfied, then break
            if (factory.evaluate(curState) == 0) {
                success = true;
                break;
            }

            lenOfRoute++;
            cost += factory.getNextBetterNode(tmp);
            if(factory.evaluate(tmp) >= factory.evaluate(curState)) {
                break;
            } else {
                curState = tmp;
            }
        }

        if(success) {
            sumOfsuccess++;
            theSumOfCostOfSearchOfSuccess += cost;
            theSumLengthOfSolutionOfSuccess += lenOfRoute;
        } else {
            sumOfFailure++;
        }

        // output
        cout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";
        if(success){
            cout << "success ";
        } else {
            cout << "failure ";
        }
        cout << endl;
    }
    cout << "Sum of success: " << sumOfsuccess << endl;
    cout << "Sum of failure " << sumOfFailure << endl;
    cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  
    cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;
    cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  
    return;
}

void randomRebootClimbing() {
    int sumOfsuccess = 0, sumOfFailure = 0;
    double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;
    for(int i = 0; i < NUM_OF_LOOP; i++) {
        bool success = false;
        int cost = 0, lenOfRoute = 0, numOfReboot = NUM_OF_REBOOT;
        eightQueueNode curState = factory.getARandomNode();
        eightQueueNode tmp = curState;
        while(true) {
            // if satisfied, then break
            if (factory.evaluate(curState) == 0) {
                success = true;
                break;
            }

            lenOfRoute++;
            cost += factory.getNextBetterNode(tmp);
            if(factory.evaluate(tmp) >= factory.evaluate(curState)) {
                if(numOfReboot > 0) {
                    numOfReboot--;
                    curState = factory.getARandomNode();
                    tmp = curState;
                } else {
                    break;
                }
            } else {
                curState = tmp;
            }
        }

        if(success) {
            sumOfsuccess++;
            theSumOfCostOfSearchOfSuccess += cost;
            theSumLengthOfSolutionOfSuccess += lenOfRoute;
        } else {
            sumOfFailure++;
        }
        // output
        cout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";
        if(success){
            cout << "success ";
        } else {
            cout << "failure ";
        }
        cout << endl;
    }
    cout << "Sum of success: " << sumOfsuccess << endl;
    cout << "Sum of failure " << sumOfFailure << endl;
    cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  
    cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;
    cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  
    return;
}

void simulatedAnnealing() {
    int sumOfsuccess = 0, sumOfFailure = 0;
    double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;
    for(int i = 0; i < NUM_OF_LOOP; i++) {
        bool success = false;
        int cost = 0, lenOfRoute = 0;
        double curTemp = BEGIN_TEMP;
        eightQueueNode curState = factory.getARandomNode();
        eightQueueNode tmp = curState;
        while(true) {
            // if satisfied, then break
            if (factory.evaluate(curState) == 0) {
                success = true;
                break;
            } else if(curTemp < STOP_TEMP){
                // 溫度過低,則停止
                break;
            }

            // 走一步,則溫度下降
            lenOfRoute++;
            curTemp -= 1;
            cost += factory.getARandomNeighbour(tmp);
            int deltaOfEvalutaion = factory.evaluate(tmp) - factory.evaluate(curState);
            if(deltaOfEvalutaion >= 0) {
                // 根據溫度差來決定是否接受
                double probility = exp(curTemp/(deltaOfEvalutaion));
                if(rand() / double(RAND_MAX) < deltaOfEvalutaion) {
                    curState = tmp;
                }
            } else {
                curState = tmp;
            }
        }

        if(success) {
            sumOfsuccess++;
            theSumOfCostOfSearchOfSuccess += cost;
            theSumLengthOfSolutionOfSuccess += lenOfRoute;
        } else {
            sumOfFailure++;
        }

        // output
        cout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";
        if(success){
            cout << "success ";
        } else {
            cout << "failure ";
        }
        cout << endl;
    }
    cout << "Sum of success: " << sumOfsuccess << endl;
    cout << "Sum of failure " << sumOfFailure << endl;
    cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  
    cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;
    cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  
    return;
}
//***************************************************************
// eightDigit.hpp
// 包括八數碼問題的eightDigitNode類和eightDigitFactory類的實現
// **************************************************************
#include <iostream>
#include <stdlib.h> 
#include <time.h> 
#include <math.h>

#define LOOP_OF_SHUFFLE 50

class eightDigitNode {
public:
    int arr[9];
    int blank_x = 2, blank_y = 2;
    eightDigitNode(){
        for(int i = 0; i < 8; i++) {arr[i] = i+1;}
    arr[8] = 0;
    }
    ~eightDigitNode(){}
    eightDigitNode(const eightDigitNode& node) {
        arr[0] = node.arr[0];
        arr[1] = node.arr[1];
        arr[2] = node.arr[2];
        arr[3] = node.arr[3];
        arr[4] = node.arr[4];
        arr[5] = node.arr[5];
        arr[6] = node.arr[6];
        arr[7] = node.arr[7];
        arr[8] = node.arr[8];
        blank_x = node.blank_x;
        blank_y = node.blank_y;
    }
    bool operator==(const eightDigitNode& node) {
        for(int i = 0; i < 8; i++) {
            if(arr[i] != node.arr[i]) return false;
        }
        return true;
    }

    bool goLeft() {
        if(blank_y == 0) {
            return false;
        } else {
            arr[blank_x*3+blank_y] = arr[blank_x*3+blank_y-1];
            arr[blank_x*3+blank_y-1] = 0;
            blank_y--;
            return true;
        }
    }

    bool goRight() {
        if(blank_y == 2) {
            return false;
        } else {
            arr[blank_x*3+blank_y] = arr[blank_x*3+blank_y+1];
            arr[blank_x*3+blank_y+1] = 0;
            blank_y++;
            return true;
        }
    }

    bool goUp() {
        if(blank_x == 0) {
            return false;
        } else {
            arr[blank_x*3+blank_y] = arr[(blank_x-1)*3+blank_y];
            arr[(blank_x-1)*3+blank_y] = 0;
            blank_x--;
            return true;
        }
    }

    bool goDown() {
        if(blank_x == 2) {
            return false;
        } else {
            arr[blank_x*3+blank_y] = arr[(blank_x+1)*3+blank_y];
            arr[(blank_x+1)*3+blank_y] = 0;
            blank_x++;  
            return true;
        }
    }
};
class eightDigitNodeFactory{
private:
    int getManhattanDistian(const int& src, const int& target) {
        return abs(src%3 - target%3) + abs(src/3 - target/3); 
    }
    int getNumOfWrongNumber(const eightDigitNode& node) {
        int res = 0;
        for(int i = 0; i < 8; i++) {
            if (node.arr[i] != i+1) res++;
        }
        if(node.arr[8] != 0) res++;
        return res; 
    }
    bool getANeighbourNode(int direction, eightDigitNode& node) {
        switch(direction) {
                case 0: return node.goLeft();
                case 1: return node.goUp();
                case 2: return node.goRight();
                default:
                        return node.goDown();
            }
    }

    bool isTheArrayAllTrue(bool isAllCheck[4]) {
            for(int i = 0; i < 4; i++) {
                if(isAllCheck[i] == false) {
                    return false;
                }
            }
            return true;
        }

public:
    eightDigitNodeFactory() {
        srand((unsigned)time(NULL));
    }

    eightDigitNode getARandomNode() {
        eightDigitNode output;
        int timesOfShuffle = rand() % LOOP_OF_SHUFFLE;
        while(timesOfShuffle--) {
            while(!getANeighbourNode(rand()%4, output));
        }
        return output;
    }

    int evaluate(const eightDigitNode& node) {
        eightDigitNode tmp;
        int distanceToTargetState = 0;
        for(int i = 0; i < 9; i++) {
            int j = 0;
            while(tmp.arr[j] != node.arr[i]) {j++;}
            distanceToTargetState += getManhattanDistian(i, j);
        }
        return distanceToTargetState + 3*getNumOfWrongNumber(node);
    }

    int getBestNextNode(eightDigitNode& node) {
        eightDigitNode tmp = node, ans = node;
        for(int i = 0; i < 4; i++) {
            tmp = node;
            if(getANeighbourNode(i, tmp) && evaluate(tmp) < evaluate(ans)) {
                ans = tmp;
            } else if(evaluate(tmp) == evaluate(ans)) {
                if(rand() / double(RAND_MAX) > 0.5) {
                    ans = tmp;
                }
            }
        }
        node = ans;
        return 4;
    }

    int getNextBetterNode(eightDigitNode& node) {
        bool isAllCheck[4];
        for(int i = 0; i < 4; i++) {isAllCheck[i] = false;}

        eightDigitNode tmp = node;
        int costOfSearch = 1;
        while(evaluate(tmp) >= evaluate(node)) {
            // 子節點全部搜索過,都比當前差
            if(isTheArrayAllTrue(isAllCheck)) return costOfSearch;
            // 初始化,找下一鄰居
            tmp = node;
            int a = rand() % 4;
            isAllCheck[a] = true;
            getANeighbourNode(a, tmp);
            costOfSearch++;
            if(tmp == node) {
                continue;
            }
        }
        node = tmp;
        return costOfSearch;
    }

    int getARandomNeighbour(eightDigitNode& node) {
        int costOfSearch = 0;
        eightDigitNode tmp = node;
        while(!getANeighbourNode(rand()%4, tmp)) {
            costOfSearch++;
            tmp = node;
        }
        node = tmp;
        return costOfSearch;
    }
};
//*********************************************
// eightDigitRunner.cpp
// 包括八數碼問題各算法的和簡單交互界面實現
//********************************************
#include "eightDigit.hpp"
#include <iostream>
#include <math.h>

using namespace std;
eightDigitNodeFactory factory;

#define NUM_OF_LOOP 10000
#define NUM_OF_REBOOT 7
#define BEGIN_TEMP 100000
#define STOP_TEMP 1

void mostSteepClimbing();
void firstSeclectionClimbing();
void randomRebootClimbing();
void simulatedAnnealing();

int main() {
    int choice = 0;
    do{
        cout << endl;
        cout << "The Eight Digit Problem:" << endl;
        cout << "   0 -- most steep climbing" << endl;
        cout << "   1 -- first selection climbing" << endl;
        cout << "   2 -- random reboot climbing" << endl;
        cout << "   3 -- stimulated annealing" << endl;
        cout << "please input your choice: ";
        cin >> choice;
        if (choice == -1) break;
        switch(choice) {
            case 0:
                mostSteepClimbing();
                break;
            case 1:
                firstSeclectionClimbing();
                break;
            case 2:
                randomRebootClimbing();
                break;
            case 3:
                simulatedAnnealing();
                break;
            default:
                break;
        }
    }while(true);
    return 0;
}

void mostSteepClimbing() {
    int sumOfsuccess = 0, sumOfFailure = 0;
    double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;
    for(int i = 0; i < NUM_OF_LOOP; i++) {
        bool success = false;
        int cost = 0, lenOfRoute = 0;
        eightDigitNode curState = factory.getARandomNode();
        eightDigitNode tmp = curState;
        while(true) {
            // if satisfied, then break
            if (factory.evaluate(curState) == 0) {
                success = true;
                break;
            }

            lenOfRoute++;
            cost += factory.getBestNextNode(tmp);
            if(factory.evaluate(tmp) >= factory.evaluate(curState)) {
                break;
            } else {
                curState = tmp;
            }
        }

        if(success) {
            sumOfsuccess++;
            theSumOfCostOfSearchOfSuccess += cost;
            theSumLengthOfSolutionOfSuccess += lenOfRoute;
        } else {
            sumOfFailure++;
        }

        // output
        cout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";
        if(success){
            cout << "success ";
        } else {
            cout << "failure ";
        }
        cout << endl;
    }
    cout << "Sum of success: " << sumOfsuccess << endl;
    cout << "Sum of failure " << sumOfFailure << endl;
    cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;
    cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;
    cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  
    return;
}

void firstSeclectionClimbing() {
    int sumOfsuccess = 0, sumOfFailure = 0;
    double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;
    for(int i = 0; i < NUM_OF_LOOP; i++) {
        bool success = false;
        int cost = 0, lenOfRoute = 0;
        eightDigitNode curState = factory.getARandomNode();
        eightDigitNode tmp = curState;
        while(true) {
            // if satisfied, then break
            if (factory.evaluate(curState) == 0) {
                success = true;
                break;
            }

            lenOfRoute++;
            cost += factory.getNextBetterNode(tmp);
            if(factory.evaluate(tmp) >= factory.evaluate(curState)) {
                break;
            } else {
                curState = tmp;
            }
        }

        if(success) {
            sumOfsuccess++;
            theSumOfCostOfSearchOfSuccess += cost;
            theSumLengthOfSolutionOfSuccess += lenOfRoute;
        } else {
            sumOfFailure++;
        }

        // output
        cout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";
        if(success){
            cout << "success ";
        } else {
            cout << "failure ";
        }
        cout << endl;
    }
    cout << "Sum of success: " << sumOfsuccess << endl;
    cout << "Sum of failure " << sumOfFailure << endl;
    cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  
    cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;
    cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  
    return;
}
void randomRebootClimbing() {
    int sumOfsuccess = 0, sumOfFailure = 0;
    double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;
    for(int i = 0; i < NUM_OF_LOOP; i++) {
        bool success = false;
        int cost = 0, lenOfRoute = 0;
        eightDigitNode curState = factory.getARandomNode();
        eightDigitNode tmp = curState;
        while(true) {
            // if satisfied, then break
            if (factory.evaluate(curState) == 0) {
                success = true;
                break;
            }

            lenOfRoute++;
            cost += factory.getNextBetterNode(tmp);
            if(factory.evaluate(tmp) >= factory.evaluate(curState)) {
                break;
            } else {
                curState = tmp;
            }
        }

        if(success) {
            sumOfsuccess++;
            theSumOfCostOfSearchOfSuccess += cost;
            theSumLengthOfSolutionOfSuccess += lenOfRoute;
        } else {
            sumOfFailure++;
        }

        // output
        cout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";
        if(success){
            cout << "success ";
        } else {
            cout << "failure ";
        }
        cout << endl;
    }
    cout << "Sum of success: " << sumOfsuccess << endl;
    cout << "Sum of failure " << sumOfFailure << endl;
    cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  
    cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;
    cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  
    return;
}
void simulatedAnnealing() {
    int sumOfsuccess = 0, sumOfFailure = 0;
    double theSumOfCostOfSearchOfSuccess = 0, theSumLengthOfSolutionOfSuccess = 0;
    for(int i = 0; i < NUM_OF_LOOP; i++) {
        bool success = false;
        int cost = 0, lenOfRoute = 0;
        double curTemp = BEGIN_TEMP;
        eightDigitNode curState = factory.getARandomNode();
        eightDigitNode tmp = curState;
        while(true) {
            // if satisfied, then break
            if (factory.evaluate(curState) == 0) {
                success = true;
                break;
            } else if(curTemp < STOP_TEMP){
                // 溫度過低,則停止
                break;
            }

            // 走一步,則溫度下降
            lenOfRoute++;
            curTemp -= 1;
            cost += factory.getARandomNeighbour(tmp);
            int deltaOfEvalutaion = factory.evaluate(tmp) - factory.evaluate(curState);
            if(deltaOfEvalutaion >= 0) {
                // 根據溫度差來決定是否接受
                double probility = exp(curTemp/(deltaOfEvalutaion));
                if(rand() / double(RAND_MAX) < deltaOfEvalutaion) {
                    curState = tmp;
                }
            } else {
                curState = tmp;
            }
        }

        if(success) {
            sumOfsuccess++;
            theSumOfCostOfSearchOfSuccess += cost;
            theSumLengthOfSolutionOfSuccess += lenOfRoute;
        } else {
            sumOfFailure++;
        }

        // output
        cout << "case " << i << "  cost: " << cost << " " << "lengthOfSolution: " << lenOfRoute << " ";
        if(success){
            cout << "success ";
        } else {
            cout << "failure ";
        }
        cout << endl;
    }
    cout << "Sum of success: " << sumOfsuccess << endl;
    cout << "Sum of failure " << sumOfFailure << endl;
    cout << "Rate of success " << sumOfsuccess/((double)(sumOfFailure + sumOfsuccess)) << endl;  
    cout << "The average solution length of success:" << theSumLengthOfSolutionOfSuccess/NUM_OF_LOOP << endl;
    cout << "The average cost of search of success:" << theSumOfCostOfSearchOfSuccess/NUM_OF_LOOP << endl;  
    return;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章