From d9da09bd90a74ae63c378c8397f37121b1c1c4f7 Mon Sep 17 00:00:00 2001 From: Thierry Bernier Date: Sat, 29 Sep 2018 18:26:32 +0200 Subject: [PATCH] memory leak, xy is double, randomize input, cosmetics --- main.cpp | 22 +- makefile | 29 ++- tsp.cpp | 739 ++++++++++++++++++++++++++++--------------------------- tsp.h | 223 +++++++++-------- 4 files changed, 511 insertions(+), 502 deletions(-) diff --git a/main.cpp b/main.cpp index 2f43e77..675b19c 100644 --- a/main.cpp +++ b/main.cpp @@ -3,10 +3,13 @@ Title: main.cpp Description: main method for our Christofides implementation Authors: Sean Hinds, Ryan Hong, Jeff Herlitz Date: 08/16/17 + +Changes: +- cities coordinate changed from int to double +- removed useless path_vals *************************************************************************/ #include -#include #include "tsp.h" //#include "twoOpt.h" @@ -39,19 +42,16 @@ int main(int argc, char** argv) { cout << "Matching completed" << endl; // Loop through each index and find shortest path - int best = INT_MAX; - int bestIndex; + TSP::distance_t best = TSP::DINF; + int bestIndex = -1; for (long t = 0; t < tsp_size; t++) { - int result = tsp.findBestPath(t); - - tsp.path_vals[t][0] = t; // set start - tsp.path_vals[t][1] = result; // set end - - if (tsp.path_vals[t][1] < best) { - bestIndex = tsp.path_vals[t][0]; - best = tsp.path_vals[t][1]; + TSP::distance_t result = tsp.findBestPath(t); + if (result < best) { + bestIndex = t; + best = result; } } + cout << "BestPath completed " << bestIndex << endl; //Create path for best tour tsp.euler_tour(bestIndex,tsp.circuit); diff --git a/makefile b/makefile index 48960c2..4d681ee 100644 --- a/makefile +++ b/makefile @@ -1,12 +1,17 @@ -cc=g++ -cflags=-c -std=c++11 - -all: driver - -driver: main.cpp tsp.cpp tsp.h - g++ main.cpp tsp.cpp -o tsp - -clean: - rm -f a.out - rm -f *.o - rm -f driver + +inp ?= gpx + +all: tsp + +tsp: main.cpp tsp.cpp tsp.h + g++ -std=c++11 -Wall -O2 main.cpp tsp.cpp -o $@ + +clean: + rm -f a.out + rm -f *.o + rm -f tsp + +test: tsp + ./tsp $(inp) + gnuplot -e "plot '$(inp).tour' using 2:3 with lines" - + diff --git a/tsp.cpp b/tsp.cpp index dce925f..ef60f88 100644 --- a/tsp.cpp +++ b/tsp.cpp @@ -1,367 +1,372 @@ -/************************************************************************* -Title: TSP.cpp -Description: TSP class implementation file for our Christofides implementation -Authors: Sean Hinds, Ryan Hong, Jeff Herlitz -Date: 08/16/17 -*************************************************************************/ - -#include "tsp.h" - - -//Constructor -TSP::TSP(string in, string out){ - iFile = in; - oFile = out; - - ifstream inStream; - inStream.open(iFile.c_str(), ios::in); - - if(!inStream){ - cerr << "Can't open input file " << iFile << endl; - exit(1); - } - - //READ DATA - int c, x, y; - int count = 0; - while(!inStream.eof()){ - inStream >> c >> x >> y; - count++; - struct City newCity = {x,y}; - cities.push_back(newCity); - } - count--; - cout << "cities created" << endl; - inStream.close(); - - //Initialize member variables - n = count; - graph = new int*[n]; - for(int i = 0; i < n; i++){ - graph[i] = new int[n]; - for(int j = 0; j < n; j++){ - graph[i][j] = 0; - } - } - - cost = new int*[n]; - for(int i = 0; i < n; i++){ - cost[i] = new int[n]; - } - - path_vals = new int*[n]; - for(int i = 0; i < n; i++){ - path_vals[i] = new int[n]; - } - - adjlist = new vector[n]; - for(int i = 0; i < cities.size(); i++){ - struct City cur = cities[i]; - } -} - -//Destructor -TSP::~TSP(){ - for(int i = 0; i < n; i++){ - delete [] graph[i]; - delete [] cost[i]; - delete [] path_vals[i]; - } - delete [] path_vals; - delete [] graph; - delete [] cost; - delete [] adjlist; -} - -int TSP::get_distance(struct TSP::City c1, struct TSP::City c2){ - int dx = pow((float)(c1.x - c2.x),2); - int dy = pow((float)(c1.y - c2.y),2); - return floor((float)(sqrt(dx+dy) + .5)); -} - -void TSP::fillMatrix(){ - for(int i = 0; i < n; i++){ - for(int j = 0; j < n; j++){ - graph[i][j] = graph[j][i] = get_distance(cities[i],cities[j]); - } - } -} - - -/****************************************************************************** - This function uses Prim's algorithm to determine a minimum spanning tree on - the graph -******************************************************************************/ - -void TSP::findMST() { - - int key[n]; - bool included[n]; - int parent[n]; - - for (int i = 0; i < n; i++) { - - // set each key to infinity - key[i] = std::numeric_limits::max(); - - // node node yet included in MST - included[i] = false; - - } - - // root of MST has distance of 0 and no parent - key[0] = 0; - parent[0] = -1; - - for (int i = 0; i < n - 1; i++) { - - // find closes vertex not already in tree - int k = getMinIndex(key, included); - - // set included to true for this vertex - included[k] = true; - - // examine each unexamined vertex adjacent to most recently added - for (int j = 0; j < n; j++) { - - // node exists, is unexamined, and graph[k][j] less than previous - // key for u - if (graph[k][j] && included[j] == false && graph[k][j] < key[j]) { - - // update parent - parent[j] = k; - - // update key - key[j] = graph[k][j]; - - } - } - - } - - // construct a tree by forming adjacency matrices - for (int i = 0; i < n; i++) { - - int j = parent[i]; - - if (j != -1) { - - adjlist[i].push_back(j); - adjlist[j].push_back(i); - - } - - } - -} - - -/****************************************************************************** - find the index of the closest unexamined node -******************************************************************************/ - -int TSP::getMinIndex(int key[], bool mst[]) { - - // initialize min and min_index - int min = std::numeric_limits::max(); - int min_index; - - // iterate through each vertex - for (int i = 0; i < n; i++) { - - // if vertex hasn't been visited and has a smaller key than min - if (mst[i] == false && key[i] < min) { - - // reassign min and min_index to the values from this node - min = key[i]; - min_index = i; - - } - - } - - return min_index; - -} - - -/****************************************************************************** - find all vertices of odd degree in the MST. Store them in an subgraph O -******************************************************************************/ - -void TSP::findOdds() { - - for (int i = 0; i < n; i++) { - - // if degree of vertex i is odd - if ((adjlist[i].size() % 2) != 0) { - - // push vertex to odds, which is a representation of subgraph O - odds.push_back(i); - - } - - } - -} - - -void TSP::perfectMatching() { - /************************************************************************************ - find a perfect matching M in the subgraph O using greedy algorithm but not minimum - *************************************************************************************/ - int closest, length; //int d; - std::vector::iterator tmp, first; - - // Find nodes with odd degrees in T to get subgraph O - findOdds(); - - // for each odd node - while (!odds.empty()) { - first = odds.begin(); - vector::iterator it = odds.begin() + 1; - vector::iterator end = odds.end(); - length = std::numeric_limits::max(); - for (; it != end; ++it) { - // if this node is closer than the current closest, update closest and length - if (graph[*first][*it] < length) { - length = graph[*first][*it]; - closest = *it; - tmp = it; - } - } // two nodes are matched, end of list reached - adjlist[*first].push_back(closest); - adjlist[closest].push_back(*first); - odds.erase(tmp); - odds.erase(first); - } -} - - -//find an euler circuit -void TSP::euler_tour(int start, vector &path){ - //Create copy of adj. list - vector *tempList = new vector[n]; - for(int i = 0; i < n; i++){ - tempList[i].resize(adjlist[i].size()); - tempList[i] = adjlist[i]; - } - - stack stack; - int pos = start; - path.push_back(start); - while(!stack.empty() || tempList[pos].size() > 0){ - //Current node has no neighbors - if(tempList[pos].empty()){ - //add to circuit - path.push_back(pos); - //remove last vertex from stack and set it to current - pos = stack.top(); - stack.pop(); - } - //If current node has neighbors - else{ - //Add vertex to stack - stack.push(pos); - //Take a neighbor - int neighbor = tempList[pos].back(); - //Remove edge between neighbor and current vertex - tempList[pos].pop_back(); - for(int i = 0; i < tempList[neighbor].size(); i++){ - if(tempList[neighbor][i] == pos){ - tempList[neighbor].erase(tempList[neighbor].begin()+i); - } - } - //Set neighbor as current vertex - pos = neighbor; - } - } - path.push_back(pos); -} - - -//Make euler tour Hamiltonian -void TSP::make_hamiltonian(vector &path, int &pathCost){ - //remove visited nodes from Euler tour - bool visited[n]; - for(int i = 0; i < n; i++){ - visited[i] = 0; - } - - pathCost = 0; - - int root = path.front(); - vector::iterator cur = path.begin(); - vector::iterator iter = path.begin()+1; - visited[root] = 1; - - //iterate through circuit - while(iter != path.end()){ - if(!visited[*iter]){ - pathCost += graph[*cur][*iter]; - cur = iter; - visited[*cur] = 1; - iter = cur + 1; - } - else{ - iter = path.erase(iter); - } - } - - //Add distance to root - pathCost += graph[*cur][*iter]; -} - -int TSP::findBestPath(int start){ - vector path; - euler_tour(start, path); - - int length; - make_hamiltonian(path, length); - - return length; -} - - -void TSP::printResult(){ - ofstream outputStream; - outputStream.open(oFile.c_str(), ios::out); - outputStream << pathLength << endl; - for (vector::iterator it = circuit.begin(); it != circuit.end(); ++it) { - outputStream << *it << endl; - } - outputStream.close(); -}; - -void TSP::printPath(){ - cout << endl; - for (vector::iterator it = circuit.begin(); it != circuit.end()-1; ++it) { - cout << *it << " to " << *(it+1) << " "; - cout << graph[*it][*(it+1)] << endl; - } - cout << *(circuit.end()-1) << " to " << circuit.front(); - cout << "\nLength: " << pathLength << endl << endl; -}; - -void TSP::printEuler() { - for (vector::iterator it = circuit.begin(); it != circuit.end(); ++it) - cout << *it << endl; -} - -void TSP::printAdjList() { - for (int i = 0; i < n; i++) { - cout << i << ": "; //print which vertex's edge list follows - for (int j = 0; j < (int)adjlist[i].size(); j++) { - cout << adjlist[i][j] << " "; //print each item in edge list - } - cout << endl; - } -}; - -void TSP::printCities(){ - cout << endl; - int i = 0; - for (vector::iterator it = cities.begin(); it != cities.end(); ++it) - cout << i++ << ": " << it->x << " " << it->y << endl; -} - +/************************************************************************* +Title: TSP.cpp +Description: TSP class implementation file for our Christofides implementation +Authors: Sean Hinds, Ryan Hong, Jeff Herlitz +Date: 08/16/17 + +Change: +- memory leak +- cities coordinates changed from int to double +- randomized input +- removed unused vars +- pow(x,2) is not converted to x*x on old GCCs +- Assertions +*************************************************************************/ + +#include "tsp.h" + +#include +#include +#include + + +TSP::distance_t const TSP::DINF = 1.0e+99; + +//Constructor +TSP::TSP(string in, string out){ + iFile = in; + oFile = out; + + ifstream inStream; + inStream.open(iFile.c_str(), ios::in); + + if(!inStream){ + cerr << "Can't open input file " << iFile << endl; + exit(1); + } + + //READ DATA + int c; double x, y; + int count = 0; + while(!inStream.eof()){ + inStream >> c >> x >> y; + count++; + struct City newCity = {x,y}; + cities.push_back(newCity); + } + count--; + cout << "cities created" << endl; + inStream.close(); + + std::srand ( unsigned ( std::time(0) ) ); + std::random_shuffle (cities.begin(), cities.end()); + + + //Initialize member variables + n = count; + graph = new distance_t*[n]; + for(int i = 0; i < n; i++){ + graph[i] = new distance_t[n]; + for(int j = 0; j < n; j++){ + graph[i][j] = 0; + } + } + + adjlist = new vector[n]; +} + +//Destructor +TSP::~TSP(){ + for(int i = 0; i < n; i++){ + delete [] graph[i]; + } + delete [] graph; + delete [] adjlist; +} + +TSP::distance_t TSP::get_distance(struct TSP::City c1, struct TSP::City c2){ + double dx = c1.x - c2.x; + double dy = c1.y - c2.y; + double d = sqrt(dx*dx + dy*dy); + return (distance_t) d; +} + +void TSP::fillMatrix(){ + for(int i = 0; i < n; i++){ + for(int j = 0; j < n; j++){ + graph[i][j] = graph[j][i] = get_distance(cities[i],cities[j]); + } + } +} + + +/****************************************************************************** + This function uses Prim's algorithm to determine a minimum spanning tree on + the graph +******************************************************************************/ + +void TSP::findMST() { + + distance_t key[n]; + bool included[n]; + int parent[n]; + + for (int i = 0; i < n; i++) { + + // set each key to infinity + key[i] = DINF; + + // node node yet included in MST + included[i] = false; + + } + + // root of MST has distance of 0 and no parent + key[0] = 0; + parent[0] = -1; + + for (int i = 0; i < n - 1; i++) { + + // find closes vertex not already in tree + int const k = getMinIndex(key, included); + + // set included to true for this vertex + included[k] = true; + + // examine each unexamined vertex adjacent to most recently added + for (int j = 0; j < n; j++) { + + // node exists, is unexamined, and graph[k][j] less than previous + // key for u + if (graph[k][j] && included[j] == false && graph[k][j] < key[j]) { + + // update parent + parent[j] = k; + + // update key + key[j] = graph[k][j]; + + } + } + + } + + // construct a tree by forming adjacency matrices + for (int i = 0; i < n; i++) { + + int j = parent[i]; + + if (j != -1) { + assert ((j >= 0) && (j < n)); + adjlist[i].push_back(j); + adjlist[j].push_back(i); + + } + + } + +} + + +/****************************************************************************** + find the index of the closest unexamined node +******************************************************************************/ + +int TSP::getMinIndex(distance_t key[], bool mst[]) { + + // initialize min and min_index + distance_t min = DINF; + int min_index = -1; + + // iterate through each vertex + for (int i = 0; i < n; i++) { + + // if vertex hasn't been visited and has a smaller key than min + if (mst[i] == false && key[i] < min) { + + // reassign min and min_index to the values from this node + min = key[i]; + min_index = i; + + } + + } + + assert ((min_index >= 0) && (min_index < n)); + return min_index; + +} + + +/****************************************************************************** + find all vertices of odd degree in the MST. Store them in an subgraph O +******************************************************************************/ + +void TSP::findOdds() { + + for (int i = 0; i < n; i++) { + + // if degree of vertex i is odd + if ((adjlist[i].size() % 2) != 0) { + + // push vertex to odds, which is a representation of subgraph O + odds.push_back(i); + + } + + } + +} + + +void TSP::perfectMatching() { + /************************************************************************************ + find a perfect matching M in the subgraph O using greedy algorithm but not minimum + *************************************************************************************/ + int closest; + std::vector::iterator tmp, first; + + // Find nodes with odd degrees in T to get subgraph O + findOdds(); + + // for each odd node + while (!odds.empty()) { + first = odds.begin(); + vector::iterator it = odds.begin() + 1; + vector::iterator end = odds.end(); + distance_t length = DINF; + for (; it != end; ++it) { + // if this node is closer than the current closest, update closest and length + if (graph[*first][*it] < length) { + length = graph[*first][*it]; + closest = *it; + tmp = it; + } + } // two nodes are matched, end of list reached + adjlist[*first].push_back(closest); + adjlist[closest].push_back(*first); + odds.erase(tmp); + odds.erase(first); + } +} + + +//find an euler circuit +void TSP::euler_tour(int start, vector &path){ + assert ((start >= 0) && (start < n)); + //Create copy of adj. list + vector *tempList = new vector[n]; + for(int i = 0; i < n; i++){ + tempList[i].resize(adjlist[i].size()); + tempList[i] = adjlist[i]; + } + + stack stack; + int pos = start; + path.push_back(start); + while(!stack.empty() || tempList[pos].size() > 0){ + //Current node has no neighbors + if(tempList[pos].empty()){ + //add to circuit + path.push_back(pos); + //remove last vertex from stack and set it to current + pos = stack.top(); + stack.pop(); + } + //If current node has neighbors + else{ + //Add vertex to stack + stack.push(pos); + //Take a neighbor + int neighbor = tempList[pos].back(); + //Remove edge between neighbor and current vertex + tempList[pos].pop_back(); + for(auto i = 0U; i < tempList[neighbor].size(); i++){ + if(tempList[neighbor][i] == pos){ + tempList[neighbor].erase(tempList[neighbor].begin()+i); + } + } + //Set neighbor as current vertex + pos = neighbor; + } + } + path.push_back(pos); + delete [] tempList; +} + + +//Make euler tour Hamiltonian +void TSP::make_hamiltonian(vector &path, int &pathCost){ + //remove visited nodes from Euler tour + bool visited[n]; + for(int i = 0; i < n; i++){ + visited[i] = 0; + } + + pathCost = 0; + + int root = path.front(); + vector::iterator cur = path.begin(); + vector::iterator iter = path.begin()+1; + visited[root] = 1; + + //iterate through circuit + while(iter != path.end()){ + if(!visited[*iter]){ + pathCost += graph[*cur][*iter]; + cur = iter; + visited[*cur] = 1; + iter = cur + 1; + } + else{ + iter = path.erase(iter); + } + } + + //Add distance to root + pathCost += graph[*cur][*iter]; +} + +int TSP::findBestPath(int start){ + vector path; + euler_tour(start, path); + + int length; + make_hamiltonian(path, length); + + return length; +} + + +void TSP::printResult(){ + ofstream outputStream; + outputStream.open(oFile.c_str(), ios::out); + outputStream << pathLength << endl; + for (vector::iterator it = circuit.begin(); it != circuit.end(); ++it) { + outputStream << *it << " " << cities[*it].x << " " << cities[*it].y << endl; + } + outputStream.close(); +}; + +void TSP::printPath(){ + cout << endl; + for (vector::iterator it = circuit.begin(); it != circuit.end()-1; ++it) { + cout << *it << " to " << *(it+1) << " "; + cout << graph[*it][*(it+1)] << endl; + } + cout << *(circuit.end()-1) << " to " << circuit.front(); + cout << "\nLength: " << pathLength << endl << endl; +}; + +void TSP::printEuler() { + for (vector::iterator it = circuit.begin(); it != circuit.end(); ++it) + cout << *it << endl; +} + +void TSP::printAdjList() { + for (int i = 0; i < n; i++) { + cout << i << ": "; //print which vertex's edge list follows + for (int j = 0; j < (int)adjlist[i].size(); j++) { + cout << adjlist[i][j] << " "; //print each item in edge list + } + cout << endl; + } +}; + +void TSP::printCities(){ + cout << endl; + int i = 0; + for (vector::iterator it = cities.begin(); it != cities.end(); ++it) + cout << i++ << ": " << it->x << " " << it->y << endl; +} + diff --git a/tsp.h b/tsp.h index 9714a85..66f044d 100644 --- a/tsp.h +++ b/tsp.h @@ -1,112 +1,111 @@ -/************************************************************************* -Title: TSP.hpp -Description: TSP class specification file for our Christofides implementation -Authors: Sean Hinds, Ryan Hong, Jeff Herlitz -Date: 08/16/17 -*************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -#ifndef TSP_H -#define TSP_H - -class TSP -{ -private: - - struct City{ - int x; - int y; - }; - - string iFile; - string oFile; - - // List of odd nodes - vectorodds; - - //Smaller cost matrix to find minimum matching on odd nodes - int **cost; - - //Adjacency list - vector *adjList; - - void findOdds(); - - - -protected: - - -public: - // Number of cities - int n; - - //path - int **path_vals; - - //Shortest path length - int pathLength; - - //euler circuit - vector circuit; - - vector cities; - - // n x n, pairwise distances between cities - int **graph; - - vector* adjlist; - - // Constructor - TSP(string in, string out); - - // Destructor - ~TSP(); - - int get_distance(struct City c1, struct City c2); - - //Find perfect matching - void perfectMatching(); - - //Find Euler tour - void euler_tour(int start, vector &path); - - //Find Hamiltonian path - void make_hamiltonian(vector &path, int &pathCost); - - // Prim's algorithm - void findMST(); - - int getMinIndex(int key[], bool mst[]); - - void printResult(); - void printPath(); - void printEuler(); - void printAdjList(); - void printCities(); - - int get_size(){return n;}; - - void fillMatrix(); - - int findBestPath(int start); - -}; - -#endif +/************************************************************************* +Title: TSP.hpp +Description: TSP class specification file for our Christofides implementation +Authors: Sean Hinds, Ryan Hong, Jeff Herlitz +Date: 08/16/17 + +Changes: +- cities coordinates changed from int to double +- removed unused members +*************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#ifndef TSP_H +#define TSP_H + +class TSP +{ +private: + + struct City{ + double x; + double y; + }; + + string iFile; + string oFile; + + // List of odd nodes + vectorodds; + + //Adjacency list + vector *adjList; + + void findOdds(); + + + +protected: + + +public: + // Number of cities + int n; + + //Shortest path length + int pathLength; + + //euler circuit + vector circuit; + + vector cities; + + // n x n, pairwise distances between cities + typedef double distance_t; + distance_t **graph; + static distance_t const DINF; + + vector* adjlist; + + // Constructor + TSP(string in, string out); + + // Destructor + ~TSP(); + + distance_t get_distance(struct City c1, struct City c2); + + //Find perfect matching + void perfectMatching(); + + //Find Euler tour + void euler_tour(int start, vector &path); + + //Find Hamiltonian path + void make_hamiltonian(vector &path, int &pathCost); + + // Prim's algorithm + void findMST(); + + int getMinIndex(distance_t key[], bool mst[]); + + void printResult(); + void printPath(); + void printEuler(); + void printAdjList(); + void printCities(); + + int get_size(){return n;}; + + void fillMatrix(); + + int findBestPath(int start); + +}; + +#endif