cost-matrix 0.1.0__py3-none-any.whl → 0.2.0__py3-none-any.whl

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.
@@ -1,5 +1,28 @@
1
1
  import numpy as np
2
2
 
3
3
 
4
- def euclidean(sources: np.ndarray, destinations: np.ndarray) -> np.ndarray:
5
- return np.linalg.norm(sources - destinations, axis=1)
4
+ def euclidean(sources, destinations):
5
+ """
6
+ Calculate the Euclidean distance matrix between source and destination points.
7
+
8
+ Parameters
9
+ ----------
10
+ sources : np.ndarray
11
+ Array of shape (n, d) containing the source points.
12
+ destinations : np.ndarray
13
+ Array of shape (m, d) containing the destination points.
14
+
15
+ Returns
16
+ -------
17
+ np.ndarray
18
+ Euclidean distance matrix of shape (n, m).
19
+ """
20
+ # Expand dimensions to enable broadcasting
21
+ sources_expanded = sources[:, np.newaxis, :]
22
+ destinations_expanded = destinations[np.newaxis, :, :]
23
+
24
+ # Compute differences along the last dimension
25
+ differences = sources_expanded - destinations_expanded
26
+
27
+ # Compute Euclidean distances using norm along the last dimension
28
+ return np.linalg.norm(differences, axis=2)
@@ -2,4 +2,28 @@ import numpy as np
2
2
 
3
3
 
4
4
  def manhattan(sources: np.ndarray, destinations: np.ndarray) -> np.ndarray:
5
- return np.sum(np.abs(sources - destinations), axis=1)
5
+ """
6
+ Compute the Manhattan distance matrix between source and destination points.
7
+
8
+ Parameters
9
+ ----------
10
+ sources : np.ndarray
11
+ Array of shape (n, d) containing the source points.
12
+ destinations : np.ndarray
13
+ Array of shape (m, d) containing the destination points.
14
+
15
+ Returns
16
+ -------
17
+ np.ndarray
18
+ Manhattan distance matrix of shape (n, m).
19
+ """
20
+ # Expand dimensions to enable broadcasting
21
+ sources_expanded = sources[:, np.newaxis, :]
22
+ destinations_expanded = destinations[np.newaxis, :, :]
23
+
24
+ # Compute absolute differences along the last dimension
25
+ differences = np.abs(sources_expanded - destinations_expanded)
26
+
27
+ # Sum absolute differences along the last dimension to get
28
+ # Manhattan distance
29
+ return np.sum(differences, axis=2)
@@ -1,3 +1,5 @@
1
+ import os
2
+ from concurrent.futures import ThreadPoolExecutor
1
3
  from math import ceil
2
4
 
3
5
  import numpy as np
@@ -11,55 +13,88 @@ def osrm(
11
13
  batch_size: int = 150,
12
14
  cost_type: str = "distances",
13
15
  ) -> np.ndarray:
14
- """Compute the OSRM cost matrix between sources and destinations"""
15
-
16
+ """
17
+ Compute the OSRM cost matrix between sources and destinations
18
+
19
+ Parameters
20
+ ----------
21
+ sources : np.ndarray
22
+ Array of shape (n, d) containing the source points.
23
+ destinations : np.ndarray
24
+ Array of shape (m, d) containing the destination points.
25
+ server_address : str
26
+ Address of the OSRM server. Default is "http://router.project-osrm.org".
27
+ batch_size : int
28
+ Number of points to send in each request. Default is 150.
29
+ cost_type : str
30
+ Type of cost to be computed. Default is "distances". Options are
31
+ "distances" and "durations".
32
+
33
+ Returns
34
+ -------
35
+ np.ndarray
36
+ OSRM cost matrix of shape (n, m).
37
+ """
16
38
  num_sources = sources.shape[0]
17
39
  num_destinations = destinations.shape[0]
18
- cost_matrix = np.zeros((num_sources, num_destinations))
40
+ cost_matrix = np.zeros((num_sources, num_destinations), dtype=np.float32)
19
41
 
20
42
  num_batches_i = ceil(num_sources / batch_size)
21
43
  num_batches_j = ceil(num_destinations / batch_size)
22
44
 
