Design and analysis of algorithm. Documentation

University of Eastern Finland Faculty of Science and Forestry Design and analysis of algorithm Documentation of Dynamic programming (brute force) f...
Author: Jeremy Williams
5 downloads 1 Views 537KB Size
University of Eastern Finland Faculty of Science and Forestry

Design and analysis of algorithm

Documentation of

Dynamic programming (brute force) for TSP

for

O-Mopsi Project

IMPIT 2012

Emmanuel Awuni K. (251224)

17th March, 2014

1

Abstract The paper presents a naive algorithms for Travelling salesman problem (TSP) using a dynamic programming approach (brute force). The idea is to compare its optimality with Tabu search algorithm. In the end, the results showed that brute force algorithm produces a relatively high optimal solution to that of the Tabu search. However, it can only be used for cities (N) less than 10 (N < 10) due to its time complexities (N=n!) as compare to the Tabu search, which is able to find a solution without stern complexities. The algorithm was used to implement location-based game in speech recognition research group at the University of Eastern Finland, School of Computing. Keywords: Travelling salesman Problem, brute force, algorithm

2

1. INTRODUCTION 1.1 Background Travelling salesman problem (TSP) was first formulated as a mathematical problem in 1930 and is one of the most intensively studied problems in optimization [1]. The idea of TSP describes a salesman who must travel between N cities. All the cities or nodes must be visited once and return to the starting city. TSP is a very important NP-complete problem [2]. TSP is very important for organization for finding optimal solutions which is intended to minimize cost and maximize profit. Imagine a profitable company is to supply goods in N cities; there is the need to reduce cost and maximize profit. It is therefore necessary to do it optimally by going through the shortest route. This will certainly reduce the travel cost and time.

Dynamic programming typically breaks a problem down into sub-problems, solves a smaller problem, and then saves the solution to this smaller problem so that it can be use it later [2]. The first thing that comes into mind of solving TSP is the naive way in calculating the distances of all the possible routes and chooses the shortest route (brute force). In this study, I decided to use dynamic programming approach to find the shortest route given a set of nodes (cities). Brute force approach is used in this study, thereby enumerating all possible routes and output the shortest distance. Brute force algorithm for TSP certainly returns an optimal solution, but it is ideal for cities less than 10. For instance if 10 cities means the algorithm has to perm 10! (3,628,800), compare all cities and then return the shortest. It would only take a couple of seconds on a typical PC to compute all the possible routes and distances for 10 towns or less [2]. However, if we add one more town, the increase in the number of routes we need to compute increases by 1000%. If we go up to 20 towns, we could not possibly enumerate all the routes in our lifetime [2].

In this study, I try to compare the brute force algorithm to the tabu search results since tabu search does not guarantee an optimal solution.

3

2. METHOD DESCRIPTION This section focuses on the various methods or components in the algorithm (codes). The aspect explains and introduces the extraction of the input file into a distance matrix format in text file (DistanceMatrix.txt), the permutations of the cities from the input file, calculations of the permed distances and the output of the shortest distance in relative path form (result.txt). Two classes were defined and use in the algorithm. The classes include:  

DynProg class Permutator class

Figure 2.1 shows the main class (DynProg) and the auxiliary class which is responsible for the permutations and it was called into the DynProg class.

DynProg class

Permutator class Input file reading (extraction)

permutator method

Arranging in a vector

reset method

Calculating distances of perm routes

hasMore method

getNext method Output shortest route and distance

Figure 2.1 Schematic view of the algorithm

4

2.1 DynProg class The DynProg class is comprised of reading or extracting from the input file (distanceMatrix.txt), arranging and paring the distances into an array, calculating the distances after the permutations and outputting the shortest path with the least distance.

Reading the file from the distanceMatrix.txt The first part of the algorithm is to read the input file in a distance matrices format from a text file (distanceMatrix.txt) relatively. The codes below illustrate how it is done.

//Object created to handle file loading file = new File("distanceMatrix.txt"); try { //The file is read line by line BufferedReader reader = new BufferedReader(new FileReader(file)); String line; int i = 0; int k = 1; while ((line = reader.readLine()) != null) { if (line.trim().length() == 0) { break; } //The various values are being extracted from the comma separation StringTokenizer st = new StringTokenizer(line, ","); while (st.hasMoreTokens()) { //Object to store all values elements.add(st.nextToken()); ++i; ++k; } }

5

Putting the distance matrices in a vector The input file was read into a vector based on the rows and columns. Unlike an array, the vector is not definite and can accommodate more inputs as it increases. This is to enable the distance calculation across all perm cities. double dist[][] = new double[(int) Math.sqrt(k)][(int) Math.sqrt(k)]; int p = 0; for (int l = 0; l < dist.length; l++) { for (int m = 0; m < dist[0].length; m++) { dist[l][m] = Double.parseDouble(elements.get(p)); p++; } } Calculating the perm distances The distances after doing the permutations of all the nodes or cities were calculated with the intent of outputting the shortest distance. the codes below ensures that: //Handles the permutation from the permutation class while (pg.hasMore()) { int[] temp = pg.getNext(); for (int j = 0; j < temp.length; j++) { g += (temp[j]) + "-"; v += temp[j] + " "; } String words [] = g.split("-"); path.add(v); System.out.println(g); g = ""; v = ""; for (int r = 0; r < words.length - 1; r++) { //Sums all the values of the permutation sum += dist[Integer.parseInt(words[r]) - 1][Integer.parseInt(words[r+1]) - 1]; } System.out.println(sum); least.add(sum); //Stores all outcomes sum = 0; //empties the sum variable to make room for another value }

