0

I have implemented the algorithm according to this paper it's working well, but for certain tests, it doesn't get the shortest path,
here's the pseudo-code

Initialize
    For t=1 to iteration number do
        For k=1 to l do
            Repeat until ant k has completed a tour
                Select the city j to be visited next
                With probability pij given by Eq. (1)
            Calculate Lk
        Update the trail levels according to Eqs. (2-4).
    End

here's the code

import java.io.*;
import java.util.*;
import static java.lang.Math.*;

public class test2 {

private InputReader cin;
private PrintWriter cout;
double pheromones[][];
double distances[][];
double visibility[][];
static int n;
City[] city;
Ant[] ant;
int m;
int T;
double alpha = 1;                        // pheromone importance
double beta = 2;                        // visibility importance
double evaporation = 0.1;
double Q = 100.0;

static class City {
    double x, y;
    int id;

    public City(double x, double y, int id) {
        this.x = x;
        this.y = y;
        this.id = id;
    }
}

static class Ant {
    int whereAmI;
    boolean[] visited;
    double tourDistance;
    LinkedList<Integer> citiesVisitedInOrder;
    int cityEdges[][];

    Ant(int whereAmI) {
        this.whereAmI = whereAmI;
        visited = new boolean[n + 1];
        cityEdges = new int[n + 1][n + 1];

        reset();
    }

    void reset() {
        Arrays.fill(visited, false);
        visited[whereAmI] = true;
        for (int i = 1; i <= n; i++)
            Arrays.fill(cityEdges[i], 0);
        tourDistance = 0;
        citiesVisitedInOrder = new LinkedList<>();
        citiesVisitedInOrder.addLast(whereAmI);
    }
}
//the actual algorithm iteration 
/*
Initialize
For t=1 to iteration number do
    For k=1 to l do
        Repeat until ant k has completed a tour
            Select the city j to be visited next
            With probability pij given by Eq. (1)
        Calculate Lk
    Update the trail levels according to Eqs. (2-4).
End
*/
private void solve() {
    n = cin.readInt();
    initializeParameter();

    //the main loop
    for (int t = 0; t < T; t++) {


        for (int i = 0; i < m; i++) {//for each ant
            Ant current = ant[i];
            for (int j = 0; j < n; j++) {//for each city

                int currentAntsCity = current.whereAmI;
                double highestProbability = 0;
                int cityId = 1;
                double sumNotiation = calculateSum(current.visited, currentAntsCity);
                //traverse all non-visited cities and choose the best
                boolean good = false;
                for (int c = 1; c <= n; c++) {//remove the equal
                    if (!current.visited[c]) {
                        double prop = (pow(pheromones[currentAntsCity][c], alpha) * pow(visibility[currentAntsCity][c], beta))
                                / sumNotiation;
                        if (prop >= highestProbability) {
                            highestProbability = prop;
                            cityId = c;
                            good = true;
                        }
                    }
                }
                if (good) {
                    current.tourDistance += distances[currentAntsCity][cityId];
                    current.cityEdges[currentAntsCity][cityId] = current.cityEdges[cityId][currentAntsCity] = 1;
                    current.citiesVisitedInOrder.addLast(cityId);
                    current.whereAmI = cityId;
                    current.visited[cityId] = true;
                }
            }//after n iteration i ant completes a tour
            current.tourDistance += distances[current.citiesVisitedInOrder.getFirst()][current.citiesVisitedInOrder.getLast()];
        }//update
        for (int i = 1; i <= n; i++) {
            for (int j = i + 1; j <= n; j++) {
                double deltaPhermons = 0;
                for (int a = 0; a < m; a++) {
                    if (ant[a].cityEdges[i][j] != 0) {
                        deltaPhermons += Q / ant[a].tourDistance;
                    }
                }
                pheromones[i][j] = pheromones[j][i] = pheromones[i][j] * evaporation + deltaPhermons;
                pheromones[i][i] = 0;
            }
        }

        if (t == T - 1)
            break;

        //reset everything
        for (int i = 0; i < m; i++) {
            ant[i].reset();
        }
    }
    //get the best ant route
    double minDistance = Double.MAX_VALUE;
    LinkedList<Integer> minRout = new LinkedList<>();
    for (Ant ant : ant) {
        if (ant.tourDistance < minDistance) {
            minDistance = ant.tourDistance;
            minRout = ant.citiesVisitedInOrder;
        }
    }

    cout.println(minDistance);
    for (int element : minRout)
        cout.print(element + " ");


}


private double calculateSum(boolean[] visited, int currentAntsCity) {
    //traverse all non-visited cities
    double ans = 0.0;
    for (int c = 1; c <= n; c++) {
        if (!visited[c]) {
            ans +=
                    pow(pheromones[currentAntsCity][c], alpha) *
                            pow(visibility[currentAntsCity][c], beta);
        }
    }
    return ans;
}

private void initializeParameter() {
    m = 2 * n;
    T = 4 * m;
    city = new City[n + 1];
    pheromones = new double[n + 1][n + 1];
    distances = new double[n + 1][n + 1];
    visibility = new double[n + 1][n + 1];

    //read cities coordinates
    for (int i = 1; i <= n; i++) {
        city[i] = new City(cin.readDouble(), cin.readDouble(), i);
    }

    //initialize distances
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            distances[i][j] = distances[j][i] = sqrt(pow(city[i].x -
                    city[j].x, 2.0) + pow(city[i].y -
                    city[j].y, 2.0));
        }
    }

    //initialize the pheromones
    double pheromones0 = 1.0 / (double) n;
    for (int i = 1; i <= n; i++) {
        Arrays.fill(pheromones[i], pheromones0);
        pheromones[i][i] = 0;
    }

    //initialize the visibility
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            visibility[i][j] = visibility[j][i] = 1.0 / distances[i][j];

        }
    }

    //initialize the ants
    ant = new Ant[m];
    Random rand = new Random(); //instance of random class for
    for (int i = 0; i < m; i++) {
        int random_int = rand.nextInt(n) + 1;
        ant[i] = new Ant(random_int);
    }
}

