Skip to content

Commit

Permalink
Add Common Algorithm for TSP
Browse files Browse the repository at this point in the history
  • Loading branch information
heatingma committed Aug 19, 2024
1 parent 98c1d4b commit da2fa9b
Show file tree
Hide file tree
Showing 47 changed files with 34,430 additions and 7 deletions.
2 changes: 2 additions & 0 deletions ml4co_kit/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import importlib.util

# base
from .algorithm import tsp_greedy_decoder, tsp_insertion_decoder, tsp_mcts_decoder
from .algorithm import tsp_mcts_local_search
from .data import TSPLIBOriDataset, TSPUniformDataset, TSPLIB4MLDataset, ML4TSPDataset
from .data import SATLIBOriDataset
from .data import VRPLIBOriDataset
Expand Down
4 changes: 4 additions & 0 deletions ml4co_kit/algorithm/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .tsp import (
tsp_greedy_decoder, tsp_mcts_decoder, tsp_insertion_decoder,
tsp_mcts_local_search
)
2 changes: 2 additions & 0 deletions ml4co_kit/algorithm/tsp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .decoder import tsp_mcts_decoder, tsp_greedy_decoder, tsp_insertion_decoder
from .local_search import tsp_mcts_local_search
3 changes: 3 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .greedy import tsp_greedy_decoder
from .mcts import tsp_mcts_decoder
from .insertion import tsp_insertion_decoder
25 changes: 25 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_insertion/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Specify the target shared library name
TARGET := insertion.so

# Specify the compiler and compilation options
CXX := g++
CXXFLAGS := -std=c++11 -fPIC -Wall

# Specify the source files and object files
CPP_SRC := insertion.cpp # Specify your .cpp filename here
OBJ := $(CPP_SRC:.cpp=.o)

# Default target
all: $(TARGET)

# Generate the shared library
$(TARGET): $(OBJ)
$(CXX) $(CXXFLAGS) -shared $^ -o $@

# Generate the object file
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $@

# Clean the generated files
clean:
rm -f $(OBJ) $(TARGET)
28 changes: 28 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_insertion/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import ctypes
import platform
import os
import pathlib


os_name = platform.system().lower()
if os_name == "windows":
raise NotImplementedError("Temporarily not supported for Windows platform")
else:
c_insertion_path = pathlib.Path(__file__).parent
c_insertion_so_path = pathlib.Path(__file__).parent / "insertion.so"
try:
lib = ctypes.CDLL(c_insertion_so_path)
except:
ori_dir = os.getcwd()
os.chdir(c_insertion_path)
os.system("make clean")
os.system("make")
os.chdir(ori_dir)
lib = ctypes.CDLL(c_insertion_so_path)
c_insertion = lib.insertion
c_insertion.argtypes = [
ctypes.POINTER(ctypes.c_short), # order
ctypes.POINTER(ctypes.c_float), # points
ctypes.c_int, # nodes_num
]
c_insertion.restype = ctypes.POINTER(ctypes.c_int)
24 changes: 24 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_insertion/distance.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef DISTANCE_H
#define DISTANCE_H

#include "insertion.h"

double get_distance(int node1_idx, int node2_idx)
{
double x = coord_x[node1_idx] - coord_x[node2_idx];
double y = coord_y[node1_idx] - coord_y[node2_idx];
double dist = sqrt(x*x + y*y);
return dist;
}


double get_insert_distance(int node1_idx, int node2_idx, int insert_node_idx)
{
double cut_distance = get_distance(node1_idx, node2_idx);
double add_distance_1 = get_distance(node1_idx, insert_node_idx);
double add_distance_2 = get_distance(node2_idx, insert_node_idx);
double insert_distance = add_distance_1 + add_distance_2 - cut_distance;
return insert_distance;
}

#endif // DISTANCE_H
47 changes: 47 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_insertion/greedy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef GREEDY_H
#define GREEDY_H

#include "insertion.h"

void greedy_insertion(void)
{
int i;
int j;
end_idx = 2;
int node1;
int node2;
int cur_node;
int best_insert_idx;
double min_cost;
double cur_cost;
solution[0] = order[0];
solution[1] = order[1];
solution[2] = order[0];

for(i=2; i<nodes_num; ++i){
min_cost = 1000000.0;
cur_node = order[i];

// find the best_insert_idx
for(j=0; j<end_idx; ++j){
node1 = solution[j];
node2 = solution[j+1];
cur_cost = get_insert_distance(node1, node2, cur_node);
if (cur_cost < min_cost){
best_insert_idx = j;
min_cost = cur_cost;
}
}
// insert
for(int k=end_idx+1; k>best_insert_idx+1; --k){
solution[k] = solution[k-1];
}
solution[best_insert_idx+1] = cur_node;

// update end_idx
end_idx ++;
}
}


#endif // GREEDY_H
26 changes: 26 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_insertion/input.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef INPUT_H
#define INPUT_H

#include "insertion.h"

void read_nodes_coords(float *nodes_coords)
{
int i;
for(i=0; i<nodes_num; i++)
{
coord_x[i]= nodes_coords[2*i];
coord_y[i]= nodes_coords[2*i+1];
}
}


void read_order(short* input_order){
int i;
for(i=0; i<nodes_num; i++)
{
order[i] = input_order[i];
}
}


