├── demo ├── usa.pdf ├── .DS_Store ├── country.jpg ├── graph.tex ├── adj_matrix └── usa.tex ├── makefile ├── .gitignore ├── include ├── mst.h └── simplex.h ├── LICENSE ├── README.md └── src ├── mst.cpp ├── simplex.cpp └── tsp_solver.cpp /demo/usa.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PetarV-/Simplex-TSP-Solver/HEAD/demo/usa.pdf -------------------------------------------------------------------------------- /demo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PetarV-/Simplex-TSP-Solver/HEAD/demo/.DS_Store -------------------------------------------------------------------------------- /demo/country.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PetarV-/Simplex-TSP-Solver/HEAD/demo/country.jpg -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CC = clang++ -Iinclude/ 2 | CFLAGS = -std=c++11 -O3 -Wall -Wextra -Werror -Weffc++ -Wstrict-aliasing --pedantic 3 | 4 | tsp_solver : src/mst.cpp src/simplex.cpp src/tsp_solver.cpp 5 | $(CC) $(CFLAGS) src/mst.cpp src/simplex.cpp src/tsp_solver.cpp -o tsp_solver 6 | 7 | .PHONY : clean 8 | clean : 9 | -rm -f tsp_solver &> /dev/null 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /include/mst.h: -------------------------------------------------------------------------------- 1 | /* 2 | Petar 'PetarV' Velickovic 3 | Algorithm: MST-TSP approximation 4 | */ 5 | 6 | #ifndef MST 7 | #define MST 8 | 9 | #include 10 | 11 | #define MAX_N 5001 12 | 13 | /* 14 | This is a polynomial time 2-approximation algorithm to the Traveling 15 | Salesman Problem, making advantage of a minimal spanning tree (MST) 16 | subroutine. It proceeds as follows: 17 | 1. Compute the MST of the input graph; 18 | 2. Perform a preorder traversal of the MST; 19 | 3. Traverse vertices in that exact order, closing the circuit at the end. 20 | */ 21 | 22 | std::pair > > tsp_mst(int n, double adj[MAX_N][MAX_N]); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Petar Veličković 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /demo/graph.tex: -------------------------------------------------------------------------------- 1 | \node[] (title) at (10, 25) {\Huge Objective value: $-701.000000$, $861$ variables, $952$ constraints, $2255$ iterations}; 2 | \draw[edge,black] (2) to node[lab]{1} (1); 3 | \draw[edge,black] (3) to node[lab]{1} (2); 4 | \draw[edge,black] (4) to node[lab]{1} (3); 5 | \draw[edge,black] (5) to node[lab]{1} (4); 6 | \draw[edge,black] (6) to node[lab]{1} (5); 7 | \draw[edge,black] (7) to node[lab]{1} (6); 8 | \draw[edge,black] (8) to node[lab]{1} (7); 9 | \draw[edge,black] (9) to node[lab]{1} (8); 10 | \draw[edge,black] (12) to node[lab]{1} (10); 11 | \draw[edge,black] (12) to node[lab]{1} (11); 12 | \draw[edge,black] (14) to node[lab]{1} (13); 13 | \draw[edge,black] (15) to node[lab]{1} (14); 14 | \draw[edge,black] (16) to node[lab]{1} (15); 15 | \draw[edge,black] (17) to node[lab]{1} (13); 16 | \draw[edge,black] (18) to node[lab]{1} (16); 17 | \draw[edge,black] (19) to node[lab]{1} (18); 18 | \draw[edge,black] (20) to node[lab]{1} (19); 19 | \draw[edge,black] (21) to node[lab]{1} (20); 20 | \draw[edge,black] (22) to node[lab]{1} (17); 21 | \draw[edge,black] (23) to node[lab]{1} (11); 22 | \draw[edge,black] (23) to node[lab]{1} (22); 23 | \draw[edge,black] (25) to node[lab]{1} (9); 24 | \draw[edge,black] (25) to node[lab]{1} (10); 25 | \draw[edge,black] (26) to node[lab]{1} (24); 26 | \draw[edge,black] (27) to node[lab]{1} (24); 27 | \draw[edge,black] (27) to node[lab]{1} (26); 28 | \draw[edge,black] (28) to node[lab]{1} (21); 29 | \draw[edge,black] (29) to node[lab]{1} (28); 30 | \draw[edge,black] (30) to node[lab]{1} (29); 31 | \draw[edge,black] (31) to node[lab]{1} (30); 32 | \draw[edge,black] (32) to node[lab]{1} (31); 33 | \draw[edge,black] (33) to node[lab]{1} (32); 34 | \draw[edge,black] (34) to node[lab]{1} (33); 35 | \draw[edge,black] (35) to node[lab]{1} (34); 36 | \draw[edge,black] (36) to node[lab]{1} (35); 37 | \draw[edge,black] (37) to node[lab]{1} (36); 38 | \draw[edge,black] (38) to node[lab]{1} (37); 39 | \draw[edge,black] (39) to node[lab]{1} (38); 40 | \draw[edge,black] (40) to node[lab]{1} (39); 41 | \draw[edge,black] (41) to node[lab]{1} (40); 42 | \draw[edge,black] (42) to node[lab]{1} (1); 43 | \draw[edge,black] (42) to node[lab]{1} (41); 44 | -------------------------------------------------------------------------------- /include/simplex.h: -------------------------------------------------------------------------------- 1 | /* 2 | Petar 'PetarV' Velickovic 3 | Algorithm: Simplex Algorithm 4 | */ 5 | 6 | #ifndef SIMPLEX 7 | #define SIMPLEX 8 | 9 | #include 10 | #include 11 | 12 | /* 13 | The Simplex algorithm aims to solve a linear program - optimising a linear function subject 14 | to linear constraints. As such it is useful for a very wide range of applications. 15 | 16 | N.B. The linear program has to be given in *slack form*, which is as follows: 17 | maximise 18 | c_1 * x_1 + c_2 * x_2 + ... + c_n * x_n + v 19 | subj. to 20 | a_11 * x_1 + a_12 * x_2 + ... + a_1n * x_n + b_1 = s_1 21 | a_21 * x_1 + a_22 * x_2 + ... + a_2n * x_n + b_2 = s_2 22 | ... 23 | a_m1 * x_1 + a_m2 * x_2 + ... + a_mn * x_n + b_m = s_m 24 | and 25 | x_1, x_2, ..., x_n, s_1, s_2, ..., s_m >= 0 26 | 27 | Every linear program can be translated into slack form; the parameters to specify are: 28 | - the number of variables, n, and the number of constraints, m; 29 | - the matrix A = [[A_11, A_12, ..., A_1n], ..., [A_m1, A_m2, ..., A_mn]]; 30 | - the vector b = [b_1, b_2, ..., b_m]; 31 | - the vector c = [c_1, c_2, ..., c_n] and the constant v. 32 | 33 | Complexity: O(m^(n/2)) worst case 34 | O(n + m) average case (common) 35 | */ 36 | 37 | class Simplex 38 | { 39 | private: 40 | int n, m; 41 | double **A, *b, *c, v; 42 | int *N, *B; // nonbasic & basic 43 | 44 | public: 45 | Simplex(int n, int m, double **A, double *b, double *c, double v); 46 | 47 | ~Simplex(); 48 | 49 | // pivot yth variable around xth constraint 50 | void pivot(int x, int y); 51 | 52 | // Run a single iteration of the simplex algorithm. 53 | // Returns: 0 if OK, 1 if STOP, -1 if UNBOUNDED 54 | int iterate_simplex(); 55 | 56 | // (Possibly) converts the LP into a slack form with a feasible basic solution. 57 | // Returns 0 if OK, -1 if INFEASIBLE 58 | int initialise_simplex(); 59 | 60 | // Runs the simplex algorithm to optimise the LP. 61 | // Returns a vector of -1s if unbounded, -2s if infeasible. 62 | std::tuple, double, int> simplex(); 63 | }; 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simplex-TSP-Solver 2 | Iterative exact solver of the Travelling Salesman Problem, taking advantage of the Simplex Algorithm (by methods of Dantzig, Fulkerson and Johnson). The topmost layer of the solver also interfaces to a demo folder, which can be used for plotting the current solution as successive solutions are found. 3 | 4 | The current form has been used for demonstrations at the [mgcsweek](http://www.csnedelja.mg.edu.rs) seminar at the [High School of Mathematics](http://www.mg.edu.rs) in Belgrade and the [Advanced Algorithms](http://www.cl.cam.ac.uk/teaching/1516/AdvAlgo/) lecture course for Part II of the Computer Science Tripos at the [University of Cambridge](http://www.cam.ac.uk). 5 | 6 | ## Building 7 | Simply run 8 | 9 | $ make 10 | 11 | while in the root directory of the repository, and the executable, `tsp_solver`, will be created therewith. 12 | 13 | ## Usage 14 | In order to interface properly to a demo setting, four parameters need to be given right after executing 15 | 16 | $ ./tsp_solver 17 | 18 | These are, in order: 19 | - A path to the adjacency matrix specifying the input graph (`demo/adj_matrix` in this case); 20 | - A path to the folder containing the demonstration .tex files (`demo/` in this case); 21 | - File name of the .tex file containing the edge-drawing commands (`graph.tex` in this case); 22 | - File name of the .tex file containing the map-drawing commands (`usa.tex` in this case); 23 | 24 | Afterwards, an interactive window will open where one of the following commands may be performed repeatedly: 25 | - `SOLVE`: launch the Simplex algorithm on the constraints obtained so far; 26 | - `REM_LOOP`/`REM_LOOP_RNG`: add a cycle-eliminating constraint on a given set of nodes; 27 | - `SET`: add a constraint that sets a particular edge's indicator variable to 0/1; 28 | - `UNDO`: undo a number of previously added constraints (useful for branch&bound); 29 | - `APPROX_MST`: perform a 2-approximation of the optimal tour using Prim's MST algorithm; 30 | - `EXIT`: exit the program. 31 | 32 | Upon each call to `SOLVE`, detailed information about all the useful iterations (that improve the objective value) will be printed on the terminal. Once a solution has been found, `pdflatex` will be called to regenerate the output PDF file (`demo/usa.pdf` in this case). Finally, if you are using Mac OS X, `qlmanage` will be called for automatically displaying the PDF. 33 | 34 | ## License 35 | MIT 36 | -------------------------------------------------------------------------------- /src/mst.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | typedef long long lld; 19 | typedef unsigned long long llu; 20 | typedef unsigned int uint; 21 | using namespace std; 22 | 23 | struct pq_entry 24 | { 25 | double x; 26 | pair e; 27 | bool operator <(const pq_entry &a) const 28 | { 29 | return (x > a.x); 30 | } 31 | }; 32 | 33 | inline vector prim(int n, double adj[MAX_N][MAX_N]) 34 | { 35 | vector mark(n + 1, false); 36 | vector ret(n + 1, -1); 37 | priority_queue pq_prim; 38 | int xt = 1; 39 | int amt = 0; 40 | while (amt < n - 1) 41 | { 42 | mark[xt] = true; 43 | for (int i=1;i<=n;i++) 44 | { 45 | if (!mark[i]) pq_prim.push({adj[max(xt, i)][min(xt, i)], {xt, i}}); 46 | } 47 | while (!pq_prim.empty()) 48 | { 49 | auto X = pq_prim.top(); 50 | pq_prim.pop(); 51 | if (!mark[X.e.second]) 52 | { 53 | ret[X.e.second] = X.e.first; 54 | xt = X.e.second; 55 | amt++; 56 | break; 57 | } 58 | } 59 | } 60 | return ret; 61 | } 62 | 63 | inline pair > > build_tree(vector p) 64 | { 65 | int root; 66 | vector > T(p.size(), vector()); 67 | for (uint i=1;i > T, vector &ret) 76 | { 77 | ret.push_back(x); 78 | for (uint i=0;i > > tsp_mst(int n, double adj[MAX_N][MAX_N]) 85 | { 86 | vector mst = prim(n, adj); 87 | auto mst_t = build_tree(mst); 88 | vector walk; 89 | preorder(mst_t.first, mst_t.second, walk); 90 | 91 | double val = 0.0; 92 | vector > used; 93 | 94 | for (uint i=0;i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #define EPS 1e-3 20 | 21 | typedef long long lld; 22 | typedef unsigned long long llu; 23 | using namespace std; 24 | 25 | int total_steps = 0; 26 | 27 | Simplex::Simplex(int n, int m, double **A, double *b, double *c, double v) : n(n), m(m), v(v) 28 | { 29 | this -> A = new double*[m]; 30 | for (int i=0;i A[i] = new double[n+1]; // allocate +1 because of aux. LP 33 | for (int j=0;j A[i][j] = A[i][j]; 36 | } 37 | } 38 | 39 | this -> b = new double[m]; 40 | for (int i=0;i b[i] = b[i]; 43 | } 44 | 45 | this -> c = new double[n+1]; // allocate +1 because of aux. LP 46 | for (int i=0;i c[i] = c[i]; 49 | } 50 | 51 | this -> N = new int[n+1]; // allocate +1 because of aux. LP 52 | this -> B = new int[m]; 53 | } 54 | 55 | Simplex::~Simplex() 56 | { 57 | for (int i=0;i vars; 136 | int best_var = -1; 137 | for (int j=0;j 0) 140 | { 141 | vars.push_back(j); 142 | /* Bland's Rule 143 | if (best_var == -1 || N[j] < ind) 144 | { 145 | ind = N[j]; 146 | best_var = j; 147 | } 148 | */ 149 | } 150 | } 151 | if (vars.empty()) return 1; 152 | 153 | best_var = vars[rand() % vars.size()]; 154 | 155 | double max_constr = INFINITY; 156 | int best_constr = -1; 157 | for (int i=0;i EPS) cout << "Iteration " << total_steps << ": " << v << endl; 197 | 198 | return 0; 199 | } 200 | 201 | // (Possibly) converts the LP into a slack form with a feasible basic solution. 202 | // Returns 0 if OK, -1 if INFEASIBLE 203 | int Simplex::initialise_simplex() 204 | { 205 | total_steps = 0; 206 | 207 | int k = -1; 208 | double min_b = -1; 209 | for (int i=0;i= 0) // basic solution feasible! 219 | { 220 | for (int j=0;j n) N[j]--; 289 | for (int i=0;i n) B[i]--; 290 | 291 | for (int j=0;j, double, int> Simplex::simplex() 328 | { 329 | printf("Running the Simplex algorithm with %d variables and %d constraints.\n", n, m); 330 | 331 | if (initialise_simplex() == -1) 332 | { 333 | return {vector(n + m, -2), INFINITY, total_steps}; 334 | } 335 | 336 | int code; 337 | while (!(code = iterate_simplex())); 338 | 339 | if (code == -1) return {vector(n + m, -1), INFINITY, total_steps}; 340 | 341 | vector ret; 342 | ret.resize(n + m); 343 | for (int j=0;j 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #define MAX_N 5001 26 | #define EPS 1e-5 27 | 28 | typedef long long lld; 29 | typedef unsigned long long llu; 30 | typedef unsigned int uint; 31 | using namespace std; 32 | 33 | char path_adj[150], path_demo[150], file_graph[150], file_map[150]; 34 | char path_graph[150], path_map[150], path_pdf[150]; 35 | FILE *f_adj, *f_graph, *f_lp; 36 | 37 | char cmd[150]; 38 | char cmd_map[150]; 39 | char cmd_prev[150]; 40 | 41 | int n; 42 | double adj[MAX_N][MAX_N]; 43 | 44 | int simp_n; 45 | double c[MAX_N * MAX_N]; 46 | 47 | // Constraints 48 | vector > Ap; 49 | vector bp; 50 | 51 | int curr_pos = 0; 52 | stack positions; 53 | 54 | inline void print_delimiter() 55 | { 56 | printf("---------------------------------------------------------------\n"); 57 | } 58 | 59 | inline int encode_edge(int i, int j) 60 | { 61 | // Precondition: i > j 62 | assert(i > j); 63 | return (((i - 1) * (i - 2)) >> 1) + (j - 1); 64 | } 65 | 66 | inline pair decode_edge(int x) 67 | { 68 | int i = 2, j = 1; 69 | 70 | while (((i * (i - 1)) >> 1) <= x) i++; 71 | j = x - (((i - 1) * (i - 2)) >> 1) + 1; 72 | 73 | return make_pair(i, j); 74 | } 75 | 76 | inline void dump_lp(int n, int m, double **A, double *b, double *c, double v) 77 | { 78 | fprintf(f_lp, "minimise %.2lf ", v); 79 | for (int i=0;i EPS) 82 | { 83 | fprintf(f_lp, "%c %.2lf * x_{%02d, %02d} ", (c[i] >= 0.0 ? '+' : '-'), fabs(c[i]), decode_edge(i).first, decode_edge(i).second); 84 | } 85 | } 86 | fprintf(f_lp, "\nsubject to\n"); 87 | for (int i=0;i EPS) 93 | { 94 | fprintf(f_lp, "%c %.2lf * x_{%02d, %02d} ", (A[i][j] >= 0.0 ? '+' : '-'), fabs(A[i][j]), decode_edge(j).first, decode_edge(j).second); 95 | } 96 | } 97 | fprintf(f_lp, "\n"); 98 | } 99 | } 100 | 101 | inline void dump_title(double obj, int n, int m, int iter) 102 | { 103 | fprintf(f_graph, "\\node[] (title) at (10, 25) {\\Huge Objective value: $%lf$, $%d$ variables, $%d$ constraints, $%d$ iterations};\n", obj, n, m, iter); 104 | } 105 | 106 | inline void dump_edge(int x, double val) 107 | { 108 | fprintf(f_graph, "\\draw[edge,%s] (%d) to node[lab]{%g} (%d);\n", ((fabs(1.0 - val) < EPS) ? "black" : "red"), decode_edge(x).first, val, decode_edge(x).second); 109 | } 110 | 111 | inline void write_full_edge(int x, int y) 112 | { 113 | fprintf(f_graph, "\\draw[edge] (%d) to node[lab]{%d} (%d);\n", x, 1, y); 114 | } 115 | 116 | char *rep_ext(char *name, const char *ext) 117 | { 118 | char *ret = new char[150]; 119 | strcpy(ret, name); 120 | int ii = strlen(ret) - 1; 121 | while (ii >= 0 && ret[ii] != '.') ii--; 122 | assert(ii >= 0); 123 | int l = strlen(ext); 124 | for (int i=0;i<=l;i++) // takes care of '\0' at the end as well 125 | { 126 | ret[ii + i] = ext[i]; 127 | } 128 | 129 | return ret; 130 | } 131 | 132 | int main() 133 | { 134 | srand(time(NULL)); 135 | 136 | printf("Linear Programming TSP Solver, implemented by Petar Veličković.\n"); 137 | printf("Thanks to Thomas Sauerwald for the visualisation data!\n"); 138 | print_delimiter(); 139 | 140 | printf("Enter the path to the file containing the adjacency matrix:\n"); 141 | scanf("%s", path_adj); 142 | 143 | if ((f_adj = fopen(path_adj, "r")) == NULL) 144 | { 145 | printf("Error: Adjacency matrix file could not be opened!\n"); 146 | return 1; 147 | } 148 | 149 | printf("Processing adjacency matrix...\n"); 150 | if (fscanf(f_adj, "%d", &n) == 0) 151 | { 152 | printf("Error: Improper adjacency matrix format!\n"); 153 | return 2; 154 | } 155 | 156 | printf("The graph has %d nodes.\n", n); 157 | 158 | for (int i=2;i<=n;i++) 159 | { 160 | for (int j=1;j> 1; // the number of edges 178 | 179 | // Generating objective function 180 | for (int i=0;i constr_1(simp_n, 0.0), constr_2(simp_n, 0.0); 189 | 190 | for (int j=1;j<=n;j++) 191 | { 192 | if (j < i) 193 | { 194 | constr_1[encode_edge(i, j)] = -1.0; 195 | constr_2[encode_edge(i, j)] = 1.0; 196 | } 197 | else if (j > i) 198 | { 199 | constr_1[encode_edge(j, i)] = -1.0; 200 | constr_2[encode_edge(j, i)] = 1.0; 201 | } 202 | } 203 | 204 | Ap.push_back(constr_1); 205 | bp.push_back(2.0); 206 | 207 | Ap.push_back(constr_2); 208 | bp.push_back(-2.0); 209 | } 210 | 211 | for (int i=0;i constr(simp_n, 0.0); 214 | constr[i] = -1.0; 215 | 216 | Ap.push_back(constr); 217 | bp.push_back(1.0); 218 | } 219 | 220 | curr_pos = Ap.size(); 221 | 222 | printf("Constraints generated!\n"); 223 | print_delimiter(); 224 | 225 | printf("Enter the path to the folder containing the demo .tex files:\n"); 226 | scanf("%s", path_demo); 227 | print_delimiter(); 228 | 229 | printf("Enter the name of the file containing the graph:\n"); 230 | scanf("%s", file_graph); 231 | print_delimiter(); 232 | 233 | strcpy(path_graph, path_demo); 234 | strcat(path_graph, file_graph); 235 | 236 | printf("Enter the name of the file containing the map:\n"); 237 | scanf("%s", file_map); 238 | print_delimiter(); 239 | 240 | strcpy(path_map, path_demo); 241 | strcat(path_map, file_map); 242 | 243 | strcpy(path_pdf, path_demo); 244 | strcat(path_pdf, rep_ext(file_map, ".pdf")); 245 | 246 | 247 | while (true) 248 | { 249 | printf("Enter one of the following:\n"); 250 | printf("- SOLVE : to launch the Simplex Algorithm on the constraints given thus far;\n"); 251 | printf("- REM_LOOP N x_1 x_2 ... x_N : to add a loop-removing constraint for the subset of N nodes x_1, x_2, ..., x_N;\n"); 252 | printf("- REM_LOOP_RNG lo hi : to add a loop-removing constraint for the contiguous interval of nodes [lo, hi];\n"); 253 | printf("- SET x_1 x_2 v : to add constraints that set the edge between x_1 and x_2 to v (where v is either 0 or 1);\n"); 254 | printf("- UNDO N : to remove the N previously generated constraint sets;\n"); 255 | printf("- APPROX_MST : to run the MST-based 2-approximation algorithm;\n"); 256 | printf("- EXIT : to stop the program.\n"); 257 | scanf("%s", cmd); 258 | 259 | if (strcmp(cmd, "SOLVE") == 0) 260 | { 261 | int constr_n = curr_pos; 262 | 263 | double **A = new double*[constr_n]; 264 | for (int i=0;i simplex(); 291 | 292 | while (std::isnan(get<1>(ret))) 293 | { 294 | delete s; 295 | s = new Simplex(simp_n, constr_n, A, b, c, 0); 296 | ret = s -> simplex(); 297 | } 298 | 299 | delete s; 300 | for (int i=0;i xs = get<0>(ret); 307 | double val = get<1>(ret); 308 | int iters = get<2>(ret); 309 | 310 | if (std::isinf(val)) 311 | { 312 | if (xs[0] == -1) printf("Objective function unbounded!\n"); 313 | else if (xs[0] == -2) printf("Linear program infeasible!\n"); 314 | } 315 | 316 | else 317 | { 318 | printf("Objective value: %lf\n", val); 319 | 320 | //for (int i=0;i 0) dump_edge(i, xs[i]); 333 | } 334 | 335 | fclose(f_graph); 336 | 337 | printf("Results written to the graph file! Compiling the map...\n"); 338 | 339 | sprintf(cmd_map, "(cd %s && exec pdflatex %s &> /dev/null)", path_demo, file_map); 340 | 341 | system(cmd_map); 342 | 343 | printf("Map compiled!\n"); 344 | #ifdef __APPLE__ 345 | // These shell instructions will work only on OS X 346 | sprintf(cmd_prev, "killall qlmanage &> /dev/null; qlmanage -p %s &> /dev/null &", path_pdf); 347 | 348 | printf("%s\n", cmd_prev); 349 | 350 | system(cmd_prev); 351 | #endif 352 | } 353 | 354 | print_delimiter(); 355 | } 356 | 357 | else if (strcmp(cmd, "REM_LOOP") == 0) 358 | { 359 | int num; 360 | scanf("%d", &num); 361 | 362 | vector vals(num); 363 | for (int i=0;i constr(simp_n, 0.0); 366 | 367 | for (int i=0;i vals[j]) constr[encode_edge(vals[i], vals[j])] = -1.0; 372 | else if (vals[i] < vals[j]) constr[encode_edge(vals[j], vals[i])] = -1.0; 373 | } 374 | } 375 | 376 | double val = num - 1.0; 377 | 378 | if (curr_pos == (int)Ap.size()) 379 | { 380 | Ap.push_back(constr); 381 | bp.push_back(val); 382 | } 383 | else 384 | { 385 | Ap[curr_pos] = constr; 386 | bp[curr_pos] = val; 387 | } 388 | 389 | positions.push(curr_pos); 390 | curr_pos++; 391 | 392 | printf("Loop-removing constraint added!\n"); 393 | print_delimiter(); 394 | } 395 | 396 | else if (strcmp(cmd, "REM_LOOP_RNG") == 0) 397 | { 398 | int lo, hi; 399 | scanf("%d%d", &lo, &hi); 400 | 401 | assert(hi >= lo); 402 | 403 | int num = hi - lo + 1; 404 | vector vals(num); 405 | for (int i=0;i constr(simp_n, 0.0); 408 | 409 | for (int i=0;i vals[j]) constr[encode_edge(vals[i], vals[j])] = -1.0; 414 | else if (vals[i] < vals[j]) constr[encode_edge(vals[j], vals[i])] = -1.0; 415 | } 416 | } 417 | 418 | double val = num - 1.0; 419 | 420 | if (curr_pos == (int)Ap.size()) 421 | { 422 | Ap.push_back(constr); 423 | bp.push_back(val); 424 | } 425 | else 426 | { 427 | Ap[curr_pos] = constr; 428 | bp[curr_pos] = val; 429 | } 430 | 431 | positions.push(curr_pos); 432 | curr_pos++; 433 | 434 | printf("Loop-removing constraint added!\n"); 435 | print_delimiter(); 436 | } 437 | 438 | else if (strcmp(cmd, "SET") == 0) 439 | { 440 | // x(i, j) = v 441 | int x, y, v; 442 | scanf("%d%d%d", &x, &y, &v); 443 | 444 | vector constr1(simp_n, 0.0), constr2(simp_n, 0.0); 445 | 446 | if (x > y) 447 | { 448 | constr1[encode_edge(x, y)] = -1.0; 449 | constr2[encode_edge(x, y)] = 1.0; 450 | } 451 | else if (x < y) 452 | { 453 | constr1[encode_edge(y, x)] = -1.0; 454 | constr2[encode_edge(y, x)] = 1.0; 455 | } 456 | 457 | positions.push(curr_pos); 458 | 459 | if (curr_pos == (int)Ap.size()) 460 | { 461 | Ap.push_back(constr1); 462 | bp.push_back(v); 463 | } 464 | else 465 | { 466 | Ap[curr_pos] = constr1; 467 | bp[curr_pos] = v; 468 | } 469 | 470 | curr_pos++; 471 | 472 | if (v == 1) 473 | { 474 | if (curr_pos == (int)Ap.size()) 475 | { 476 | Ap.push_back(constr2); 477 | bp.push_back(-1.0); 478 | } 479 | else 480 | { 481 | Ap[curr_pos] = constr2; 482 | bp[curr_pos] = -1.0; 483 | } 484 | 485 | curr_pos++; 486 | } 487 | 488 | printf("Value setting constraints added!\n"); 489 | print_delimiter(); 490 | } 491 | 492 | else if (strcmp(cmd, "UNDO") == 0) 493 | { 494 | int steps; 495 | scanf("%d", &steps); 496 | 497 | bool done = true; 498 | 499 | while (steps--) 500 | { 501 | if (positions.empty()) 502 | { 503 | printf("There's nothing to undo!\n"); 504 | print_delimiter(); 505 | done = false; 506 | break; 507 | } 508 | 509 | curr_pos = positions.top(); 510 | positions.pop(); 511 | } 512 | 513 | if (!done) continue; 514 | 515 | printf("Previous generated constraint set(s) removed!\n"); 516 | print_delimiter(); 517 | } 518 | 519 | else if (strcmp(cmd, "APPROX_MST") == 0) 520 | { 521 | auto mst_sol = tsp_mst(n, adj); 522 | 523 | printf("Objective value: %lf\n", mst_sol.first); 524 | 525 | //for (int i=0;i /dev/null)", path_demo, file_map); 543 | 544 | system(cmd_map); 545 | 546 | printf("Map compiled!\n"); 547 | #ifdef __APPLE__ 548 | // These shell instructions will work only on OS X 549 | sprintf(cmd_prev, "killall qlmanage &> /dev/null; qlmanage -p %s &> /dev/null &", path_pdf); 550 | 551 | printf("%s\n", cmd_prev); 552 | 553 | system(cmd_prev); 554 | #endif 555 | print_delimiter(); 556 | } 557 | 558 | else if (strcmp(cmd, "EXIT") == 0) 559 | { 560 | break; 561 | } 562 | 563 | else 564 | { 565 | printf("Incorrectly entered command! Try again.\n"); 566 | print_delimiter(); 567 | } 568 | } 569 | 570 | return 0; 571 | } 572 | --------------------------------------------------------------------------------