public static void main(String args[]) {
    new test2().run();

}

private void run() {
    // cin = new InputReader(System.in);
    // cout = new PrintWriter(System.out);
    try {
        cin = new InputReader(new FileInputStream("input.txt"));
        cout = new PrintWriter(new FileOutputStream("output.txt"));
    } catch (FileNotFoundException e) {
        //System.out.println(e.toString());
    }
    solve();
    cout.close();
}
//just for faster reading from a file
public static class InputReader {

    private InputStream stream;
    private byte[] buf = new byte[1024];
    private int curChar, numChars;

    public InputReader(InputStream stream) {
        this.stream = stream;
    }

    public int read() {
        if (numChars == -1)
            throw new InputMismatchException();
        if (curChar >= numChars) {
            curChar = 0;
            try {
                numChars = stream.read(buf);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (numChars <= 0)
                return -1;
        }
        return buf[curChar++];
    }

    public int readInt() {
        int c = read();
        while (isSpaceChar(c))
            c = read();
        int sgn = 1;
        if (c == '-') {
            sgn = -1;
            c = read();
        }
        int res = 0;
        do {
            if (c < '0' || c > '9')
                throw new InputMismatchException();
            res *= 10;
            res += c - '0';
            c = read();
        } while (!isSpaceChar(c));
        return res * sgn;
    }

    public double readDouble() {
        int c = read();
        while (isSpaceChar(c))
            c = read();
        int sgn = 1;
        if (c == '-') {
            sgn = -1;
            c = read();
        }
        double res = 0;
        while (!isSpaceChar(c) && c != '.') {
            if (c == 'e' || c == 'E')
                return res * pow(10, readInt());
            if (c < '0' || c > '9')
                throw new InputMismatchException();
            res *= 10;
            res += c - '0';
            c = read();
        }
        if (c == '.') {
            c = read();
            double m = 1;
            while (!isSpaceChar(c)) {
                if (c == 'e' || c == 'E')
                    return res * pow(10, readInt());
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                m /= 10;
                res += (c - '0') * m;
                c = read();
            }
        }
        return res * sgn;
    }

    private boolean isSpaceChar(int c) {
        return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
    }

}
}

the test case

    10
-15 89
-5 -49
-35 -18
7 49
-95 -68
85 -39
53 -1
69 -99
-74 8
-52 -35

the right answer:

615.11811789868988853
1 9 5 10 3 2 8 6 7 4

