Skip to content

Commit

Permalink
Move string logic to Python instead of C API
Browse files Browse the repository at this point in the history
  • Loading branch information
fikisipi committed Apr 19, 2023
1 parent b981498 commit fbb29ea
Show file tree
Hide file tree
Showing 17 changed files with 478 additions and 204 deletions.
19 changes: 19 additions & 0 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash


SCR=$(cat << EOF
import re
import subprocess
repo = subprocess.check_output("git rev-parse --show-toplevel", shell=True).decode('utf8').strip()
with open(f"{repo}/README.md", "r") as f:
md = f.read()
with open(f"{repo}/setup.py", "r") as f:
content = f.read()
with open(f"{repo}/setup.py", "w") as f:
f.write(re.sub(r"long_description=.*? url", 'long_description="""' + md + '""",\n url', content, flags=re.DOTALL))
subprocess.check_output(f"git add {repo}/setup.py", shell=True)
EOF
)

python3 -c "$SCR"
7 changes: 0 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
cmake_minimum_required(VERSION 3.11.0)
project(elkai)

# set(CMAKE_POSITION_INDEPENDENT_CODE ON)

find_package(PythonExtensions REQUIRED)

include_directories(${CMAKE_SOURCE_DIR}/LKH-3.0.8/SRC/INCLUDE)
file(GLOB LKH_SRC "LKH-3.0.8/SRC/*.c")

# add_library(LKH ${LKH_SRC})
# target_compile_definitions(LKH PRIVATE TWO_LEVEL_TREE)
# target_compile_options(LKH PRIVATE -flto -fcommon)

add_library(_elkai MODULE elkai/_elkai.c ${LKH_SRC})
python_extension_module(_elkai)
# target_link_libraries(_elkai LKH)

install(TARGETS _elkai LIBRARY DESTINATION elkai)
11 changes: 0 additions & 11 deletions LKH-3.0.8/SRC/INCLUDE/LKH.h
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
#ifndef _LKH_H
#define _LKH_H

#define DEFAULT_PARAMETERS "RUNS = 10\nTRACE_LEVEL = 0\nPROBLEM_FILE = :empty:\n"
#define DEFAULT_PROBLEM "TYPE : ATSP\n\
DIMENSION : 3\n\
EDGE_WEIGHT_TYPE: EXPLICIT\n\
EDGE_WEIGHT_FORMAT: FULL_MATRIX\n\
EDGE_WEIGHT_SECTION\n\
0 4 0\n\
0 0 5\n\
0 0 0\n\
"

/*
* This header is used by almost all functions of the program. It defines
* macros and specifies data structures and function prototypes.
Expand Down
178 changes: 150 additions & 28 deletions LKH-3.0.8/SRC/LKHmain.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ static void ReadableTourClear() {
ReadableTourAllocated = 100;
if(ReadableTour != 0) {
free(ReadableTour);
ReadableTour = 0;
}
}

Expand Down Expand Up @@ -60,20 +61,160 @@ void TheTour(int *Tour, GainType Cost)
}
}

extern char *ReadLineBuf;

#define GB_STRING_IMPLEMENTATION
#include "gb_string.h"

extern void ClearLines();
extern void WriteLine(gbString str);

void ElkaiSolveProblem(gbString params, gbString problem, int *tourSize, int **tourPtr) {
ClearLines();
WriteLine(params);
ReadParameters();
GainType Cost, OldOptimum;
double Time, LastTime;
StartTime = LastTime = GetTime();
MaxMatrixDimension = 20000;
MergeWithTour =
Recombination == GPX2 ? MergeWithTourGPX2 :
Recombination == CLARIST ? MergeWithTourCLARIST :
MergeWithTourIPT;

WriteLine(problem);

ReadProblem();
AllocateStructures();
CreateCandidateSet();
InitializeStatistics();

if (Norm != 0 || Penalty) {
Norm = 9999;
BestCost = PLUS_INFINITY;
BestPenalty = CurrentPenalty = PLUS_INFINITY;
} else {
/* The ascent has solved the problem! */
Optimum = BestCost = (GainType) LowerBound;
UpdateStatistics(Optimum, GetTime() - LastTime);
RecordBetterTour();
RecordBestTour();
CurrentPenalty = PLUS_INFINITY;
BestPenalty = CurrentPenalty = Penalty ? Penalty() : 0;
TheTour(BestTour, BestCost);
Runs = 0;
}

/* Find a specified number (Runs) of local optima */

