tsp-fast-solver-codingwizard34 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tsp_fast_solver_codingwizard34-0.1.0/PKG-INFO +179 -0
- tsp_fast_solver_codingwizard34-0.1.0/README.md +166 -0
- tsp_fast_solver_codingwizard34-0.1.0/pyproject.toml +20 -0
- tsp_fast_solver_codingwizard34-0.1.0/setup.cfg +10 -0
- tsp_fast_solver_codingwizard34-0.1.0/setup.py +50 -0
- tsp_fast_solver_codingwizard34-0.1.0/tests/test_tsp.py +83 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver/__init__.py +15 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver/_tsp_cython.cpp +8971 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver/_tsp_cython.pxd +5 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver/_tsp_cython.pyx +30 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver/c_tsp.pxd +5 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver/python_solver.py +33 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver/tsp.cpp +43 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver/tsp.h +16 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver_codingwizard34.egg-info/PKG-INFO +179 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver_codingwizard34.egg-info/SOURCES.txt +17 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver_codingwizard34.egg-info/dependency_links.txt +1 -0
- tsp_fast_solver_codingwizard34-0.1.0/tsp_fast_solver_codingwizard34.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tsp-fast-solver-codingwizard34
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A blazing fast C++ TSP solver wrapped in Cython
|
|
5
|
+
Author-email: CodingWizard34 <developer@example.com>
|
|
6
|
+
Keywords: tsp,graph-algorithms,cython,cplusplus,combinatorial-optimization
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Programming Language :: C++
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
11
|
+
Requires-Python: >=3.8
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# tsp-fast-solver-codingwizard34: Graph Algorithms in Production (TSP)
|
|
15
|
+
|
|
16
|
+
A high-performance implementation of the Traveling Salesperson Problem (TSP) brute-force solver comparing pure Python against native C++ wrapped with Cython.
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
The Traveling Salesperson Problem (TSP) is an NP-hard combinatorial graph problem: given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city exactly once and returns to the origin city?
|
|
21
|
+
|
|
22
|
+
Because the number of Hamiltonian cycles scales factorially:
|
|
23
|
+
$$\text{Possible Routes} = (N - 1)!$$
|
|
24
|
+
a pure Python search quickly slows down due to interpreter overhead and dynamic type checking. By offloading the permutation traversal to native C++ using `std::next_permutation` and bridging it with a Cython C-extension, we achieve up to **~90x–100x speedup**.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Architecture & Project Structure
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
tsp-fast-solver/
|
|
32
|
+
├── pyproject.toml # Build system metadata (PEP 517/518)
|
|
33
|
+
├── setup.py # Setuptools & Cython C++ build configuration
|
|
34
|
+
├── benchmark.py # Benchmarking script comparing both solvers
|
|
35
|
+
├── README.md # Project documentation and benchmarks
|
|
36
|
+
├── .gitignore # Excludes compiled binaries (.pyd, .so, build/)
|
|
37
|
+
├── tests/
|
|
38
|
+
│ └── test_tsp.py # Comprehensive unit tests (correctness & edge cases)
|
|
39
|
+
└── tsp_fast_solver/
|
|
40
|
+
├── __init__.py # Package exports (tsp_python, tsp_cython)
|
|
41
|
+
├── python_solver.py # Pure Python solver using itertools.permutations
|
|
42
|
+
├── tsp.h # C++ header declaring tsp_cpp
|
|
43
|
+
├── tsp.cpp # C++ native solver using std::next_permutation
|
|
44
|
+
├── c_tsp.pxd # Cython C++ header declaration
|
|
45
|
+
└── _tsp_cython.pyx # Cython wrapper bridging Python 2D lists to std::vector<int>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Components
|
|
49
|
+
|
|
50
|
+
1. **Pure Python Solver (`tsp_python`)**:
|
|
51
|
+
- Uses Python's `itertools.permutations` over nodes $\{1, \dots, N-1\}$.
|
|
52
|
+
- Evaluates $(N-1)!$ possible paths starting and ending at node 0.
|
|
53
|
+
|
|
54
|
+
2. **Native C++ Solver (`tsp_cpp`)**:
|
|
55
|
+
- Implemented in `tsp.h` and `tsp.cpp`.
|
|
56
|
+
- Uses `std::next_permutation` on a flat `std::vector<int>` distance matrix representation with contiguous memory layout and pointer arithmetic.
|
|
57
|
+
|
|
58
|
+
3. **Cython Wrapper (`tsp_cython`)**:
|
|
59
|
+
- Defined across `c_tsp.pxd` and `_tsp_cython.pyx`.
|
|
60
|
+
- Validates that the input is a square $N \times N$ matrix.
|
|
61
|
+
- Converts the Python list-of-lists into a 1D `std::vector<int>`, delegates to `tsp_cpp`, and returns the optimal cost.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Benchmark Results
|
|
66
|
+
|
|
67
|
+
Benchmarked on **Python 3.14 (x86_64 Windows)** using `benchmark.py` with reproducible random symmetric distance matrices:
|
|
68
|
+
|
|
69
|
+
| Graph Size (Nodes) | Possible Routes $(N-1)!$ | Pure Python Time (s) | Cython + C++ Time (s) | Speedup Delta | Deliverable Expected Time |
|
|
70
|
+
|:------------------:|:------------------------:|:--------------------:|:---------------------:|:-------------:|:-------------------------:|
|
|
71
|
+
| **$N = 8$** | 5,040 | 0.0026 s | 0.00004 s | **65.2x** | Python < 0.1s / Instant |
|
|
72
|
+
| **$N = 10$** | 362,880 | 0.2208 s | 0.0022 s | **98.5x** | Python ~1–2s / < 0.05s |
|
|
73
|
+
| **$N = 11$** | 3,628,800 | 3.2364 s | 0.0359 s | **90.2x** | Python ~15–30s / ~ 0.5s |
|
|
74
|
+
|
|
75
|
+
*Note: The native C++ implementation solves 3.6+ million permutations in just ~36 milliseconds.*
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Quick Start & Usage
|
|
80
|
+
|
|
81
|
+
### 1. Installation
|
|
82
|
+
|
|
83
|
+
#### From Source (Local Development)
|
|
84
|
+
```bash
|
|
85
|
+
# Clone the repository
|
|
86
|
+
git clone https://github.com/CodingWizard34/tsp-solver.git
|
|
87
|
+
cd tsp-solver
|
|
88
|
+
|
|
89
|
+
# Build extension in-place
|
|
90
|
+
python setup.py build_ext --inplace
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Via pip
|
|
94
|
+
```bash
|
|
95
|
+
pip install .
|
|
96
|
+
# Or once published:
|
|
97
|
+
pip install tsp-fast-solver-codingwizard34
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 2. Python API
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from tsp_fast_solver import tsp_python, tsp_cython
|
|
104
|
+
|
|
105
|
+
# Define an N x N distance matrix (symmetric or asymmetric)
|
|
106
|
+
distance_matrix = [
|
|
107
|
+
[0, 10, 15, 20],
|
|
108
|
+
[10, 0, 35, 25],
|
|
109
|
+
[15, 35, 0, 30],
|
|
110
|
+
[20, 25, 30, 0]
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
# Run pure Python solver
|
|
114
|
+
py_cost = tsp_python(distance_matrix)
|
|
115
|
+
print("Pure Python optimal cost:", py_cost) # Output: 80
|
|
116
|
+
|
|
117
|
+
# Run compiled Cython / C++ solver
|
|
118
|
+
cy_cost = tsp_cython(distance_matrix)
|
|
119
|
+
print("Cython / C++ optimal cost:", cy_cost) # Output: 80
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 3. Running Tests
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
python -m unittest discover -s tests -v
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 4. Running Benchmarks
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
python benchmark.py
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Packaging and Publishing to PyPI
|
|
137
|
+
|
|
138
|
+
### 1. Build Source Distribution (sdist) and Wheel
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
# Install the build tool
|
|
142
|
+
python -m pip install --upgrade build
|
|
143
|
+
|
|
144
|
+
# Generate distributions
|
|
145
|
+
python -m build --sdist
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
The generated `.tar.gz` archive in `dist/` contains all C++ sources, headers, and Cython `.pyx`/`.pxd` files ready for cross-platform compilation upon `pip install`.
|
|
149
|
+
|
|
150
|
+
### 2. Upload to PyPI with Twine
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
# Install Twine
|
|
154
|
+
python -m pip install --upgrade twine
|
|
155
|
+
|
|
156
|
+
# Upload to TestPyPI (recommended first):
|
|
157
|
+
python -m twine upload --repository testpypi dist/*
|
|
158
|
+
|
|
159
|
+
# Upload to production PyPI:
|
|
160
|
+
python -m twine upload dist/*
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
When prompted:
|
|
164
|
+
- **Username**: `__token__`
|
|
165
|
+
- **Password**: `<your-pypi-api-token>`
|
|
166
|
+
|
|
167
|
+
### 3. Verifying Installation
|
|
168
|
+
|
|
169
|
+
In a clean virtual environment:
|
|
170
|
+
```bash
|
|
171
|
+
pip install tsp-fast-solver-codingwizard34
|
|
172
|
+
python -c "import tsp_fast_solver; print('Success! tsp-fast-solver loaded version:', tsp_fast_solver.__version__)"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT License.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# tsp-fast-solver-codingwizard34: Graph Algorithms in Production (TSP)
|
|
2
|
+
|
|
3
|
+
A high-performance implementation of the Traveling Salesperson Problem (TSP) brute-force solver comparing pure Python against native C++ wrapped with Cython.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The Traveling Salesperson Problem (TSP) is an NP-hard combinatorial graph problem: given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city exactly once and returns to the origin city?
|
|
8
|
+
|
|
9
|
+
Because the number of Hamiltonian cycles scales factorially:
|
|
10
|
+
$$\text{Possible Routes} = (N - 1)!$$
|
|
11
|
+
a pure Python search quickly slows down due to interpreter overhead and dynamic type checking. By offloading the permutation traversal to native C++ using `std::next_permutation` and bridging it with a Cython C-extension, we achieve up to **~90x–100x speedup**.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Architecture & Project Structure
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
tsp-fast-solver/
|
|
19
|
+
├── pyproject.toml # Build system metadata (PEP 517/518)
|
|
20
|
+
├── setup.py # Setuptools & Cython C++ build configuration
|
|
21
|
+
├── benchmark.py # Benchmarking script comparing both solvers
|
|
22
|
+
├── README.md # Project documentation and benchmarks
|
|
23
|
+
├── .gitignore # Excludes compiled binaries (.pyd, .so, build/)
|
|
24
|
+
├── tests/
|
|
25
|
+
│ └── test_tsp.py # Comprehensive unit tests (correctness & edge cases)
|
|
26
|
+
└── tsp_fast_solver/
|
|
27
|
+
├── __init__.py # Package exports (tsp_python, tsp_cython)
|
|
28
|
+
├── python_solver.py # Pure Python solver using itertools.permutations
|
|
29
|
+
├── tsp.h # C++ header declaring tsp_cpp
|
|
30
|
+
├── tsp.cpp # C++ native solver using std::next_permutation
|
|
31
|
+
├── c_tsp.pxd # Cython C++ header declaration
|
|
32
|
+
└── _tsp_cython.pyx # Cython wrapper bridging Python 2D lists to std::vector<int>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Components
|
|
36
|
+
|
|
37
|
+
1. **Pure Python Solver (`tsp_python`)**:
|
|
38
|
+
- Uses Python's `itertools.permutations` over nodes $\{1, \dots, N-1\}$.
|
|
39
|
+
- Evaluates $(N-1)!$ possible paths starting and ending at node 0.
|
|
40
|
+
|
|
41
|
+
2. **Native C++ Solver (`tsp_cpp`)**:
|
|
42
|
+
- Implemented in `tsp.h` and `tsp.cpp`.
|
|
43
|
+
- Uses `std::next_permutation` on a flat `std::vector<int>` distance matrix representation with contiguous memory layout and pointer arithmetic.
|
|
44
|
+
|
|
45
|
+
3. **Cython Wrapper (`tsp_cython`)**:
|
|
46
|
+
- Defined across `c_tsp.pxd` and `_tsp_cython.pyx`.
|
|
47
|
+
- Validates that the input is a square $N \times N$ matrix.
|
|
48
|
+
- Converts the Python list-of-lists into a 1D `std::vector<int>`, delegates to `tsp_cpp`, and returns the optimal cost.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Benchmark Results
|
|
53
|
+
|
|
54
|
+
Benchmarked on **Python 3.14 (x86_64 Windows)** using `benchmark.py` with reproducible random symmetric distance matrices:
|
|
55
|
+
|
|
56
|
+
| Graph Size (Nodes) | Possible Routes $(N-1)!$ | Pure Python Time (s) | Cython + C++ Time (s) | Speedup Delta | Deliverable Expected Time |
|
|
57
|
+
|:------------------:|:------------------------:|:--------------------:|:---------------------:|:-------------:|:-------------------------:|
|
|
58
|
+
| **$N = 8$** | 5,040 | 0.0026 s | 0.00004 s | **65.2x** | Python < 0.1s / Instant |
|
|
59
|
+
| **$N = 10$** | 362,880 | 0.2208 s | 0.0022 s | **98.5x** | Python ~1–2s / < 0.05s |
|
|
60
|
+
| **$N = 11$** | 3,628,800 | 3.2364 s | 0.0359 s | **90.2x** | Python ~15–30s / ~ 0.5s |
|
|
61
|
+
|
|
62
|
+
*Note: The native C++ implementation solves 3.6+ million permutations in just ~36 milliseconds.*
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Quick Start & Usage
|
|
67
|
+
|
|
68
|
+
### 1. Installation
|
|
69
|
+
|
|
70
|
+
#### From Source (Local Development)
|
|
71
|
+
```bash
|
|
72
|
+
# Clone the repository
|
|
73
|
+
git clone https://github.com/CodingWizard34/tsp-solver.git
|
|
74
|
+
cd tsp-solver
|
|
75
|
+
|
|
76
|
+
# Build extension in-place
|
|
77
|
+
python setup.py build_ext --inplace
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### Via pip
|
|
81
|
+
```bash
|
|
82
|
+
pip install .
|
|
83
|
+
# Or once published:
|
|
84
|
+
pip install tsp-fast-solver-codingwizard34
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 2. Python API
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from tsp_fast_solver import tsp_python, tsp_cython
|
|
91
|
+
|
|
92
|
+
# Define an N x N distance matrix (symmetric or asymmetric)
|
|
93
|
+
distance_matrix = [
|
|
94
|
+
[0, 10, 15, 20],
|
|
95
|
+
[10, 0, 35, 25],
|
|
96
|
+
[15, 35, 0, 30],
|
|
97
|
+
[20, 25, 30, 0]
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
# Run pure Python solver
|
|
101
|
+
py_cost = tsp_python(distance_matrix)
|
|
102
|
+
print("Pure Python optimal cost:", py_cost) # Output: 80
|
|
103
|
+
|
|
104
|
+
# Run compiled Cython / C++ solver
|
|
105
|
+
cy_cost = tsp_cython(distance_matrix)
|
|
106
|
+
print("Cython / C++ optimal cost:", cy_cost) # Output: 80
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 3. Running Tests
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
python -m unittest discover -s tests -v
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 4. Running Benchmarks
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
python benchmark.py
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Packaging and Publishing to PyPI
|
|
124
|
+
|
|
125
|
+
### 1. Build Source Distribution (sdist) and Wheel
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Install the build tool
|
|
129
|
+
python -m pip install --upgrade build
|
|
130
|
+
|
|
131
|
+
# Generate distributions
|
|
132
|
+
python -m build --sdist
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The generated `.tar.gz` archive in `dist/` contains all C++ sources, headers, and Cython `.pyx`/`.pxd` files ready for cross-platform compilation upon `pip install`.
|
|
136
|
+
|
|
137
|
+
### 2. Upload to PyPI with Twine
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Install Twine
|
|
141
|
+
python -m pip install --upgrade twine
|
|
142
|
+
|
|
143
|
+
# Upload to TestPyPI (recommended first):
|
|
144
|
+
python -m twine upload --repository testpypi dist/*
|
|
145
|
+
|
|
146
|
+
# Upload to production PyPI:
|
|
147
|
+
python -m twine upload dist/*
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
When prompted:
|
|
151
|
+
- **Username**: `__token__`
|
|
152
|
+
- **Password**: `<your-pypi-api-token>`
|
|
153
|
+
|
|
154
|
+
### 3. Verifying Installation
|
|
155
|
+
|
|
156
|
+
In a clean virtual environment:
|
|
157
|
+
```bash
|
|
158
|
+
pip install tsp-fast-solver-codingwizard34
|
|
159
|
+
python -c "import tsp_fast_solver; print('Success! tsp-fast-solver loaded version:', tsp_fast_solver.__version__)"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT License.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "cython"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tsp-fast-solver-codingwizard34"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "CodingWizard34", email = "developer@example.com" }
|
|
10
|
+
]
|
|
11
|
+
description = "A blazing fast C++ TSP solver wrapped in Cython"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.8"
|
|
14
|
+
keywords = ["tsp", "graph-algorithms", "cython", "cplusplus", "combinatorial-optimization"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: C++",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Topic :: Scientific/Engineering :: Mathematics",
|
|
20
|
+
]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
from setuptools import setup, find_packages, Extension
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
from Cython.Build import cythonize
|
|
7
|
+
USE_CYTHON = True
|
|
8
|
+
except ImportError:
|
|
9
|
+
USE_CYTHON = False
|
|
10
|
+
|
|
11
|
+
source_ext = ".pyx" if USE_CYTHON else ".cpp"
|
|
12
|
+
|
|
13
|
+
extra_compile_args = []
|
|
14
|
+
extra_link_args = []
|
|
15
|
+
|
|
16
|
+
if sys.platform != "win32":
|
|
17
|
+
extra_compile_args.extend(["-O3", "-std=c++11"])
|
|
18
|
+
|
|
19
|
+
pkg_dir = os.path.abspath("tsp_fast_solver")
|
|
20
|
+
|
|
21
|
+
extensions = [
|
|
22
|
+
Extension(
|
|
23
|
+
name="tsp_fast_solver._tsp_cython",
|
|
24
|
+
sources=[
|
|
25
|
+
os.path.join("tsp_fast_solver", f"_tsp_cython{source_ext}"),
|
|
26
|
+
os.path.join("tsp_fast_solver", "tsp.cpp"),
|
|
27
|
+
],
|
|
28
|
+
include_dirs=[pkg_dir],
|
|
29
|
+
language="c++",
|
|
30
|
+
extra_compile_args=extra_compile_args,
|
|
31
|
+
extra_link_args=extra_link_args,
|
|
32
|
+
),
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
if USE_CYTHON:
|
|
36
|
+
ext_modules = cythonize(
|
|
37
|
+
extensions,
|
|
38
|
+
include_path=[pkg_dir, "."],
|
|
39
|
+
compiler_directives={"language_level": "3"},
|
|
40
|
+
)
|
|
41
|
+
else:
|
|
42
|
+
ext_modules = extensions
|
|
43
|
+
|
|
44
|
+
setup(
|
|
45
|
+
packages=find_packages(),
|
|
46
|
+
ext_modules=ext_modules,
|
|
47
|
+
package_data={
|
|
48
|
+
"tsp_fast_solver": ["*.h", "*.pxd", "*.pyx", "*.cpp"],
|
|
49
|
+
},
|
|
50
|
+
)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
import random
|
|
3
|
+
from tsp_fast_solver.python_solver import tsp_python
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
from tsp_fast_solver._tsp_cython import tsp_cython
|
|
7
|
+
CYTHON_AVAILABLE = True
|
|
8
|
+
except ImportError:
|
|
9
|
+
CYTHON_AVAILABLE = False
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def generate_random_matrix(n, seed=None):
|
|
13
|
+
if seed is not None:
|
|
14
|
+
random.seed(seed)
|
|
15
|
+
matrix = [[0] * n for _ in range(n)]
|
|
16
|
+
for i in range(n):
|
|
17
|
+
for j in range(i + 1, n):
|
|
18
|
+
d = random.randint(5, 100)
|
|
19
|
+
matrix[i][j] = d
|
|
20
|
+
matrix[j][i] = d
|
|
21
|
+
return matrix
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestTSPSolvers(unittest.TestCase):
|
|
25
|
+
|
|
26
|
+
def test_trivial_cases(self):
|
|
27
|
+
self.assertEqual(tsp_python([]), 0)
|
|
28
|
+
self.assertEqual(tsp_python([[0]]), 0)
|
|
29
|
+
|
|
30
|
+
if CYTHON_AVAILABLE:
|
|
31
|
+
self.assertEqual(tsp_cython([]), 0)
|
|
32
|
+
self.assertEqual(tsp_cython([[0]]), 0)
|
|
33
|
+
|
|
34
|
+
def test_two_cities(self):
|
|
35
|
+
mat = [
|
|
36
|
+
[0, 15],
|
|
37
|
+
[15, 0]
|
|
38
|
+
]
|
|
39
|
+
self.assertEqual(tsp_python(mat), 30)
|
|
40
|
+
if CYTHON_AVAILABLE:
|
|
41
|
+
self.assertEqual(tsp_cython(mat), 30)
|
|
42
|
+
|
|
43
|
+
def test_three_cities(self):
|
|
44
|
+
mat = [
|
|
45
|
+
[0, 10, 20],
|
|
46
|
+
[10, 0, 15],
|
|
47
|
+
[20, 15, 0]
|
|
48
|
+
]
|
|
49
|
+
# Only one distinct cycle (both directions have same length): 0 -> 1 -> 2 -> 0 => 10 + 15 + 20 = 45
|
|
50
|
+
self.assertEqual(tsp_python(mat), 45)
|
|
51
|
+
if CYTHON_AVAILABLE:
|
|
52
|
+
self.assertEqual(tsp_cython(mat), 45)
|
|
53
|
+
|
|
54
|
+
def test_four_cities_known(self):
|
|
55
|
+
mat = [
|
|
56
|
+
[0, 10, 15, 20],
|
|
57
|
+
[10, 0, 35, 25],
|
|
58
|
+
[15, 35, 0, 30],
|
|
59
|
+
[20, 25, 30, 0]
|
|
60
|
+
]
|
|
61
|
+
# Best route: 0 -> 1 -> 3 -> 2 -> 0 => 10 + 25 + 30 + 15 = 80
|
|
62
|
+
self.assertEqual(tsp_python(mat), 80)
|
|
63
|
+
if CYTHON_AVAILABLE:
|
|
64
|
+
self.assertEqual(tsp_cython(mat), 80)
|
|
65
|
+
|
|
66
|
+
def test_python_and_cython_equivalence(self):
|
|
67
|
+
if not CYTHON_AVAILABLE:
|
|
68
|
+
self.skipTest("Cython extension not built yet")
|
|
69
|
+
|
|
70
|
+
for size in [4, 5, 6, 7]:
|
|
71
|
+
mat = generate_random_matrix(size, seed=100 + size)
|
|
72
|
+
py_cost = tsp_python(mat)
|
|
73
|
+
cy_cost = tsp_cython(mat)
|
|
74
|
+
self.assertEqual(py_cost, cy_cost, f"Mismatch on size {size}: Python={py_cost}, Cython={cy_cost}")
|
|
75
|
+
|
|
76
|
+
def test_invalid_dimension(self):
|
|
77
|
+
if CYTHON_AVAILABLE:
|
|
78
|
+
with self.assertRaises(ValueError):
|
|
79
|
+
tsp_cython([[0, 10], [10]])
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
if __name__ == "__main__":
|
|
83
|
+
unittest.main()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""
|
|
2
|
+
tsp-fast-solver: High-performance Traveling Salesperson Problem (TSP) solver
|
|
3
|
+
comparing pure Python against Cython-wrapped C++ std::next_permutation.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .python_solver import tsp_python
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from ._tsp_cython import tsp_cython
|
|
10
|
+
except ImportError:
|
|
11
|
+
# Fallback for environments where the compiled C-extension has not been built yet
|
|
12
|
+
tsp_cython = None
|
|
13
|
+
|
|
14
|
+
__version__ = "0.1.0"
|
|
15
|
+
__all__ = ["tsp_python", "tsp_cython"]
|