This commit is contained in:
Claudio Maggioni 2020-12-20 19:39:46 +01:00
parent 061b9f7d32
commit 412c87ef2a
6 changed files with 164 additions and 127 deletions

118
aco.cc
View File

@ -13,19 +13,13 @@
#include <iostream>
#include <algorithm>
#include <unistd.h>
#include "opt.h"
#define SINGLE_CORE 1
using namespace std;
typedef unsigned int uint;
ostream& operator<< (ostream& out, vector<uint> a) {
out << "[";
for (int i = 0; i < a.size() - 1; i++) {
out << a[i] << ",";
}
out << a[a.size() - 1] << "]";
return out;
}
const uint MAX_NODES = 1577;
// alpha >= 0
@ -49,16 +43,11 @@ vector<uint> sh_route;
bool first_pass;
uint start;
uint select_random(const set<uint> &s) {
auto n = rand() % s.size(); // not _really_ random
auto it = begin(s);
advance(it, n); // 'advance' the iterator n times
return *it;
}
struct ant {
uint other;
uint seed;
uint idx;
uint iter;
pthread_t t_handle;
uint location;
double distance_travelled;
@ -66,8 +55,15 @@ struct ant {
vector<uint> route;
bool tour_complete = false;
uint select_random(const set<uint> &s) {
auto n = rand_r(&seed) % s.size(); // not _really_ random
auto it = begin(s);
advance(it, n); // 'advance' the iterator n times
return *it;
}
void init() {
this->other = 0;
this->seed = this->idx * 1000 + this->iter;
this->distance_travelled = 0.0;
@ -78,7 +74,6 @@ struct ant {
this->possible_locations.insert(i);
}
this->location = start;
this->update_route(start);
@ -95,6 +90,8 @@ struct ant {
if (first_pass) {
return select_random(this->possible_locations);
} else {
double toss = (double) rand_r(&seed) / (double) RAND_MAX;
double attractiveness[n_nodes];
double sum_total = 0.0;
vector<uint> idxs;
@ -126,10 +123,6 @@ struct ant {
sum_total = nextafter(sum_total, std::numeric_limits<double>::infinity());
}
double toss = (double) rand() / (double) RAND_MAX;
// cerr << "ant " << idx << " sum_total is " << sum_total << " toss is " << toss << endl;
double cumulative = 0.0;
for (uint loc : idxs) {
double weight = (attractiveness[loc] / sum_total);
@ -140,11 +133,6 @@ struct ant {
cumulative += weight;
}
cerr << "cum " << cumulative << " n " << idxs.size() << " toss " << toss << endl;
sleep(1);
other++;
// cerr << "ant " << idx << " change statement" << endl;
return idxs[idxs.size() - 1];
}
};
@ -153,11 +141,9 @@ struct ant {
this->update_route(next);
this->distance_travelled += dist_matrix[this->location][next];
this->location = next;
//cerr << "traversing " << next << " dist: " << this->distance_travelled << endl;
}
void run() {
// cerr << "started ant - # can pick: " << this->possible_locations.size() << endl;
while (!this->possible_locations.empty()) {
uint next = this->pick_path();
this->traverse(next);
@ -165,7 +151,6 @@ struct ant {
this->distance_travelled += dist_matrix[this->route[this->route.size() - 1]]
[this->route[0]];
// cerr << "stopped ant" << endl;
this->tour_complete = true;
}
};
@ -178,10 +163,11 @@ void *ant_thread (void *ant_ptr) {
ant* ants;
void init_ants() {
void init_ants(size_t it) {
for (size_t i = 0; i < n_ants; i++) {
ants[i].init();
ants[i].idx = i;
ants[i].iter = it;
ants[i].init();
}
}
@ -193,7 +179,7 @@ void init_aco() {
first_pass = true;
memset(pheromone_map, 0, sizeof(pheromone_map));
memset(ant_updated_pheromone_map, 0, sizeof(ant_updated_pheromone_map));
init_ants();
init_ants(0);
sh_dist = -1.0;
}
@ -220,8 +206,12 @@ void update_pheromone_map() {
double mainloop(size_t i) {
srand(i);
//cerr << "starting ants" << endl;
#if SINGLE_CORE
for (uint j = 0; j < n_ants; j++) {
ant_thread(&(ants[j]));
}
#else
for (uint j = 0; j < n_ants; j++) {
pthread_create(&(ants[j].t_handle), NULL, ant_thread, &(ants[j]));
}
@ -229,11 +219,10 @@ double mainloop(size_t i) {
for (uint j = 0; j < n_ants; j++) {
pthread_join(ants[j].t_handle, NULL);
}
#endif
//cerr << "summing ants" << endl;
uint os = 0;
unsigned long sum = 0L;
for (uint j = 0; j < n_ants; j++) {
os += ants[j].other;
populate_ant_updated_pheromone_map(ants[j]);
sum += ants[j].distance_travelled;
@ -250,7 +239,7 @@ double mainloop(size_t i) {
first_pass = false;
init_ants();
init_ants(i+1);
memset(ant_updated_pheromone_map, 0, sizeof(ant_updated_pheromone_map));
@ -321,30 +310,22 @@ uint two_five_opt() {
+ dist_matrix[y1][x2] + dist_matrix[y3][y2];
if (var_a < sh_dist && var_a < var_b && var_a < var_c) {
//cerr << "25opt(a) " << i << " " << j << ": " << var_a << endl;
sh_dist = var_a;
reverse(sh_route.begin() + i, sh_route.begin() + j);
swaps++;
} else if (var_b < sh_dist && var_b < var_a && var_b < var_c) {
//cerr << "25opt(b) " << i << " " << j << ": " << var_b << endl;
//cerr << vector<uint>(sh_route.begin() + i - 1, sh_route.begin() + j + 1) << endl;
for (int k = i; k < j - 1; k++) {
sh_route[k] = sh_route[k + 1];
}
sh_route[j - 1] = x2;
//cerr << vector<uint>(sh_route.begin() + i - 1, sh_route.begin() + j + 1) << endl;
sh_dist = var_b;
swaps++;
} else if (var_c < sh_dist && var_c < var_a && var_c < var_b) {
//cerr << "25opt(c) " << i << " " << j << ": " << var_c << endl;
//cerr << vector<uint>(sh_route.begin() + i - 1, sh_route.begin() + j + 1) << endl;
for (int k = j - 2; k >= i; k--) {
sh_route[k + 1] = sh_route[k];
}
sh_route[i] = y1;
//cerr << vector<uint>(sh_route.begin() + i - 1, sh_route.begin() + j + 1) << endl;
sh_dist = var_c;
swaps++;
}
@ -357,8 +338,10 @@ uint two_five_opt() {
int main(int argc, char** argv) {
unsigned started = time(NULL);
if (argc < 8) {
cerr << argv[0] << " [n_nodes] [n_iter] [n_ants] [alpha] [beta] [evap] [weight]" << endl;
int optruns;
if (argc < 9) {
cerr << argv[0] << " [n_nodes] [n_iter] [n_ants] [alpha] [beta] [evap] [weight] [optruns]" << endl;
return 1;
}
@ -369,6 +352,7 @@ int main(int argc, char** argv) {
sscanf(argv[5], "%lf", &beta);
sscanf(argv[6], "%lf", &pheromone_evaporation_coeff);
sscanf(argv[7], "%lf", &pheromone_constant);
sscanf(argv[8], "%d", &optruns);
ant ants_arr[n_ants];
ants = ants_arr;
@ -392,18 +376,7 @@ int main(int argc, char** argv) {
cerr << "reading done" << endl;
/*uint nnz = 0;
for (int i = 0; i < n_nodes; i++) {
for (int j = 0; j < n_nodes - 1; j++) {
if (dist_matrix[i][j] != 0.0) nnz++;
}
}
cerr << "dist: nnz " << nnz << endl;*/
init_aco();
// scan and parse
unsigned limit = 175;
unsigned last_time = started;
@ -411,36 +384,25 @@ int main(int argc, char** argv) {
for (size_t i = 0; i < n_iterations; i++) {
double d = mainloop(i);
unsigned now = time(NULL);
cerr << "iter: " << i << " - dist: " << sh_dist << " - avg: "
<< d << " - elapsed: " << now - started << endl;
if ((now - started) + last_delta > limit) {
cerr << "out of time" << endl;
break;
}
cerr << "iter: " << i << " - dist: " << sh_dist << " - avg: "
<< d << " - elapsed: " << now - started << endl;
last_delta = now - last_time;
last_time = now;
}
//for (uint k = 0; k < n_nodes; k++) {
// cerr << "p: " << sh_route[k] << ": " << dist_matrix[sh_route[k]][sh_route[(k + 1) % n_nodes]] << endl;
//}
cerr << "pre-optimization length: " << sh_dist << endl;
uint i = 0;
uint j = 0;
do {
//for (i = 0; i < 50; i++) {
//cerr << "2opt round " << i << endl;
//if(two_opt() == 0) break;
//}
for (j = 0; j < 50; j++) {
//cerr << "25opt round " << j << endl;
if(two_five_opt() == 0) break;
}
cerr << "optimizing length: " << sh_dist << endl;
} while (i > 0 || j > 0);
cerr << sh_route << endl;
for (uint j = 0; j < optruns; j++) {
two_five_opt();
three_opt(sh_route, dist_matrix, sh_dist);
cerr << "optimized length " << j << " : " << sh_dist << endl;
}
cerr << "optimized length: " << sh_dist << endl;
cout << sh_route << endl;
}

84
opt.cc Normal file
View File

@ -0,0 +1,84 @@
// vim: set ts=2 sw=2 et tw=80:
#include "opt.h"
using namespace std;
typedef unsigned int uint;
typedef tuple<uint, uint, uint> triple;
ostream& operator<< (ostream& out, vector<uint> a) {
out << "[";
for (int i = 0; i < a.size() - 1; i++) {
out << a[i] << ",";
}
out << a[a.size() - 1] << "]";
return out;
}
ostream& operator<< (ostream& out, triple& a) {
out << "(" << get<0>(a) << "," << get<1>(a) << "," << get<2>(a) << ")";
return out;
}
double reverse_segment_if_better(vector<uint>& tour, const double (&dist_matrix) [1577][1577],
uint i, uint j, uint k) {
uint A = tour[i-1];
uint B = tour[i];
uint C = tour[j-1];
uint D = tour[j];
uint E = tour[k-1];
uint F = tour[k % (tour.size()-1)];
double d0 = (dist_matrix[A][B] + dist_matrix[C][D] + dist_matrix[E][F]);
double d1 = (dist_matrix[A][C] + dist_matrix[B][D] + dist_matrix[E][F]);
double d2 = (dist_matrix[A][B] + dist_matrix[C][E] + dist_matrix[D][F]);
double d3 = (dist_matrix[A][D] + dist_matrix[E][B] + dist_matrix[C][F]);
double d4 = (dist_matrix[F][B] + dist_matrix[C][D] + dist_matrix[E][A]);
if (d0 > d1) {
reverse(tour.begin() + i, tour.begin() + j);
return -d0 + d1;
}
else if (d0 > d2) {
reverse(tour.begin() + j, tour.begin() + k);
return -d0 + d2;
}
else if (d0 > d4) {
reverse(tour.begin() + i, tour.begin() + k);
return -d0 + d4;
}
else if (d0 > d3) {
vector<uint> tmp;
for (uint z = j; z < k; z++) {
tmp.push_back(tour[z]);
}
for (uint z = i; z < j; z++) {
tmp.push_back(tour[z]);
}
for (uint f = i; f < k; f++) {
tour[f] = tmp[f - i];
}
return -d0 + d3;
}
return 0;
}
void three_opt(vector<uint>& tour, const double (&dist_matrix) [1577][1577], double& sh_dist) {
double delta = 0;
uint n = tour.size() - 1;
for (uint i = 0; i < 1; i++) {
for (uint i = 1; i < n; i++)
for (uint j = i+2; j < n; j++)
for (uint k = j+2; k < n; k++) {
double d = reverse_segment_if_better(tour, dist_matrix, i, j, k);
if (d > 0) cerr << d << " " << i << "," << j << "," << k << endl;
delta += d;
}
if (delta >= 0)
break;
}
sh_dist += delta;
}

11
opt.h Normal file
View File

@ -0,0 +1,11 @@
#include <iostream>
#include <vector>
#include <utility>
#include <limits>
#include <algorithm>
#include <tuple>
extern void three_opt(std::vector<uint>& tour,
const double (&dist_matrix) [1577][1577],
double& sh_dist);
extern std::ostream& operator<< (std::ostream& out, std::vector<uint> a);

8
run.py
View File

@ -1,5 +1,5 @@
import glob
#import pandas as pd
import pandas as pd
from src.io_tsp import ProblemInstance
from src.TSP_solver import TSPSolver, available_improvers, available_solvers
import numpy as np
@ -29,7 +29,7 @@ def use_solver_to_compute_solution(solver, improve, index, results, name, verbos
def run(show_plots=False, verbose=False):
problems = glob.glob('./problems/*.tsp')
problems = ["./problems/fl1577.tsp"]
# problems = ["./problems/fl1577.tsp"]
solvers_names = available_solvers.keys()
improvers_names = available_improvers.keys()
@ -67,8 +67,8 @@ def run(show_plots=False, verbose=False):
#index = pd.MultiIndex.from_tuples(index, names=['problem', 'method'])
return None
#return pd.DataFrame(results, index=index, columns=["tour length", "optimal solution", "gap", "time to solve"])
#return None
return pd.DataFrame(results, index=index, columns=["tour length", "optimal solution", "gap", "time to solve"])
if __name__ == '__main__':

View File

@ -1,61 +1,41 @@
from src.io_tsp import ProblemInstance
import os
# OOT = out-of-time
# Run #0 unknown
# Run #1
# alpha = 0.5, beta = 7, evap = 0.5, weight = instance.best_sol
# if instance.nPoints > 1000: ants = 550 loops = 15
# elif instance.nPoints > 195: ants = 1000 loops = 55
# else: ants = 2500 loops = 150
# pr439=112263 pcb442=53699 d198=16199 fl1577=<OOT> ch130=6332 u1060=247703
# kroA100=21737 eil76=554 rat783=<OOT> lin318=45580
# Run #2
# alpha, beta, evap, weight = (0.9, 8, 0.4, 100_000)
# ants, loops = (900, 6) if instance.nPoints > 1100 \
# else (600, 15) if instance.nPoints > 1000 \
# else (750, 30) if instance.nPoints > 700 \
# else (975, 40) if instance.nPoints > 500 \
# else (1000, 50) if instance.nPoints > 300 \
# else (1100, 70) if instance.nPoints > 195 else (2700, 140)
# pr439=111322 pcb442=52176 d198=16177 ch130=6269 u1060=246085
# kroA100=21665 eil76=550 lin318=43675
# Separate run: fl1577=24238 (132s) rat783=9389 (174s)
# Run #3
# alpha, beta, evap, weight = (0.1, 1, 0.1, 1 - 15/instance.nPoints)
# ants, loops = (800, 75) if instance.nPoints > 1100 \
# else (800, 100) if instance.nPoints > 1000 \
# else (800, 300) if instance.nPoints > 700 \
# else (800, 750) if instance.nPoints > 500 \
# else (800, 1000) if instance.nPoints > 300 \
# else (800, 1250) if instance.nPoints > 195 else (800, 1500)
dir = "/Users/maggicl/Git/AI2020BsC/c_prob/"
def ant_colony_opt(instance):
fname = dir + instance.name + ".txt"
# write .mat file for C++
if not os.path.exists(fname):
with open(fname, "w") as f:
for i in range(instance.nPoints):
print(" ".join(map(str, instance.dist_matrix[i])), file=f)
with open(fname, "w") as f:
for i in range(instance.nPoints):
print(" ".join(map(str, instance.dist_matrix[i])), file=f)
alpha, beta, evap, weight = (0.9, 6, 0.6, 100_000)
ants, loops = (400, 100_000) if instance.nPoints > 1100 \
else (600, 15) if instance.nPoints > 1000 \
else (750, 30) if instance.nPoints > 700 \
else (975, 40) if instance.nPoints > 500 \
else (1000, 50) if instance.nPoints > 300 \
else (1100, 70) if instance.nPoints > 195 else (2700, 140)
# single core params
params = {
"eil76": (0.9, 8, 0.4, 1000, 500, 200, 30), # 543
"d198": (0.9, 8, 0.4, 1000, 500, 60, 30), # 16042
"ch130": (0.9, 8, 0.4, 1000, 1750, 25, 30), # 6212
"kroA100": (0.9, 8, 0.4, 1000, 750, 100, 30), # 21378
"lin318": (0.9, 8, 0.4, 1000, 500, 32, 30), # 43171
"pcb442": (0.9, 8, 0.4, 1000, 450, 24, 3), # 52466
"pr439": (0.9, 8, 0.4, 1000, 450, 24, 2), # 11734
"rat783": (0.9, 8, 0.4, 1000, 450, 24, 2), # 9232
"u1060": (0.9, 8, 0.4, 1000, 350, 6, 3), # 238025
"fl1577": (0.9, 8, 0.4, 1000, 50, 9, 3), # 24145
}
# params_multicore = {
# "d198": (0.9, 8, 0.4, 1000, 750, 200, 30), # 15970
# "ch130": (0.9, 8, 0.4, 1000, 1750, 200, 30), # 6173
# }
alpha, beta, evap, weight, ants, loops, optruns = params[instance.name]
# Call C++ program
cmd = dir + "aco " + str(instance.nPoints) + " " + str(loops) + " " + str(ants) + \
" " + str(alpha) + " " + str(beta) + " " + str(evap) + " " + str(weight) + \
" " + str(alpha) + " " + str(beta) + " " + str(evap) + " " + str(weight) + " " + str(optruns) + \
" < " + fname + " &2>/dev/null"
print(cmd)
solution = eval(os.popen(cmd).read())
solution.append(solution[0])
print(solution)
print(len(solution))
return solution