23
- for i in range(num_batches_i):
24
- start_i = i * batch_size
25
- end_i = min((i + 1) * batch_size, num_sources)
45
+ cpu_count = os.cpu_count() or 0
46
+ default_max = cpu_count * 2 if cpu_count > 0 else 8
47
+ max_workers = min(default_max, 16)
48
+
49
+ futures = []
50
+ positions = []
51
+
52
+ with ThreadPoolExecutor(max_workers=max_workers) as executor:
53
+ for i in range(num_batches_i):
54
+ start_i = i * batch_size
55
+ end_i = min((i + 1) * batch_size, num_sources)
56
+
57
+ for j in range(num_batches_j):
58
+ start_j = j * batch_size
59
+ end_j = min((j + 1) * batch_size, num_destinations)
26
60
 
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]
61
+ sources_batch = sources[start_i:end_i]
62
+ destinations_batch = destinations[start_j:end_j]
32
63
 
33
- cost_matrix[start_i:end_i, start_j:end_j] = (
34
- _get_batch_osrm_distance(
64
+ future = executor.submit(
65
+ _fetch_matrix_batch,
35
66
  sources_batch,
36
67
  destinations_batch,
37
68
  server_address,
38
- cost_type=cost_type,
69
+ cost_type,
39
70
  )
40
- )
71
+ futures.append(future)
72
+ positions.append((start_i, end_i, start_j, end_j))
73
+
74
+ for future, (start_i, end_i, start_j, end_j) in zip(
75
+ futures, positions, strict=False
76
+ ):
77
+ cost_matrix[start_i:end_i, start_j:end_j] = future.result()
41
78
 
42
79
  return cost_matrix
43
80
 
44
81
 
45
- def _get_batch_osrm_distance(
82
+ def _fetch_matrix_batch(
46
83
  sources_batch: np.ndarray,
47
84
  destinations_batch: np.ndarray,
48
85
  server_address: str,
49
86
  cost_type: str,
50
87
  ):
51
88
  """Request the OSRM cost matrix for a given batch"""
52
-
53
- url = _format_osrm_url(
89
+ url = _format_url(
54
90
  sources_batch, destinations_batch, server_address, cost_type
55
91
  )
56
- resp = requests.get(url)
57
- resp.raise_for_status()
58
-
59
- return np.array(resp.json()[cost_type])
92
+ response = requests.get(url)
93
+ response.raise_for_status()
94
+ return np.array(response.json()[cost_type], dtype=np.float32)
60
95
 
61
96
 
62
- def _format_osrm_url(
97
+ def _format_url(
63
98
  sources_batch: np.ndarray,
64
99
  destinations_batch: np.ndarray,
65
100
  server_address: str,
@@ -93,11 +128,8 @@ def _format_osrm_url(
93
128
  "distance"), but the returned JSON follows the plural form (e.g.,
94
129
  "distances"). Thus, we ignore the last letter of the input type
95
130
  """
96
-
97
131
  url_cost_type = cost_type[:-1]
98
- sources_coord = ";".join(
99
- f"{source[1]},{source[0]}" for source in sources_batch
100
- )
132
+ sources_coord = ";".join(f"{lng},{lat}" for (lat, lng) in sources_batch)
101
133
 
102
134
  # If sources == destinations, return a simpler URL early. Notice it needs
103
135
  # at least two points, otherwise OSRM complains
@@ -106,14 +138,12 @@ def _format_osrm_url(
106
138
  and sources_batch.shape[0] > 1
107
139
  ):
108
140
  return (
109
- f"{server_address}/table/v1/driving/"
110
- f"{sources_coord}"
141
+ f"{server_address}/table/v1/driving/{sources_coord}"
111
142
  f"?annotations={url_cost_type}"
112
143
  )
113
144
 
114
145
  destinations_coord = ";".join(
115
- f"{destination[1]},{destination[0]}"
116
- for destination in destinations_batch
146
+ f"{lng},{lat}" for (lat, lng) in destinations_batch
117
147
  )
118
148
  locations_coord = sources_coord + ";" + destinations_coord
119
149
 
@@ -121,7 +151,6 @@ def _format_osrm_url(
121
151
  # sources = 0,1,...,N' and destinations = N'+1,N'+2...N'+M'
122
152
  num_sources = sources_batch.shape[0]
123
153
  num_destinations = destinations_batch.shape[0]
124
-
125
154
  sources_indices = ";".join(str(index) for index in range(num_sources))
126
155
  destinations_indices = ";".join(
127
156
  str(index)
@@ -129,8 +158,8 @@ def _format_osrm_url(
129
158
  )
130
159
 
131
160
  return (
132
- f"{server_address}/table/v1/driving/"
133
- f"{locations_coord}"
134
- f"?sources={sources_indices}&destinations={destinations_indices}"
161
+ f"{server_address}/table/v1/driving/{locations_coord}"
162
+ f"?sources={sources_indices}"
163
+ f"&destinations={destinations_indices}"
135
164
  f"&annotations={url_cost_type}"
136
165
  )
@@ -4,7 +4,21 @@ EARTH_RADIUS_METERS = 6371000
4
4
 
5
5
 
6
6
  def spherical(sources: np.ndarray, destinations: np.ndarray) -> np.ndarray:
7
- """Distance matrix using the Spherical distance"""
7
+ """
8
+ Compute the distance matrix using the Spherical distance]
9
+
10
+ Parameters
11
+ ----------
12
+ sources : np.ndarray
13
+ Array of shape (n, d) containing the source points.
14
+ destinations : np.ndarray
15
+ Array of shape (m, d) containing the destination points.
16
+
17
+ Returns
18
+ -------
19
+ np.ndarray
20
+ Spherical distance matrix of shape (n, m).
21
+ """
8
22
 
9
23
  sources_rad = np.radians(sources)
10
24
  destinations_rad = np.radians(destinations)
@@ -1,12 +1,11 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.3
2
2
  Name: cost-matrix
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: Designed to simplify the creation of cost matrices for optimization problems.
5
5
  Author: Luan
6
6
  Author-email: llvdmoraes@gmail.com
7
- Requires-Python: >=3.9,<3.13
7
+ Requires-Python: >=3.10,<3.13
8
8
  Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.9
10
9
  Classifier: Programming Language :: Python :: 3.10
11
10
  Classifier: Programming Language :: Python :: 3.11
12
11
  Classifier: Programming Language :: Python :: 3.12
@@ -69,4 +68,8 @@ osrm_duration_matrix = cost_matrix.osrm(
69
68
  batch_size=250
70
69
  )
71
70
  print(osrm_duration_matrix)
71
+ ```
72
+
73
+ ## GitHub
74
+ * [Repository](https://github.com/luanleonardo/cost-matrix)
72
75
 
@@ -0,0 +1,8 @@
1
+ cost_matrix/__init__.py,sha256=9EaPsXe0SIuym34-CPmzUPSGJuBd2AkQZHqjcwlUywE,202
2
+ cost_matrix/euclidean_matrix.py,sha256=PiOJFjalkvk1p4ktcCvFD7EeXswvsnm8f-oze1gFRlk,844
3
+ cost_matrix/manhattan_matrix.py,sha256=OgOepYRfskarZmNNarl58YqNRw7WXYnjztWV2BbjGBI,907
4
+ cost_matrix/osrm_matrix.py,sha256=mlj61VoMKb0hisDl4xdNa_-9gw0RgtILmr4GpjIFg3k,5495
5
+ cost_matrix/spherical_matrix.py,sha256=9_y5XCpdAEiWcvljPX7kFYSUt0nU3Gq4DOwr7LlbhQY,1271
6
+ cost_matrix-0.2.0.dist-info/METADATA,sha256=IZyDlKzSf0C4bnMICS8CgmO6Lrb95eXlXNkK0wVC1is,2702
7
+ cost_matrix-0.2.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
8
+ cost_matrix-0.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,8 +0,0 @@
1
- cost_matrix/__init__.py,sha256=9EaPsXe0SIuym34-CPmzUPSGJuBd2AkQZHqjcwlUywE,202
2
- cost_matrix/euclidean_matrix.py,sha256=a8uLh0COVb5duaKV6DMfG9HklkJX2dOARKfnnWxLxsc,155
3
- cost_matrix/manhattan_matrix.py,sha256=bWTTiIgvb0PDWSdfCXuffHEIgb9nNMb4w7Qwhe3EbaQ,155
4
- cost_matrix/osrm_matrix.py,sha256=VuuoQVRGxMjoN_eUfs9yur9lwINg8JZxB3SX-6cvBFk,4327
5
- cost_matrix/spherical_matrix.py,sha256=SxaihjkKyrp0den5w-VsimGcjjQEi-q-_cvxeTM3xyY,946
6
- cost_matrix-0.1.0.dist-info/METADATA,sha256=4TVrFT0TlklV7jcvRAJarKqi-TE2_TPMtSJJtVZTmIQ,2676
7
- cost_matrix-0.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
8
- cost_matrix-0.1.0.dist-info/RECORD,,