6

Outputting the results in text format The below codes is responsible for outputting the shortest route and distance, saved in the same folder as results.txt. try{ FileOutputStream fout = new FileOutputStream(new File("result.txt")); String out = (least_path +" &" + least_value); for(int r = 0; r < out.length() ; r ++){ char c = (char)out.charAt(r); System.out.println(c); fout.write(c); } } catch(IOException ex){ ex.printStackTrace(); } 2.2 Permutator class Permutation is rearrangement of the elements of an ordered list into a one-to-one correspondence with itself. However, since the brute force algorithm has to calculate all the possible routes and bring out the shortest distance, there is the need to perm all the nodes. The number of permutation is dependent on the number of cities. For instance a city of 3 will out 3! Permutations (3 x 2 x 1), so is 10 nodes in 10! Permutation. the permutator class encapsulates the methods namely: permutator, reset, hasmore and getnext method.

Permutator method The method checks that the number of cities or nodes are not less than 1 (n > 1 ). This is because the number of cities cannot be less than 1.

Reset method The reset method takes the number of cities and put them into an array.

Hasmore method After the first permutation, the hasmore method checks if there are more permutations to be done. If there is then the getnext method will do the permutations.

7

Getnext method The getnext method fetches and do the next permutation array. This goes through a series of steps of arranging the cities (node). The steps are: 

Find largest index j with a[j] < a[j+1]



Find index k such that a[k] is smallest integer greater than a[j] to the right of a[j]



Interchange a[j] and a[k]



Put tail end of permutation after jth position in increasing order

The permutations are done by swapping and perm. For instance if you have 8 cities: 1 2 3 4 5 6 7 8, below shows how the permutations are done.

1

2

3

4

5

6

7

8

1

2

4

3

5

6

8

7

swap the 7 and 8 and perm from there

1 2

3

4

5

7

6

8

swaps the 6 and 7 and perm from there

. . .

Permatations of 768 follows here

1 2

3

4

6

5

7

8

swap the 5 and 6 and perm from there

. . .

Permatations of 5678 follows here

1

2

. . .

Permatations of 5678 follows here

1

2

. . .

Permatations of 5678 follows here

3

3

8

5

4

4

5

6

6

7

7

8

8

swap the 4 and 5 and perm from there

swap the 4 and 5 and perm from there

3. EXPIREMENTS

Since the brute force algorithms is ideal for cities < 10, three, five and eight nodes (nodes) expressed in distance matrix format was used for the testing. The figure 3.1 below represents the output upon testing the 8 city distance matrix (distanceMatrix.txt) from an input file. The permutation in the brute force is done in n! (n-number of cities) times without repeating any of the perm cities. Figure 3.1 permutations of all the nodes (cities) with their distances

Route

Distance

…………

9

4. OBERVATIONS AND CONCLUSIONS This section takes a look at the observations after testing the algorithm with distance matrices.

4.1 Observations The results of the algorithm were compared to that of the Tabu search algorithm for TSP using the same 8 city distance matrix. The observation is that the dynamic programming approach gives an optimal solution as compare to the Tabu search. With the same 8 city distance matrix input, the output for the shortest distances for the two algorithms are:

Dynamic programming (brute force) Output: 2 -6- 5- 8- 1- 4- 7 & 0.5054475098027422 km

Tabu search Output: 3- 2- 5- 6- 7- 4- 1- 8

& 0.5163941322233778 km

The observation in this scenario indicates that the shortest path and distance of the same input data of the dynamic programming (brute force) is optimal than that of the Tabu search. Another observation is that in trying to test for 19 cities input file with the same algorithm (dynamic programming), it took days and eventually freezes the computer. This is because it has to take 19! Permutations.

4.2 Conclusion The dynamic programming for finding the shortest possible path in TSP using brute force is a naïve approach and returns the optimal solution, but the algorithm is slow with cities < 10. The higher the city the slower it is. However, there are other approaches that can be used to find the shortest route for cities more than 10, but may not produce an optimal solution. Example is the Tabu search which relatively does not return an optimal solution for the same input file.

10