#endif // INPUT_H
24 changes: 24 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_insertion/insertion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#include "insertion.h"
#include "input.h"
#include "memory.h"
#include "greedy.h"
#include "distance.h"
#include "test.h"
#include <iostream>


extern "C" {
int* insertion(
short* input_order,
float *nodes_coords,
int input_nodes_num
){
nodes_num = input_nodes_num;
allocate_memory(input_nodes_num);
read_nodes_coords(nodes_coords);
read_order(input_order);
greedy_insertion();
release_memory(input_nodes_num);
return solution;
}
}
40 changes: 40 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_insertion/insertion.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef INSERTION_H
#define INSERTION_H

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>

// input
int nodes_num;
double *coord_x;
double *coord_y;
int *order;
extern void read_nodes_coords(float *nodes_coords);
extern void read_order(short* input_order);

// memory
extern void allocate_memory(int nodes_num);
extern void release_memory(int nodes_num);

// distance
extern double get_distance(int node1_idx, int node2_idx);
extern double get_insert_distance(int node1_idx, int node2_idx, int insert_node_idx);

// solution & nodes
int *solution;

// greedy insertion
int end_idx;
extern void greedy_insertion(void);

// test
extern void print_num(int x);
extern void print_solution(void);
extern void print_solution_length(void);

#endif // INSERTION_H
25 changes: 25 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_insertion/memory.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef MEMORY_H
#define MEMORY_H

#include "insertion.h"

// Allocate Memory
void allocate_memory(int nodes_num)
{
// input parameters
coord_x = new double [nodes_num];
coord_y = new double [nodes_num];
order = new int [nodes_num];
solution = new int [nodes_num+1];
}


// Release Memory
void release_memory(int nodes_num)
{
delete []coord_x;
delete []coord_y;
delete []order;
}

#endif
33 changes: 33 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_insertion/test.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifndef TEST_H
#define TEST_H

#include "insertion.h"

// print number
void print_num(int x)
{
std::cout << x << std::endl;
}

// print solution
void print_solution(void)
{
for(int i=0; i<=end_idx; ++i){
std::cout << solution[i] << " ";
if (i % 10 == 9){
std::cout << std::endl;
}
}
std::cout << std::endl;
}

void print_solution_length(void)
{
double length = 0;
for(int i=0; i<nodes_num; ++i){
length = length + get_distance(solution[i], solution[i+1]);
}
std::cout << "length:" << length << std::endl;
}

#endif
84 changes: 84 additions & 0 deletions ml4co_kit/algorithm/tsp/decoder/c_tsp_mcts/2opt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#ifndef OPT_H
#define OPT_H

#include "tsp.h"


// Evaluate the delta after applying a 2-opt move (delta >0 indicates an improving solution)
int get_2opt_delta(int city_1, int city_2)
{
if(check_if_two_city_same_or_adjacent(city_1, city_2)==true)
return -INF;

int next_city_1 = all_node[city_1].next_city;
int next_city_2 = all_node[city_2].next_city;

int delta = get_distance(city_1, next_city_1) + get_distance(city_2, next_city_2)
- get_distance(city_1, city_2) - get_distance(next_city_1, next_city_2);

// Update the chosen_times[][] and total_simulation_times which are used in MCTS
chosen_times[city_1][city_2] ++;
chosen_times[city_2][city_1] ++;
chosen_times[next_city_1][next_city_2] ++;
chosen_times[next_city_2][next_city_1] ++;
total_simulation_times++;

return delta;
}

// Apply a chosen 2-opt move
void apply_2opt_move(int city_1,int city_2)
{
int before_distance = get_solution_total_distance();
int delta = get_2opt_delta(city_1, city_2);

int next_city_1=all_node[city_1].next_city;
int next_city_2=all_node[city_2].next_city;

reverse_sub_path(next_city_1,city_2);
all_node[city_1].next_city=city_2;
all_node[city_2].pre_city=city_1;
all_node[next_city_1].next_city=next_city_2;
all_node[next_city_2].pre_city=next_city_1;

// Update the values of matrix weight[][] by back propagation, which would be used in MCTS
double increase_rate = beta*(pow(2.718, (double)(delta) / (double)(before_distance)) - 1);

weight[city_1][city_2] += increase_rate;
weight[city_2][city_1] += increase_rate;
weight[next_city_1][next_city_2] += increase_rate;
weight[next_city_2][next_city_1] += increase_rate;
}


bool improve_by_2opt_move()
{
bool if_improved=false;
for(int i=0;i<city_num;i++){
for(int j=0; j<candidate_num[i]; j++){
int candidate_city = candidate[i][j];
if(get_2opt_delta(i, candidate_city) > 0){
apply_2opt_move(i, candidate_city);
if_improved=true;
break;
}
}
}
return if_improved;
}

// Iteratively apply an improving 2-opt move until no improvement is possible
void local_search_by_2opt_move()
{
int iter = 0;
while(improve_by_2opt_move() == true && iter <= max_iterations_2opt){iter = iter + 1;}
int cur_solution_total_distance = get_solution_total_distance();
if(cur_solution_total_distance < best_distance)
{
// Store the information of the best found solution to Struct_Node *Best_all_node
best_distance = cur_solution_total_distance;
store_best_solution();
}
}

#endif
Loading

0 comments on commit da2fa9b

Please sign in to comment.