cost-matrix 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.
- cost_matrix-0.1.0/PKG-INFO +72 -0
- cost_matrix-0.1.0/README.md +55 -0
- cost_matrix-0.1.0/cost_matrix/__init__.py +4 -0
- cost_matrix-0.1.0/cost_matrix/euclidean_matrix.py +5 -0
- cost_matrix-0.1.0/cost_matrix/manhattan_matrix.py +5 -0
- cost_matrix-0.1.0/cost_matrix/osrm_matrix.py +136 -0
- cost_matrix-0.1.0/cost_matrix/spherical_matrix.py +31 -0
- cost_matrix-0.1.0/pyproject.toml +33 -0
@@ -0,0 +1,72 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: cost-matrix
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: Designed to simplify the creation of cost matrices for optimization problems.
|
5
|
+
Author: Luan
|
6
|
+
Author-email: llvdmoraes@gmail.com
|
7
|
+
Requires-Python: >=3.9,<3.13
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: Programming Language :: Python :: 3.9
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
13
|
+
Requires-Dist: numpy (>=1.26.4,<2.0.0)
|
14
|
+
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
15
|
+
Description-Content-Type: text/markdown
|
16
|
+
|
17
|
+
# cost-matrix
|
18
|
+
|
19
|
+
`cost-matrix` is a Python package designed to simplify the creation of cost matrices for optimization problems. Whether you're dealing with distance calculations or travel durations, `cost-matrix` provides a robust set of tools to meet your needs.
|
20
|
+
|
21
|
+
This package is invaluable for anyone working on optimization problems, data analysis, or transportation planning. With its diverse range of distance calculation methods and integration with OSRM, it provides a comprehensive solution for generating cost matrices efficiently.
|
22
|
+
|
23
|
+
## Key Features:
|
24
|
+
- **Manhattan**: Compute distances based on orthogonal paths.
|
25
|
+
- **Euclidean**: Calculate straight-line distances in a Cartesian plane.
|
26
|
+
- **Spherical**: Calculate distances between geographical points considering the Earth's curvature.
|
27
|
+
- **OSRM**: Integrate with the Open Source Routing Machine (OSRM) to obtain travel duration or distance matrices.
|
28
|
+
|
29
|
+
## Installation
|
30
|
+
|
31
|
+
To install the `cost-matrix` package, you can use pip:
|
32
|
+
|
33
|
+
```sh
|
34
|
+
pip install cost-matrix
|
35
|
+
```
|
36
|
+
|
37
|
+
|
38
|
+
## Example Usage:
|
39
|
+
```python
|
40
|
+
import numpy as np
|
41
|
+
import cost_matrix
|
42
|
+
|
43
|
+
# Define source and destination coordinates (latitude, longitude)
|
44
|
+
sources = np.array([[37.7749, -122.4194], [34.0522, -118.2437]]) # San Francisco, Los Angeles
|
45
|
+
destinations = np.array([[40.7128, -74.0060], [51.5074, -0.1278]]) # New York, London
|
46
|
+
|
47
|
+
# Calculate Manhattan distance matrix
|
48
|
+
manhattan_matrix = cost_matrix.manhattan(sources, destinations)
|
49
|
+
print(manhattan_matrix)
|
50
|
+
|
51
|
+
# Calculate Euclidean distance matrix
|
52
|
+
euclidean_matrix = cost_matrix.euclidean(sources, destinations)
|
53
|
+
print(euclidean_matrix)
|
54
|
+
|
55
|
+
# Calculate Spherical distance matrix
|
56
|
+
spherical_matrix = cost_matrix.spherical(sources, destinations)
|
57
|
+
print(spherical_matrix)
|
58
|
+
|
59
|
+
# Calculate OSRM travel distances matrix
|
60
|
+
osrm_distance_matrix = cost_matrix.osrm(sources, destinations)
|
61
|
+
print(osrm_distance_matrix)
|
62
|
+
|
63
|
+
# Calculate OSRM travel durations matrix
|
64
|
+
osrm_duration_matrix = cost_matrix.osrm(
|
65
|
+
sources,
|
66
|
+
destinations,
|
67
|
+
cost_type="durations",
|
68
|
+
server_address="http://localhost:5000",
|
69
|
+
batch_size=250
|
70
|
+
)
|
71
|
+
print(osrm_duration_matrix)
|
72
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# cost-matrix
|
2
|
+
|
3
|
+
`cost-matrix` is a Python package designed to simplify the creation of cost matrices for optimization problems. Whether you're dealing with distance calculations or travel durations, `cost-matrix` provides a robust set of tools to meet your needs.
|
4
|
+
|
5
|
+
This package is invaluable for anyone working on optimization problems, data analysis, or transportation planning. With its diverse range of distance calculation methods and integration with OSRM, it provides a comprehensive solution for generating cost matrices efficiently.
|
6
|
+
|
7
|
+
## Key Features:
|
8
|
+
- **Manhattan**: Compute distances based on orthogonal paths.
|
9
|
+
- **Euclidean**: Calculate straight-line distances in a Cartesian plane.
|
10
|
+
- **Spherical**: Calculate distances between geographical points considering the Earth's curvature.
|
11
|
+
- **OSRM**: Integrate with the Open Source Routing Machine (OSRM) to obtain travel duration or distance matrices.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
To install the `cost-matrix` package, you can use pip:
|
16
|
+
|
17
|
+
```sh
|
18
|
+
pip install cost-matrix
|
19
|
+
```
|
20
|
+
|
21
|
+
|
22
|
+
## Example Usage:
|
23
|
+
```python
|
24
|
+
import numpy as np
|
25
|
+
import cost_matrix
|
26
|
+
|
27
|
+
# Define source and destination coordinates (latitude, longitude)
|
28
|
+
sources = np.array([[37.7749, -122.4194], [34.0522, -118.2437]]) # San Francisco, Los Angeles
|
29
|
+
destinations = np.array([[40.7128, -74.0060], [51.5074, -0.1278]]) # New York, London
|
30
|
+
|
31
|
+
# Calculate Manhattan distance matrix
|
32
|
+
manhattan_matrix = cost_matrix.manhattan(sources, destinations)
|
33
|
+
print(manhattan_matrix)
|
34
|
+
|
35
|
+
# Calculate Euclidean distance matrix
|
36
|
+
euclidean_matrix = cost_matrix.euclidean(sources, destinations)
|
37
|
+
print(euclidean_matrix)
|
38
|
+
|
39
|
+
# Calculate Spherical distance matrix
|
40
|
+
spherical_matrix = cost_matrix.spherical(sources, destinations)
|
41
|
+
print(spherical_matrix)
|
42
|
+
|
43
|
+
# Calculate OSRM travel distances matrix
|
44
|
+
osrm_distance_matrix = cost_matrix.osrm(sources, destinations)
|
45
|
+
print(osrm_distance_matrix)
|
46
|
+
|
47
|
+
# Calculate OSRM travel durations matrix
|
48
|
+
osrm_duration_matrix = cost_matrix.osrm(
|
49
|
+
sources,
|
50
|
+
destinations,
|
51
|
+
cost_type="durations",
|
52
|
+
server_address="http://localhost:5000",
|
53
|
+
batch_size=250
|
54
|
+
)
|
55
|
+
print(osrm_duration_matrix)
|
@@ -0,0 +1,136 @@
|
|
1
|
+
from math import ceil
|
2
|
+
|
3
|
+
import numpy as np
|
4
|
+
import requests
|
5
|
+
|
6
|
+
|
7
|
+
def osrm(
|
8
|
+
sources: np.ndarray,
|
9
|
+
destinations: np.ndarray,
|
10
|
+
server_address: str = "http://router.project-osrm.org",
|
11
|
+
batch_size: int = 150,
|
12
|
+
cost_type: str = "distances",
|
13
|
+
) -> np.ndarray:
|
14
|
+
"""Compute the OSRM cost matrix between sources and destinations"""
|
15
|
+
|
16
|
+
num_sources = sources.shape[0]
|
17
|
+
num_destinations = destinations.shape[0]
|
18
|
+
cost_matrix = np.zeros((num_sources, num_destinations))
|
19
|
+
|
20
|
+
num_batches_i = ceil(num_sources / batch_size)
|
21
|
+
num_batches_j = ceil(num_destinations / batch_size)
|
22
|
+
|
23
|
+
for i in range(num_batches_i):
|
24
|
+
start_i = i * batch_size
|
25
|
+
end_i = min((i + 1) * batch_size, num_sources)
|
26
|
+
|
27
|
+
for j in range(num_batches_j):
|
28
|
+
start_j = j * batch_size
|
29
|
+
end_j = min((j + 1) * batch_size, num_destinations)
|
30
|
+
sources_batch = sources[start_i:end_i]
|
31
|
+
destinations_batch = destinations[start_j:end_j]
|
32
|
+
|
33
|
+
cost_matrix[start_i:end_i, start_j:end_j] = (
|
34
|
+
_get_batch_osrm_distance(
|
35
|
+
sources_batch,
|
36
|
+
destinations_batch,
|
37
|
+
server_address,
|
38
|
+
cost_type=cost_type,
|
39
|
+
)
|
40
|
+
)
|
41
|
+
|
42
|
+
return cost_matrix
|
43
|
+
|
44
|
+
|
45
|
+
def _get_batch_osrm_distance(
|
46
|
+
sources_batch: np.ndarray,
|
47
|
+
destinations_batch: np.ndarray,
|
48
|
+
server_address: str,
|
49
|
+
cost_type: str,
|
50
|
+
):
|
51
|
+
"""Request the OSRM cost matrix for a given batch"""
|
52
|
+
|
53
|
+
url = _format_osrm_url(
|
54
|
+
sources_batch, destinations_batch, server_address, cost_type
|
55
|
+
)
|
56
|
+
resp = requests.get(url)
|
57
|
+
resp.raise_for_status()
|
58
|
+
|
59
|
+
return np.array(resp.json()[cost_type])
|
60
|
+
|
61
|
+
|
62
|
+
def _format_osrm_url(
|
63
|
+
sources_batch: np.ndarray,
|
64
|
+
destinations_batch: np.ndarray,
|
65
|
+
server_address: str,
|
66
|
+
cost_type: str,
|
67
|
+
) -> str:
|
68
|
+
"""Format OSRM url string with sources and destinations
|
69
|
+
|
70
|
+
Notes
|
71
|
+
-----
|
72
|
+
Consider the N sources in the form
|
73
|
+
(lat_src1, lgn_src1), (lat_src2, lgn_src2), ...
|
74
|
+
|
75
|
+
and the M destinations in the form
|
76
|
+
(lat_dest1, lgn_dest1), (lat_dest2, lgn_dest2), ...
|
77
|
+
|
78
|
+
This function converts these properties in a URL of the form
|
79
|
+
{OSRM_SERVER_ADDRESS}/table/v1/driving/
|
80
|
+
lng_src1,lat_src1;lng_src2,lat_src2;...;lng_srcN,lat_srcN;
|
81
|
+
lng_dest1,lat_dest1;lng_dest2,lat_dest2;...;lng_destM,lng_destM
|
82
|
+
?sources=0;1;...;N-1
|
83
|
+
&destinations=N;N+1;...;N+M-1
|
84
|
+
&annotations=distance
|
85
|
+
|
86
|
+
In the simpler case when sources == destinations, the URL is simplified to
|
87
|
+
{OSRM_SERVER_ADDRESS}/table/v1/driving/
|
88
|
+
lng_src1,lat_src1;lng_src2,lat_src2;...;lng_srcN,lat_srcN
|
89
|
+
?annotations=distance
|
90
|
+
|
91
|
+
Obs: Replace "distance" with "duration" if a time matrix is required
|
92
|
+
Obs2: The matrix type follows the singular form in the URL (e.g.,
|
93
|
+
"distance"), but the returned JSON follows the plural form (e.g.,
|
94
|
+
"distances"). Thus, we ignore the last letter of the input type
|
95
|
+
"""
|
96
|
+
|
97
|
+
url_cost_type = cost_type[:-1]
|
98
|
+
sources_coord = ";".join(
|
99
|
+
f"{source[1]},{source[0]}" for source in sources_batch
|
100
|
+
)
|
101
|
+
|
102
|
+
# If sources == destinations, return a simpler URL early. Notice it needs
|
103
|
+
# at least two points, otherwise OSRM complains
|
104
|
+
if (
|
105
|
+
np.array_equal(sources_batch, destinations_batch)
|
106
|
+
and sources_batch.shape[0] > 1
|
107
|
+
):
|
108
|
+
return (
|
109
|
+
f"{server_address}/table/v1/driving/"
|
110
|
+
f"{sources_coord}"
|
111
|
+
f"?annotations={url_cost_type}"
|
112
|
+
)
|
113
|
+
|
114
|
+
destinations_coord = ";".join(
|
115
|
+
f"{destination[1]},{destination[0]}"
|
116
|
+
for destination in destinations_batch
|
117
|
+
)
|
118
|
+
locations_coord = sources_coord + ";" + destinations_coord
|
119
|
+
|
120
|
+
# Get indices of sources and destinations in the form
|
121
|
+
# sources = 0,1,...,N' and destinations = N'+1,N'+2...N'+M'
|
122
|
+
num_sources = sources_batch.shape[0]
|
123
|
+
num_destinations = destinations_batch.shape[0]
|
124
|
+
|
125
|
+
sources_indices = ";".join(str(index) for index in range(num_sources))
|
126
|
+
destinations_indices = ";".join(
|
127
|
+
str(index)
|
128
|
+
for index in range(num_sources, num_sources + num_destinations)
|
129
|
+
)
|
130
|
+
|
131
|
+
return (
|
132
|
+
f"{server_address}/table/v1/driving/"
|
133
|
+
f"{locations_coord}"
|
134
|
+
f"?sources={sources_indices}&destinations={destinations_indices}"
|
135
|
+
f"&annotations={url_cost_type}"
|
136
|
+
)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import numpy as np
|
2
|
+
|
3
|
+
EARTH_RADIUS_METERS = 6371000
|
4
|
+
|
5
|
+
|
6
|
+
def spherical(sources: np.ndarray, destinations: np.ndarray) -> np.ndarray:
|
7
|
+
"""Distance matrix using the Spherical distance"""
|
8
|
+
|
9
|
+
sources_rad = np.radians(sources)
|
10
|
+
destinations_rad = np.radians(destinations)
|
11
|
+
|
12
|
+
delta_lambda = sources_rad[:, [1]] - destinations_rad[:, 1] # (N x M) lng
|
13
|
+
phi1 = sources_rad[:, [0]] # (N x 1) array of source latitudes
|
14
|
+
phi2 = destinations_rad[:, 0] # (1 x M) array of destination latitudes
|
15
|
+
|
16
|
+
delta_sigma = np.arctan2(
|
17
|
+
np.sqrt(
|
18
|
+
(np.cos(phi2) * np.sin(delta_lambda)) ** 2
|
19
|
+
+ (
|
20
|
+
np.cos(phi1) * np.sin(phi2)
|
21
|
+
- np.sin(phi1) * np.cos(phi2) * np.cos(delta_lambda)
|
22
|
+
)
|
23
|
+
** 2
|
24
|
+
),
|
25
|
+
(
|
26
|
+
np.sin(phi1) * np.sin(phi2)
|
27
|
+
+ np.cos(phi1) * np.cos(phi2) * np.cos(delta_lambda)
|
28
|
+
),
|
29
|
+
)
|
30
|
+
|
31
|
+
return EARTH_RADIUS_METERS * delta_sigma
|
@@ -0,0 +1,33 @@
|
|
1
|
+
[tool.poetry]
|
2
|
+
name = "cost-matrix"
|
3
|
+
version = "0.1.0"
|
4
|
+
description = "Designed to simplify the creation of cost matrices for optimization problems."
|
5
|
+
authors = ["Luan <llvdmoraes@gmail.com>"]
|
6
|
+
readme = "README.md"
|
7
|
+
|
8
|
+
[tool.poetry.dependencies]
|
9
|
+
python = ">=3.9,<3.13"
|
10
|
+
numpy = "^1.26.4"
|
11
|
+
requests = "^2.32.3"
|
12
|
+
|
13
|
+
[tool.poetry.group.dev.dependencies]
|
14
|
+
black = "^24.4.2"
|
15
|
+
isort = "^5.13.2"
|
16
|
+
pytest-cov = "^5.0.0"
|
17
|
+
pytest = "^8.2.1"
|
18
|
+
mypy = "^1.10.0"
|
19
|
+
autopep8 = "^2.2.0"
|
20
|
+
flake8 = "^7.0.0"
|
21
|
+
mock = "^5.1.0"
|
22
|
+
types-requests = "^2.32.0.20240602"
|
23
|
+
types-mock = "^5.1.0.20240425"
|
24
|
+
|
25
|
+
[tool.autopep8]
|
26
|
+
max_line_length = 79
|
27
|
+
|
28
|
+
[tool.black]
|
29
|
+
line-length = 79
|
30
|
+
|
31
|
+
[build-system]
|
32
|
+
requires = ["poetry-core"]
|
33
|
+
build-backend = "poetry.core.masonry.api"
|