The entire codes built on java 5 platform /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package dynProgram; import java.io.Serializable; import java.util.*; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.util.StringTokenizer; import java.util.Vector; import javax.swing.JFileChooser; /** * * @author inspiron */ public class DynProgram extends javax.swing.JFrame { File file; Vector elements = new Vector(); /** * Creates new form BruteForce */ public DynProgram() { //initComponents(); boolean status = true; Vector elements = new Vector(); Vector least = new Vector(); Vector path = new Vector(); double least_value = 0; double temp_var = 0; String least_path = ""; String[][] items = new String[8][8]; //Object created to handle file loading file = new File("distanceMatrix.txt"); try { //The file is read line by line

11

BufferedReader reader = new BufferedReader(new FileReader(file)); String line; int i = 0; int k = 1; while ((line = reader.readLine()) != null) { if (line.trim().length() == 0) { break; } //The various values are being extracted from the comma separation StringTokenizer st = new StringTokenizer(line, ","); while (st.hasMoreTokens()) { //Object to store all values elements.add(st.nextToken()); ++i; ++k; } } //Stores the input file values into an array double dist[][] = new double[(int) Math.sqrt(k)][(int) Math.sqrt(k)]; int p = 0; for (int l = 0; l < dist.length; l++) { for (int m = 0; m < dist[0].length; m++) { dist[l][m] = Double.parseDouble(elements.get(p)); p++; } } //System.out.println(Math.sqrt(k)); Permutator pg = new Permutator((int) Math.sqrt(k), 1); double sum = 0; String g = ""; String v = ""; //Handles the permutation while (pg.hasMore()) { int[] temp = pg.getNext(); for (int j = 0; j < temp.length; j++) { g += (temp[j]) + "-"; v += temp[j] + " "; } String words [] = g.split("-"); path.add(v); System.out.println(g); g = ""; v = ""; for (int r = 0; r < words.length - 1; r++) {

12

//Sums all the values of the permutation sum += dist[Integer.parseInt(words[r]) - 1][Integer.parseInt(words[r+1]) - 1]; } System.out.println(sum); least.add(sum); //Stores all outcomes sum = 0; //empties the sum variable to make room for another value } } catch (IOException ex) { ex.printStackTrace(); } //computes for the least distance for (int w = 0; w < least.size(); w++) { if (w == 0) { least_value = least.get(w); least_path = path.get(w); } if (least.get(w) < least_value) { least_value = least.get(w); least_path = path.get(w); } } //outputs the file as a text namely result.txt try{ FileOutputStream fout = new FileOutputStream(new File("result.txt")); String out = (least_path +" &" + least_value); for(int r = 0; r < out.length() ; r ++){ char c = (char)out.charAt(r); System.out.println(c); fout.write(c); } } catch(IOException ex){ ex.printStackTrace(); } } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // private void initComponents() {

13

jLabel1 = new javax.swing.JLabel(); jTxtDistance = new javax.swing.JTextField(); jButton1 = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); jLabel1.setText("Select File"); jButton1.setText("Select File"); jButton1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jButton1ActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jTxtDistance, javax.swing.GroupLayout.PREFERRED_SIZE, 273, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jButton1) .addContainerGap(142, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jTxtDistance, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(jButton1) .addComponent(jLabel1)) .addContainerGap(464, Short.MAX_VALUE)) ); pack(); }// private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

14

} /** * @param args the command line arguments */ public static void main(String args[]) { /* Set the Nimbus look and feel */ // /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html */ try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(DynProgram.class.getName()).log(java.util.logging.Level.SE VERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(DynProgram.class.getName()).log(java.util.logging.Level.SE VERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(DynProgram.class.getName()).log(java.util.logging.Level.SE VERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(DynProgram.class.getName()).log(java.util.logging.Level.SE VERE, null, ex); } // /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new DynProgram().setVisible(true); } }); }

15

// Variables declaration - do not modify private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel1; private javax.swing.JTextField jTxtDistance; // End of variables declaration } //----------------------------- Permutation -----------------------------------/* * Class to handle permutatoin */ class Permutator { private int[] array; private int firstNum; private boolean firstReady = false; //checking that the number of cities is not less than 1 public Permutator(int n, int firstNum_) { if (n < 1) { throw new IllegalArgumentException("The n must be min. 1"); } firstNum = firstNum_; array = new int[n]; reset(); } //takes the nunber of cities and put them into an array public void reset() { for (int i = 0; i < array.length; i++) { array[i] = i + firstNum; } firstReady = false; } //asking for more permutation public boolean hasMore() { boolean end = firstReady; for (int i = 1; i < array.length; i++) { end = end && array[i] < array[i - 1]; } return !end; } //gets the next permutation array public int[] getNext() { if (!firstReady) {

16

firstReady = true; return array; } int temp; int j = array.length - 2; int k = array.length - 1; // Find largest index j with a[j] < a[j+1] for (; array[j] > array[j + 1]; j--); // Find index k such that a[k] is smallest integer // greater than a[j] to the right of a[j] for (; array[j] > array[k]; k--); // Interchange a[j] and a[k] temp = array[k]; array[k] = array[j]; array[j] = temp; // Put tail end of permutation after jth position in increasing order int r = array.length - 1; int s = j + 1; while (r > s) { temp = array[s]; array[s++] = array[r]; array[r--] = temp; } return array; } // getNext() // For testing of the PermutationGenerator class } // class

REFERENCES [1] http://www.princeton.edu/~achaney/tmve/wiki100k/docs/Travelling_salesman_problem.html [2] https://gcu.googlecode.com/files/Exploring%20Algorithms.doc

17

Suggest Documents