my coes's output:

685.2134200307595
5 9 10 3 2 8 6 7 4 1

as you can notice I am not getting the shortest path, I believe that the mistake is somewhere in the constant, and the probability comparing!

the formula I have implemented formula and the update formulas enter image description here how can I improve the algorithm accuracy? or maybe there's something wrong in my implementation!

Amr
  • 1,068
  • 12
  • 21
  • There's no guarantee that you will get the optimal tour. There's not even any guarantee that you'll get the same tour for two executions of your program, since there's some randomness involved. Have you tried running the same problems that they used in the report, to see if you get _similar_ results as them? – Michael Apr 02 '20 at 11:40
  • I didn't think to do so before, good idea, I will try out – Amr Apr 02 '20 at 12:00

1 Answers1

0

I found the solution, Changing the Update functions after each complete tour for all ants, fixed the problem:

#part 1
//the elaboration presses after a complete tour for all ants
for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    pheromones[i][j] *= evaporation;
                    if (pheromones[i][j] < 1.0 / (double) n)//notice it the phermones can't be less than the starting value`
                        pheromones[i][j] = 1.0 / (double) n;
                    pheromones[i][i] = 0;
                }
            }
#part 2
//update the phermonses 
for (int i = 0; i < m; i++) {
                for (int j = i + 1; j <= n; j++) {
                    int from = ant[i].rout[0];
                    int to = ant[i].rout[n - 1];
                    pheromones[from][to] += Q / ant[i].tourDistance;
                    pheromones[to][from] = pheromones[from][to];
                }
            }

source HERE

strangely enough the algorithm can work without the elaboration presses i.e. #part1.
Anyway here's the complete code with little changes

import java.io.*;
import java.util.*;

import static java.lang.Math.*;

public class test2 {

    private InputReader cin;
    private PrintWriter cout;
    double[][] arr;
    double[][] pheromones;
    double[][] distances;
    double[][] visibility;
    static int n;
    Ant[] ant;
    int m;
    int T;
    double alpha = 1;                        // pheromone importance
    double beta = 3;                        // visibility importance
    double evaporation = 0.9;
    double Q = 40.0;
    double pheromones0;

    static class Ant {
        int whereAmI;
        boolean[] visited;
        double tourDistance;
        private int ctr; //counter for the cites thought which the ant pass
        private int[] route;


        Ant(int whereAmI) {
            this.whereAmI = whereAmI;
            reset();
        }

        void reset() {
            ctr = 0;
            route = new int[n];
            visited = new boolean[n + 1];
            visited[whereAmI] = true;
            tourDistance = 0;

            addCityToTheRoute(whereAmI);
        }

        void addCityToTheRoute(int cityId) {
            route[ctr++] = cityId;
        }
    }

    private void solve() {
        n = cin.readInt();
        initializeParameter();

        double mi = Double.MAX_VALUE;
        int[] cityRoute = new int[n];
        //the main loop
        for (int t = 0; t < T; t++) {
            for (int i = 0; i < m; i++) {//for each ant
                for (int j = 0; j < n; j++) {//for each city
                    double highestProbability = 0;
                    int cityId = 1;
                    double sumNotiation = calculateSum(ant[i].visited, ant[i].whereAmI);
                    //traverse all non-visited cities and choose the best
                    boolean good = false;
                    for (int c = 1; c <= n; c++) {//remove the equal
                        if (!ant[i].visited[c]) {
                            double prop = (pow(pheromones[ant[i].whereAmI][c], alpha) * pow(visibility[ant[i].whereAmI][c], beta))
                                    / sumNotiation;
                            if (prop >= highestProbability) {
                                highestProbability = prop;
                                cityId = c;
                                good = true;
                            }
                        }
                    }
                    if (good) {
                        ant[i].tourDistance += distances[ant[i].whereAmI][cityId];
                        ant[i].addCityToTheRoute(cityId);
                        ant[i].whereAmI = cityId;
                        ant[i].visited[cityId] = true;
                    }
                }//after n iteration i ant completes a tour
                ant[i].tourDistance += distances[ant[i].route[0]][ant[i].route[n - 1]];//add the distance from the last city to the first city
                //while k ant finishes its tour take the best ant's route so far
                if (ant[i].tourDistance < mi) {
                    mi = ant[i].tourDistance;
                    cityRoute = ant[i].route;
                }
            }
            //update
            //evaporatePheromones
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    pheromones[i][j] *= evaporation;
                    if (pheromones[i][j] < pheromones0)
                        pheromones[i][j] = pheromones0;
                    pheromones[i][i] = 0;
                }
            }
            //updatePheromones
            for (int i = 0; i < m; i++) {
                for (int j = i + 1; j <= n; j++) {
                    int from = ant[i].route[0];
                    int to = ant[i].route[n - 1];
                    pheromones[from][to] += Q / ant[i].tourDistance;
                    pheromones[to][from] = pheromones[from][to];
                }
            }

