Done c++ ant colony opt with 2.5opt = 7.5
This commit is contained in:
parent
9f61b503d1
commit
55fa9b5d64
15 changed files with 670 additions and 1868 deletions
141
.gitignore
vendored
141
.gitignore
vendored
|
@ -24,3 +24,144 @@
|
|||
/Complete notebooks/
|
||||
/Lectures/.ipynb_checkpoints/
|
||||
/.ipynb_checkpoints/Student_lecture 1-checkpoint.ipynb
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
c_prob/*
|
||||
!c_prob/.gitkeep
|
||||
|
|
BIN
AI_cup_2020_description.pdf
Normal file
BIN
AI_cup_2020_description.pdf
Normal file
Binary file not shown.
BIN
AI_cup_2020_studentname.xls
Normal file
BIN
AI_cup_2020_studentname.xls
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,37 +0,0 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"collapsed": true,
|
||||
"pycharm": {
|
||||
"name": "#%% md\n"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"## Fourth Lecture"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"name": "pycharm-61970693",
|
||||
"language": "python",
|
||||
"display_name": "PyCharm (AI2020BsC)"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 1
|
||||
}
|
427
aco.cc
Normal file
427
aco.cc
Normal file
|
@ -0,0 +1,427 @@
|
|||
// vim: set ts=2 sw=2 et tw=80:
|
||||
|
||||
// compile with
|
||||
// g++ -lpthread --std=c++11 -o c_prob/aco aco.cc
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <unistd.h>
|
||||
|
||||
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
|
||||
double alpha;
|
||||
// beta >= 1
|
||||
double beta;
|
||||
double pheromone_evaporation_coeff;
|
||||
double pheromone_constant;
|
||||
uint n_iterations;
|
||||
|
||||
uint n_ants;
|
||||
|
||||
uint n_nodes;
|
||||
|
||||
double dist_matrix[MAX_NODES][MAX_NODES];
|
||||
double pheromone_map[MAX_NODES][MAX_NODES];
|
||||
double ant_updated_pheromone_map[MAX_NODES][MAX_NODES];
|
||||
|
||||
double sh_dist;
|
||||
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 idx;
|
||||
pthread_t t_handle;
|
||||
uint location;
|
||||
double distance_travelled;
|
||||
set<uint> possible_locations;
|
||||
vector<uint> route;
|
||||
bool tour_complete = false;
|
||||
|
||||
void init() {
|
||||
this->other = 0;
|
||||
|
||||
this->distance_travelled = 0.0;
|
||||
|
||||
this->route.clear();
|
||||
|
||||
this->possible_locations.clear();
|
||||
for (size_t i = 0; i < n_nodes; i++) {
|
||||
this->possible_locations.insert(i);
|
||||
}
|
||||
|
||||
|
||||
this->location = start;
|
||||
|
||||
this->update_route(start);
|
||||
|
||||
this->tour_complete = false;
|
||||
};
|
||||
|
||||
void update_route(uint new_loc) {
|
||||
this->route.push_back(new_loc);
|
||||
this->possible_locations.erase(new_loc);
|
||||
};
|
||||
|
||||
uint pick_path() {
|
||||
if (first_pass) {
|
||||
return select_random(this->possible_locations);
|
||||
} else {
|
||||
double attractiveness[n_nodes];
|
||||
double sum_total = 0.0;
|
||||
vector<uint> idxs;
|
||||
|
||||
for (uint loc : this->possible_locations) {
|
||||
idxs.push_back(loc);
|
||||
double pheromone_amount = pheromone_map[this->location][loc];
|
||||
double distance = dist_matrix[this->location][loc];
|
||||
if (distance == 0) { distance = 0.000000001; };
|
||||
|
||||
attractiveness[loc] = pow(pheromone_amount, alpha) *
|
||||
pow(1 / distance, beta);
|
||||
//cerr << "ant " << idx << " attr[loc]=" << attractiveness[loc] << endl;
|
||||
sum_total += attractiveness[loc];
|
||||
if (isnan(sum_total)) { cerr << "nanalert " << attractiveness[loc] <<
|
||||
" " << pheromone_amount << " " << distance << endl; }
|
||||
}
|
||||
|
||||
// it is possible to have small values for pheromone amount / distance,
|
||||
// such that with rounding errors this is equal to zero
|
||||
if (sum_total == 0.0) {
|
||||
// increment all zero's, such that they are the smallest non-zero
|
||||
// values supported by the system
|
||||
// source: http://stackoverflow.com/a/10426033/5343977
|
||||
for (uint loc : idxs) {
|
||||
attractiveness[loc] = nextafter(attractiveness[loc],
|
||||
std::numeric_limits<double>::infinity());
|
||||
}
|
||||
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);
|
||||
//cerr << "ant " << idx << " w: " << weight + cumulative << endl;
|
||||
if (toss <= (weight + cumulative)) {
|
||||
return loc;
|
||||
}
|
||||
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];
|
||||
}
|
||||
};
|
||||
|
||||
void traverse(uint next) {
|
||||
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);
|
||||
}
|
||||
this->distance_travelled += dist_matrix[this->route[this->route.size() - 1]]
|
||||
[this->route[0]];
|
||||
|
||||
// cerr << "stopped ant" << endl;
|
||||
this->tour_complete = true;
|
||||
}
|
||||
};
|
||||
|
||||
void *ant_thread (void *ant_ptr) {
|
||||
ant& ant = *((struct ant *) ant_ptr);
|
||||
ant.run();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ant* ants;
|
||||
|
||||
void init_ants() {
|
||||
for (size_t i = 0; i < n_ants; i++) {
|
||||
ants[i].init();
|
||||
ants[i].idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_t mut;
|
||||
|
||||
void init_aco() {
|
||||
pthread_mutex_init(&mut, NULL);
|
||||
start = 0;
|
||||
first_pass = true;
|
||||
memset(pheromone_map, 0, sizeof(pheromone_map));
|
||||
memset(ant_updated_pheromone_map, 0, sizeof(ant_updated_pheromone_map));
|
||||
init_ants();
|
||||
sh_dist = -1.0;
|
||||
}
|
||||
|
||||
void populate_ant_updated_pheromone_map(ant& ant) {
|
||||
for (size_t i = 0; i < ant.route.size(); i++) {
|
||||
size_t j = (i + 1) % n_nodes;
|
||||
double current_ph = ant_updated_pheromone_map[ant.route[i]][ant.route[j]];
|
||||
double new_ph = pheromone_constant / ant.distance_travelled;
|
||||
|
||||
ant_updated_pheromone_map[ant.route[i]][ant.route[j]] =
|
||||
ant_updated_pheromone_map[ant.route[j]][ant.route[i]] =
|
||||
current_ph + new_ph;
|
||||
}
|
||||
}
|
||||
|
||||
void update_pheromone_map() {
|
||||
for (size_t i = 0; i < n_nodes; i++) {
|
||||
for (size_t j = 0; j < n_nodes; j++) {
|
||||
pheromone_map[i][j] = (1 - pheromone_evaporation_coeff) *
|
||||
pheromone_map[i][j] + ant_updated_pheromone_map[i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mainloop() {
|
||||
for (size_t i = 0; i < n_iterations; i++) {
|
||||
srand(i);
|
||||
//cerr << "starting ants" << endl;
|
||||
for (uint j = 0; j < n_ants; j++) {
|
||||
pthread_create(&(ants[j].t_handle), NULL, ant_thread, &(ants[j]));
|
||||
}
|
||||
// cerr << "joining ants" << endl;
|
||||
for (uint j = 0; j < n_ants; j++) {
|
||||
pthread_join(ants[j].t_handle, NULL);
|
||||
}
|
||||
//cerr << "summing ants" << endl;
|
||||
uint os = 0;
|
||||
for (uint j = 0; j < n_ants; j++) {
|
||||
os += ants[j].other;
|
||||
populate_ant_updated_pheromone_map(ants[j]);
|
||||
|
||||
if (sh_dist < 0 || ants[j].distance_travelled < sh_dist) {
|
||||
sh_dist = ants[j].distance_travelled;
|
||||
sh_route = ants[j].route;
|
||||
|
||||
cerr << "new short distance is " << sh_dist << " ant " << j << endl;
|
||||
}
|
||||
}
|
||||
|
||||
update_pheromone_map();
|
||||
|
||||
first_pass = false;
|
||||
|
||||
init_ants();
|
||||
|
||||
memset(ant_updated_pheromone_map, 0, sizeof(ant_updated_pheromone_map));
|
||||
|
||||
/*double real = 0;
|
||||
for (uint k = 0; k < n_nodes; k++) {
|
||||
real += dist_matrix[sh_route[k]][sh_route[(k + 1) % n_nodes]];
|
||||
}*/
|
||||
|
||||
cerr << "iteration " << i << ": dist " << sh_dist << endl;// << " os " << os << " rdist " << real << endl;
|
||||
/*
|
||||
uint nnz = 0;
|
||||
double sum = 0, min = 1.0/0.0, max = -1.0/0.0;
|
||||
for (int i = 0; i < n_nodes; i++) {
|
||||
for (int j = 0; j < n_nodes - 1; j++) {
|
||||
if (pheromone_map[i][j] != 0.0) nnz++;
|
||||
sum += pheromone_map[i][j];
|
||||
if (min > pheromone_map[i][j]) min = pheromone_map[i][j];
|
||||
if (max < pheromone_map[i][j]) max = pheromone_map[i][j];
|
||||
}
|
||||
}
|
||||
cerr << "phmap: avg " << sum / (double) (n_nodes * n_nodes) << " min " << min << " max " << max << " nnz " << nnz << endl;*/
|
||||
}
|
||||
}
|
||||
|
||||
uint two_opt() {
|
||||
uint swaps = 0;
|
||||
for (int i = 0; i < n_nodes - 1; i++) {
|
||||
for (int j = i+2; j < n_nodes; j++) {
|
||||
size_t ip = i == 0 ? (n_nodes - 1) : (i - 1);
|
||||
size_t ei = sh_route[i], ej = sh_route[j], eii = sh_route[ip],
|
||||
ejj = sh_route[j];
|
||||
double new_dist = sh_dist - dist_matrix[eii][ei] - dist_matrix[ejj][ej]
|
||||
+ dist_matrix[ei][ej] + dist_matrix[ejj][eii];
|
||||
if (new_dist < sh_dist) {
|
||||
//cerr << "2opt " << i << " " << j << ": " << new_dist << endl;
|
||||
sh_dist = new_dist;
|
||||
reverse(sh_route.begin() + i, sh_route.begin() + j);
|
||||
swaps++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return swaps;
|
||||
}
|
||||
|
||||
uint two_five_opt() {
|
||||
uint swaps = 0;
|
||||
for (int i = 0; i < n_nodes - 2; i++) {
|
||||
for (int j = i+2; j < n_nodes; j++) {
|
||||
size_t ip = i == 0 ? (n_nodes - 1) : (i - 1);
|
||||
size_t x1 = sh_route[ip];
|
||||
size_t x2 = sh_route[i];
|
||||
size_t x3 = sh_route[i+1];
|
||||
|
||||
size_t y3 = sh_route[j-2];
|
||||
size_t y1 = sh_route[j-1];
|
||||
size_t y2 = sh_route[j];
|
||||
|
||||
double var_a = sh_dist - dist_matrix[x2][x1] - dist_matrix[y2][y1]
|
||||
+ dist_matrix[x1][y1] + dist_matrix[y2][x2];
|
||||
|
||||
double var_b = sh_dist - dist_matrix[x2][x1] - dist_matrix[y2][y1]
|
||||
- dist_matrix[x2][x3] + dist_matrix[x2][y2]
|
||||
+ dist_matrix[y1][x2] + dist_matrix[x1][x3];
|
||||
|
||||
double var_c = sh_dist - dist_matrix[x2][x1] - dist_matrix[y2][y1]
|
||||
- dist_matrix[y1][y3] + dist_matrix[x1][y1]
|
||||
+ 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return swaps;
|
||||
}
|
||||
|
||||
#define buffersize 100000
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 8) {
|
||||
cerr << argv[0] << " [n_nodes] [n_iter] [n_ants] [alpha] [beta] [evap] [weight]" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
n_nodes = atoi(argv[1]);
|
||||
n_iterations = atoi(argv[2]);
|
||||
n_ants = atoi(argv[3]);
|
||||
sscanf(argv[4], "%lf", &alpha);
|
||||
sscanf(argv[5], "%lf", &beta);
|
||||
sscanf(argv[6], "%lf", &pheromone_evaporation_coeff);
|
||||
sscanf(argv[7], "%lf", &pheromone_constant);
|
||||
ant ants_arr[n_ants];
|
||||
ants = ants_arr;
|
||||
|
||||
cerr << n_nodes << endl;
|
||||
char * pch;
|
||||
int row = 0, column = 0;
|
||||
|
||||
char buffer[buffersize];
|
||||
for (size_t i = 0; i < n_nodes; i++) {
|
||||
fgets(buffer, buffersize, stdin);
|
||||
pch = strtok(buffer, " ");
|
||||
column = 0;
|
||||
|
||||
while (pch != NULL) {
|
||||
sscanf(pch, "%lf", &(dist_matrix[row][column]));
|
||||
pch = strtok(NULL, " ");
|
||||
column++;
|
||||
}
|
||||
row++;
|
||||
}
|
||||
|
||||
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
|
||||
mainloop();
|
||||
|
||||
//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 << "optimized length: " << sh_dist << endl;
|
||||
cout << sh_route << endl;
|
||||
}
|
46
run.py
46
run.py
|
@ -1,13 +1,17 @@
|
|||
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
|
||||
|
||||
|
||||
def use_solver_to_compute_solution(solver, improve, index, results, name, verbose, show_plots):
|
||||
solver.bind(improve)
|
||||
#solver.bind(improve)
|
||||
# solver.bind("2-opt")
|
||||
# solver.bind("2.5-opt")
|
||||
solver.compute_solution(return_value=False, verbose=verbose)
|
||||
# solver.pop()
|
||||
# solver.pop()
|
||||
|
||||
if verbose:
|
||||
print(f"the total length for the solution found is {solver.found_length}",
|
||||
|
@ -23,8 +27,10 @@ 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/eil76.tsp"]
|
||||
problems = glob.glob('./problems/*.tsp')
|
||||
|
||||
problems = ["./problems/fl1577.tsp"]
|
||||
|
||||
solvers_names = available_solvers.keys()
|
||||
improvers_names = available_improvers.keys()
|
||||
results = []
|
||||
|
@ -36,19 +42,22 @@ def run(show_plots=False, verbose=False):
|
|||
if show_plots:
|
||||
prob_instance.plot_data()
|
||||
|
||||
|
||||
for solver_name in solvers_names:
|
||||
for improve in improvers_names:
|
||||
solver = TSPSolver(solver_name, prob_instance)
|
||||
use_solver_to_compute_solution(solver, improve, index, results, problem_path, verbose, show_plots)
|
||||
for improve2 in [j for j in improvers_names if j not in [improve]]:
|
||||
use_solver_to_compute_solution(solver, improve2, index, results, problem_path, verbose, show_plots)
|
||||
|
||||
for improve3 in [j for j in improvers_names if j not in [improve, improve2]]:
|
||||
use_solver_to_compute_solution(solver, improve3, index, results, problem_path, verbose,
|
||||
show_plots)
|
||||
solver.pop()
|
||||
|
||||
solver.pop()
|
||||
use_solver_to_compute_solution(solver, None, index, results, problem_path, verbose, show_plots)
|
||||
# for improve in improvers_names:
|
||||
# solver = TSPSolver(solver_name, prob_instance)
|
||||
# use_solver_to_compute_solution(solver, improve, index, results, problem_path, verbose, show_plots)
|
||||
# for improve2 in [j for j in improvers_names if j not in [improve]]:
|
||||
# use_solver_to_compute_solution(solver, improve2, index, results, problem_path, verbose, show_plots)
|
||||
#
|
||||
# for improve3 in [j for j in improvers_names if j not in [improve, improve2]]:
|
||||
# use_solver_to_compute_solution(solver, improve3, index, results, problem_path, verbose,
|
||||
# show_plots)
|
||||
# solver.pop()
|
||||
#
|
||||
# solver.pop()
|
||||
|
||||
if prob_instance.exist_opt and show_plots:
|
||||
solver = TSPSolver("optimal", prob_instance)
|
||||
|
@ -56,11 +65,12 @@ def run(show_plots=False, verbose=False):
|
|||
solver.solution = np.concatenate([prob_instance.optimal_tour, [prob_instance.optimal_tour[0]]])
|
||||
solver.plot_solution()
|
||||
|
||||
index = pd.MultiIndex.from_tuples(index, names=['problem', 'method'])
|
||||
#index = pd.MultiIndex.from_tuples(index, names=['problem', 'method'])
|
||||
|
||||
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__':
|
||||
df = run(show_plots=False, verbose=True)
|
||||
df = run(show_plots=True, verbose=True)
|
||||
df.to_csv("./results.csv")
|
||||
|
|
|
@ -6,17 +6,23 @@ from src.two_opt import loop2opt
|
|||
from src.two_dot_five_opt import loop2dot5opt
|
||||
from src.simulated_annealing import sa
|
||||
from src.constructive_algorithms import random_method, nearest_neighbor, best_nearest_neighbor, multi_fragment_mf
|
||||
from src.ant_colony import ant_colony_opt
|
||||
|
||||
available_solvers = {"random": random_method,
|
||||
"nearest_neighbors": nearest_neighbor,
|
||||
"best_nn": best_nearest_neighbor,
|
||||
"multi_fragment": multi_fragment_mf
|
||||
}
|
||||
|
||||
# available_solvers = {"random": random_method,
|
||||
# "nearest_neighbors": nearest_neighbor,
|
||||
# "best_nn": best_nearest_neighbor,
|
||||
# "multi_fragment": multi_fragment_mf
|
||||
# }
|
||||
available_improvers = {"2-opt": loop2opt,
|
||||
"2.5-opt": loop2dot5opt,
|
||||
"simulated_annealing": sa}
|
||||
|
||||
# available_solvers = {}
|
||||
# for i in range(1, 10):
|
||||
# for j in range(1, 10):
|
||||
# available_solvers["aco_" + str(i) + "_" + str(j)] = ant_colony_opt(i/10, j)
|
||||
|
||||
available_solvers = {"aco": ant_colony_opt}
|
||||
|
||||
class TSPSolver:
|
||||
def __init__(self, algorithm_name, problem_instance, passed_avail_solvers=None, passed_avail_improvers=None):
|
||||
|
@ -52,14 +58,14 @@ class TSPSolver:
|
|||
print(f"### solving with {self.algorithms} ####")
|
||||
start_time = t()
|
||||
self.solution = self.available_solvers[self.algorithms[0]](self.problem_instance)
|
||||
if self.check_if_solution_is_valid():
|
||||
if not self.check_if_solution_is_valid():
|
||||
print(f"Error the solution of {self.algorithm_name} for problem {self.problem_instance.name} is not valid")
|
||||
if return_value:
|
||||
return False
|
||||
for i in range(1, len(self.algorithms)):
|
||||
improver = self.algorithms[i]
|
||||
self.solution = self.available_improvers[improver](self.solution, self.problem_instance)
|
||||
if self.check_if_solution_is_valid():
|
||||
if not self.check_if_solution_is_valid():
|
||||
print(
|
||||
f"Error the solution of {self.algorithm_name} with {improver} for problem {self.problem_instance.name} is not valid")
|
||||
if return_value:
|
||||
|
|
55
src/ant_colony.py
Normal file
55
src/ant_colony.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
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)
|
||||
|
||||
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)
|
||||
|
||||
alpha, beta, evap, weight = (0.9, 8, 0.4, 100_000)
|
||||
ants, loops = (1000,7) 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)
|
||||
|
||||
# Call C++ program
|
||||
cmd = dir + "aco " + str(instance.nPoints) + " " + str(loops) + " " + str(ants) + \
|
||||
" " + str(alpha) + " " + str(beta) + " " + str(evap) + " " + str(weight) +" < " + fname + " &2>/dev/null"
|
||||
print(cmd)
|
||||
solution = eval(os.popen(cmd).read())
|
||||
solution.append(solution[0])
|
||||
return solution
|
||||
|
||||
if __name__ == "__main__":
|
||||
ant_colony_opt(ProblemInstance("../problems/eil76.tsp"))
|
||||
|
|
@ -2,13 +2,11 @@ import numpy as np
|
|||
|
||||
from src.utils import compute_length
|
||||
|
||||
|
||||
def random_method(instance_):
|
||||
n = int(instance_.nPoints)
|
||||
solution = np.random.choice(np.arange(n), size=n, replace=False)
|
||||
return np.concatenate([solution, [solution[0]]])
|
||||
|
||||
|
||||
def nearest_neighbor(instance_, starting_node=0):
|
||||
dist_matrix = np.copy(instance_.dist_matrix)
|
||||
n = int(instance_.nPoints)
|
||||
|
|
|
@ -27,7 +27,8 @@ def step2dot5opt(solution, matrix_dist, distance):
|
|||
uncrosses += 1
|
||||
tsp_sequence = sequences[best_method]
|
||||
distance = best_len
|
||||
# print(distance, best_method, [twoOpt_len, first_shift_len, second_shift_len])
|
||||
print(i, j, best_len)
|
||||
#print(distance, best_method, [twoOpt_len, first_shift_len, second_shift_len])
|
||||
return tsp_sequence, distance, uncrosses
|
||||
|
||||
|
||||
|
@ -62,7 +63,7 @@ def shift_gain2(i, j, tsp_sequence, matrix_dist):
|
|||
return - old_link_len + changed_links_len
|
||||
|
||||
|
||||
def loop2dot5opt(solution, instance, max_num_of_changes=10000):
|
||||
def loop2dot5opt(solution, instance, max_num_of_changes=2500):
|
||||
matrix_dist = instance.dist_matrix
|
||||
actual_len = compute_length(solution, matrix_dist)
|
||||
new_tsp_sequence = np.copy(np.array(solution))
|
||||
|
|
|
@ -2,7 +2,6 @@ import numpy as np
|
|||
|
||||
from src.utils import compute_length
|
||||
|
||||
|
||||
def step2opt(solution, matrix_dist, distance):
|
||||
seq_length = len(solution) - 1
|
||||
tsp_sequence = np.array(solution)
|
||||
|
@ -26,7 +25,7 @@ def swap2opt(tsp_sequence, i, j):
|
|||
|
||||
def gain(i, j, tsp_sequence, matrix_dist):
|
||||
old_link_len = (matrix_dist[tsp_sequence[i], tsp_sequence[i - 1]] + matrix_dist[
|
||||
tsp_sequence[j], tsp_sequence[j + 1]])
|
||||
tsp_sequence[j], tsp_sequence[j + 1]])x
|
||||
changed_links_len = (matrix_dist[tsp_sequence[j], tsp_sequence[i - 1]] + matrix_dist[
|
||||
tsp_sequence[i], tsp_sequence[j + 1]])
|
||||
return - old_link_len + changed_links_len
|
||||
|
|
Reference in a new issue