for (Run = 1; Run <= Runs; Run++) {
LastTime = GetTime();
if (LastTime - StartTime >= TotalTimeLimit) {
if (TraceLevel >= 1)
printff("*** Time limit exceeded ***\n");
Run--;
break;
}
Cost = FindTour(); /* using the Lin-Kernighan heuristic */
if (MaxPopulationSize > 1 && !TSPTW_Makespan) {
/* Genetic algorithm */
int i;
for (i = 0; i < PopulationSize; i++) {
Cost = MergeTourWithIndividual(i);
}
if (!HasFitness(CurrentPenalty, Cost)) {
if (PopulationSize < MaxPopulationSize) {
AddToPopulation(CurrentPenalty, Cost);
if (TraceLevel >= 1)
PrintPopulation();
} else if (SmallerFitness(CurrentPenalty, Cost,
PopulationSize - 1)) {
i = ReplacementIndividual(CurrentPenalty, Cost);
ReplaceIndividualWithTour(i, CurrentPenalty, Cost);
if (TraceLevel >= 1)
PrintPopulation();
}
}
} else if (Run > 1 && !TSPTW_Makespan)
Cost = MergeTourWithBestTour();
if (CurrentPenalty < BestPenalty ||
(CurrentPenalty == BestPenalty && Cost < BestCost)) {
BestPenalty = CurrentPenalty;
BestCost = Cost;
RecordBetterTour();
RecordBestTour();
TheTour(BestTour, BestCost);
}
OldOptimum = Optimum;
if (!Penalty ||
(MTSPObjective != MINMAX && MTSPObjective != MINMAX_SIZE)) {
if (CurrentPenalty == 0 && Cost < Optimum)
Optimum = Cost;
} else if (CurrentPenalty < Optimum)
Optimum = CurrentPenalty;
if (Optimum < OldOptimum) {
if (FirstNode->InputSuc) {
Node *N = FirstNode;
while ((N = N->InputSuc = N->Suc) != FirstNode);
}
}
Time = fabs(GetTime() - LastTime);
UpdateStatistics(Cost, Time);
if (StopAtOptimum && MaxPopulationSize >= 1) {
if (ProblemType != CCVRP && ProblemType != TRP &&
ProblemType != MLP &&
MTSPObjective != MINMAX &&
MTSPObjective != MINMAX_SIZE ?
CurrentPenalty == 0 && Cost == Optimum :
CurrentPenalty == Optimum) {
Runs = Run;
break;
}
}
if (PopulationSize >= 2 &&
(PopulationSize == MaxPopulationSize ||
Run >= 2 * MaxPopulationSize) && Run < Runs) {
Node *N;
int Parent1, Parent2;
Parent1 = LinearSelection(PopulationSize, 1.25);
do
Parent2 = LinearSelection(PopulationSize, 1.25);
while (Parent2 == Parent1);
ApplyCrossover(Parent1, Parent2);
N = FirstNode;
do {
if (ProblemType != HCP && ProblemType != HPP) {
int d = C(N, N->Suc);
AddCandidate(N, N->Suc, d, INT_MAX);
AddCandidate(N->Suc, N, d, INT_MAX);
}
N = N->InitialSuc = N->Suc;
} while (N != FirstNode);
}
SRandom(++Seed);
}

*tourSize = ReadableTourSize;

if(tourPtr != 0) {
*tourPtr = ReadableTour;
}

// if(tour != 0) {
// for(int M = 0; M < ReadableTourSize; M++) {
// tour[M] = ReadableTour[M];
// }
// }
}