            if (t == T - 1)
                break;
            //reset everything
            for (int i = 0; i < m; i++) {
                ant[i].reset();
            }
        }
        //print the route with the distance
        cout.println(mi);
        for (int element : cityRoute)
            cout.print(element + " ");

    }


    private double calculateSum(boolean[] visited, int currentAntsCity) {
        //traverse all non-visited cities
        double ans = 0.0;
        for (int c = 1; c <= n; c++) {
            if (!visited[c]) {
                ans +=
                        pow(pheromones[currentAntsCity][c], alpha) *
                                pow(visibility[currentAntsCity][c], beta);
            }
        }
        return ans;
    }

    private void initializeParameter() {
        m = 20 * n;
        T = 20;
        pheromones = new double[n + 1][n + 1];
        distances = new double[n + 1][n + 1];
        visibility = new double[n + 1][n + 1];

        //read cities coordinates
        arr = new double[n + 1][2];
        for (int i = 1; i <= n; i++) {
            double x = cin.readDouble();
            double y = cin.readDouble();
            arr[i][0] = x;
            arr[i][1] = y;
        }

        //initialize distances
        for (int i = 1; i <= n; i++) {
            for (int j = i + 1; j <= n; j++) {
                distances[i][j] = distances[j][i] = sqrt(pow(arr[i][0] -
                        arr[j][0], 2.0) + pow(arr[i][1] -
                        arr[j][1], 2.0));
            }
        }

        //initialize the pheromones
        pheromones0 = 1.0 / (double) n;
        for (int i = 1; i <= n; i++) {
            Arrays.fill(pheromones[i], pheromones0);
            pheromones[i][i] = 0;
        }

        //initialize the visibility
        for (int i = 1; i <= n; i++) {
            for (int j = i + 1; j <= n; j++) {
                visibility[i][j] = visibility[j][i] = 1.0 / distances[i][j];

            }
        }

        //initialize the ants
        ant = new Ant[m];
        Random rand = new Random(); //instance of random class for
        for (int i = 0; i < m; i++) {
            int random_int = rand.nextInt(n) + 1;
            ant[i] = new Ant(random_int);
        }
    }

    public static void main(String args[]) {
        new test2().run();

    }

    private void run() {
        // cin = new InputReader(System.in);
        // cout = new PrintWriter(System.out);
        try {
            cin = new InputReader(new FileInputStream("input.txt"));
            cout = new PrintWriter(new FileOutputStream("output.txt"));
        } catch (FileNotFoundException e) {
            //System.out.println(e.toString());
        }
        solve();
        cout.close();
    }

    //just for faster reading from a file
    public static class InputReader {

        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar, numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1)
                throw new InputMismatchException();
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0)
                    return -1;
            }
            return buf[curChar++];
        }

        public int readInt() {
            int c = read();
            while (isSpaceChar(c))
                c = read();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = read();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public double readDouble() {
            int c = read();
            while (isSpaceChar(c))
                c = read();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            double res = 0;
            while (!isSpaceChar(c) && c != '.') {
                if (c == 'e' || c == 'E')
                    return res * pow(10, readInt());
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = read();
            }
            if (c == '.') {
                c = read();
                double m = 1;
                while (!isSpaceChar(c)) {
                    if (c == 'e' || c == 'E')
                        return res * pow(10, readInt());
                    if (c < '0' || c > '9')
                        throw new InputMismatchException();
                    m /= 10;
                    res += (c - '0') * m;
                    c = read();
                }
            }
            return res * sgn;
        }

        private boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

    }
}
Amr
  • 1,068
  • 12
  • 21