int ElkaiSolveATSP(int dimension, float *weights, int *tour, int runs)
{
GainType Cost, OldOptimum;
double Time, LastTime;
ClearLines();
WriteLine(gb_make_string("TRACE_LEVEL = 0\nPROBLEM_FILE = :stdin:\n"));

ReadLineBuf = gb_make_string("TRACE_LEVEL = 0\nPROBLEM_FILE = :empty:\n");
char runsStr[100];
sprintf(runsStr, "RUNS = %d\n", runs);
ReadLineBuf = gb_append_cstring(ReadLineBuf, runsStr);
WriteLine(gb_make_string(runsStr));

ReadParameters();

Expand All @@ -83,42 +224,23 @@ int ElkaiSolveATSP(int dimension, float *weights, int *tour, int runs)
Recombination == GPX2 ? MergeWithTourGPX2 :
Recombination == CLARIST ? MergeWithTourCLARIST :
MergeWithTourIPT;

ReadLineBuf = (char *) malloc(sizeof(char) * 1000);

char dimensionStr[100];
sprintf(dimensionStr, "DIMENSION : %d\n", dimension);
ReadLineBuf = gb_make_string("TYPE: ATSP\n");
ReadLineBuf = gb_append_cstring(ReadLineBuf, dimensionStr);
ReadLineBuf = gb_append_cstring(ReadLineBuf, "EDGE_WEIGHT_TYPE: EXPLICIT\nEDGE_WEIGHT_FORMAT: FULL_MATRIX\nEDGE_WEIGHT_SECTION\n");
WriteLine(gb_make_string("TYPE: ATSP\n"));
WriteLine(gb_make_string(dimensionStr));
WriteLine(gb_make_string("EDGE_WEIGHT_TYPE: EXPLICIT\nEDGE_WEIGHT_FORMAT: FULL_MATRIX\nEDGE_WEIGHT_SECTION\n"));

for(int y = 0; y < dimension; y++) {
for(int x = 0; x < dimension; x++) {
char weightStr[64];
sprintf(weightStr, "%f ", weights[y * dimension + x]);
ReadLineBuf = gb_append_cstring(ReadLineBuf, weightStr);
WriteLine(gb_make_string(weightStr));
}
ReadLineBuf = gb_append_cstring(ReadLineBuf, "\n");
WriteLine(gb_make_string("\n"));
}

ReadProblem();
if (SubproblemSize > 0) {
if (DelaunayPartitioning)
SolveDelaunaySubproblems();
else if (KarpPartitioning)
SolveKarpSubproblems();
else if (KCenterPartitioning)
SolveKCenterSubproblems();
else if (KMeansPartitioning)
SolveKMeansSubproblems();
else if (RohePartitioning)
SolveRoheSubproblems();
else if (MoorePartitioning || SierpinskiPartitioning)
SolveSFCSubproblems();
else
SolveTourSegmentSubproblems();
return EXIT_SUCCESS;
}
AllocateStructures();
CreateCandidateSet();
InitializeStatistics();
Expand Down
45 changes: 37 additions & 8 deletions LKH-3.0.8/SRC/ReadLine.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,62 @@ static int EndOfLine(FILE * InputFile, int c)
return EOL;
}

char *ReadLineBuf = ":empty:";
char *ReadLineBuf = 0;
int ReadLinePtr = 0;
#include "gb_string.h"

void WriteLine(gbString str) {
if(ReadLineBuf == 0) {
ReadLineBuf = gb_make_string("");
}
ReadLineBuf = gb_append_string(ReadLineBuf, str);
}

void ClearLines() {
ReadLinePtr = 0;
if(ReadLineBuf != 0) {
gb_free_string(ReadLineBuf);
ReadLineBuf = 0;
}
}

double ReadNumber() {
if(ReadLinePtr == 0) return 0;
char *k = ReadLineBuf + ReadLinePtr;
double output = strtof(ReadLineBuf + ReadLinePtr, &k);
ReadLinePtr += k - (ReadLineBuf + ReadLinePtr);
return output;
}

char *ReadLine(FILE * InputFile)
{
if(InputFile == 0) {
if(ReadLineBuf[0] == '\0') {
if(ReadLineBuf[ReadLinePtr] == '\0') {
return 0;
}

gbString currentLine = gb_make_string("");

while(ReadLineBuf[0] != '\0') {
while(ReadLineBuf[ReadLinePtr] != '\0') {
char singleCh[2];
singleCh[0] = ReadLineBuf[0];
singleCh[0] = ReadLineBuf[ReadLinePtr];
singleCh[1] = '\0';

currentLine = gb_append_cstring(currentLine, singleCh);

ReadLineBuf++;
if(ReadLineBuf[0] == '\n') {
ReadLineBuf++;
ReadLinePtr++;
if(ReadLineBuf[ReadLinePtr] == '\n') {
ReadLinePtr++;
break;
}
}

return (char*)currentLine;
gbUsize lineSize = gb_string_length(currentLine);
char *L = malloc(lineSize + 1);
memcpy(L, currentLine, lineSize + 1);
gb_free_string(currentLine);

return L;
}

int i, c;
Expand Down
8 changes: 1 addition & 7 deletions LKH-3.0.8/SRC/ReadParameters.c
Original file line number Diff line number Diff line change
Expand Up @@ -485,8 +485,6 @@ static char *ReadYesOrNo(int *V);
#undef max
static size_t max(size_t a, size_t b);

extern char *ReadLineBuf;

void _Reset1();
void _Reset2();
void _Reset3();
Expand Down Expand Up @@ -612,9 +610,6 @@ void ReadParameters()
}
} else {
ParameterFile = 0;
if(!strcmp(ReadLineBuf, ":empty:")) {
ReadLineBuf = DEFAULT_PARAMETERS;
}
}
while ((Line = ReadLine(ParameterFile))) {
if (!(Keyword = strtok(Line, Delimiters)))
Expand Down Expand Up @@ -1202,9 +1197,8 @@ void ReadParameters()
DelaunayPure = 0;
if(ParameterFile != 0)
fclose(ParameterFile);
free(LastLine);
// free(LastLine);
LastLine = 0;
ReadLineBuf = ":empty:";
}

static char *GetFileName(char *Line)
Expand Down
Loading

0 comments on commit fbb29ea

Please sign in to comment.