edsger 0.1.1__cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.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.
edsger/dijkstra.pyx ADDED
@@ -0,0 +1,504 @@
1
+ """
2
+ An implementation of Dijkstra's algorithm.
3
+
4
+ cpdef functions:
5
+
6
+ - compute_sssp
7
+ Compute single-source shortest path (from one vertex to all vertices). Does
8
+ not return predecessors.
9
+ - compute_sssp_w_path
10
+ Compute single-source shortest path (from one vertex to all vertices).
11
+ Compute predecessors.
12
+ - compute_stsp
13
+ Compute single-target shortest path (from all vertices to one vertex). Does
14
+ not return successors.
15
+ - compute_stsp_w_path
16
+ Compute single-target shortest path (from all vertices to one vertex).
17
+ Compute successors.
18
+ """
19
+
20
+ cimport numpy as cnp
21
+
22
+ from edsger.commons cimport (
23
+ DTYPE_INF, UNLABELED, SCANNED, DTYPE_t, ElementState)
24
+ cimport edsger.pq_4ary_dec_0b as pq # priority queue
25
+
26
+
27
+ cpdef cnp.ndarray compute_sssp(
28
+ cnp.uint32_t[::1] csr_indptr,
29
+ cnp.uint32_t[::1] csr_indices,
30
+ DTYPE_t[::1] csr_data,
31
+ int source_vert_idx,
32
+ int vertex_count,
33
+ int heap_length):
34
+ """
35
+ Compute single-source shortest path (from one vertex to all vertices). Does
36
+ not return predecessors.
37
+
38
+ Parameters
39
+ ----------
40
+ csr_indices : cnp.uint32_t[::1]
41
+ indices in the CSR format
42
+ csr_indptr : cnp.uint32_t[::1]
43
+ pointers in the CSR format
44
+ csr_data DTYPE_t[::1]
45
+ data (edge weights) in the CSR format
46
+ source_vert_idx : int
47
+ source vertex index
48
+ vertex_count : int
49
+ vertex count
50
+ heap_length : int
51
+ heap length
52
+
53
+ Returns
54
+ -------
55
+ path_lengths : cnp.ndarray
56
+ shortest path length for each vertex
57
+ """
58
+
59
+ cdef:
60
+ size_t tail_vert_idx, head_vert_idx, idx
61
+ DTYPE_t tail_vert_val, head_vert_val
62
+ pq.PriorityQueue pqueue
63
+ ElementState vert_state
64
+ size_t source = <size_t>source_vert_idx
65
+
66
+ with nogil:
67
+
68
+ # initialization of the heap elements
69
+ # all nodes have INFINITY key and UNLABELED state
70
+ pq.init_pqueue(&pqueue, <size_t>heap_length, <size_t>vertex_count)
71
+
72
+ # the key is set to zero for the source vertex,
73
+ # which is inserted into the heap
74
+ pq.insert(&pqueue, source, 0.0)
75
+
76
+ # main loop
77
+ while pqueue.size > 0:
78
+ tail_vert_idx = pq.extract_min(&pqueue)
79
+ tail_vert_val = pqueue.Elements[tail_vert_idx].key
80
+
81
+ # loop on outgoing edges
82
+ for idx in range(<size_t>csr_indptr[tail_vert_idx],
83
+ <size_t>csr_indptr[tail_vert_idx + 1]):
84
+
85
+ head_vert_idx = <size_t>csr_indices[idx]
86
+ vert_state = pqueue.Elements[head_vert_idx].state
87
+ if vert_state != SCANNED:
88
+ head_vert_val = tail_vert_val + csr_data[idx]
89
+ if vert_state == UNLABELED:
90
+ pq.insert(&pqueue, head_vert_idx, head_vert_val)
91
+ elif pqueue.Elements[head_vert_idx].key > head_vert_val:
92
+ pq.decrease_key(&pqueue, head_vert_idx, head_vert_val)
93
+
94
+ # copy the results into a numpy array
95
+ path_lengths = pq.copy_keys_to_numpy(&pqueue, <size_t>vertex_count)
96
+
97
+ # cleanup
98
+ pq.free_pqueue(&pqueue)
99
+
100
+ return path_lengths
101
+
102
+
103
+ cpdef cnp.ndarray compute_sssp_w_path(
104
+ cnp.uint32_t[::1] csr_indptr,
105
+ cnp.uint32_t[::1] csr_indices,
106
+ DTYPE_t[::1] csr_data,
107
+ cnp.uint32_t[::1] predecessor,
108
+ int source_vert_idx,
109
+ int vertex_count,
110
+ int heap_length):
111
+ """
112
+ Compute single-source shortest path (from one vertex to all vertices).
113
+ Compute predecessors.
114
+
115
+ Parameters
116
+ ----------
117
+ csr_indices : cnp.uint32_t[::1]
118
+ indices in the CSR format
119
+ csr_indptr : cnp.uint32_t[::1]
120
+ pointers in the CSR format
121
+ csr_data : DTYPE_t[::1]
122
+ data (edge weights) in the CSR format
123
+ predecessor : cnp.uint32_t[::1]
124
+ array of indices, one for each vertex of the graph. Each vertex'
125
+ entry contains the index of its predecessor in a path from the
126
+ source, through the graph.
127
+ source_vert_idx : int
128
+ source vertex index
129
+ vertex_count : int
130
+ vertex count
131
+ heap_length : int
132
+ heap length
133
+
134
+ Returns
135
+ -------
136
+ path_lengths : cnp.ndarray
137
+ shortest path length for each vertex
138
+ """
139
+
140
+ cdef:
141
+ size_t tail_vert_idx, head_vert_idx, idx
142
+ DTYPE_t tail_vert_val, head_vert_val
143
+ pq.PriorityQueue pqueue
144
+ ElementState vert_state
145
+ size_t source = <size_t>source_vert_idx
146
+
147
+ with nogil:
148
+
149
+ # initialization of the heap elements
150
+ # all nodes have INFINITY key and UNLABELED state
151
+ pq.init_pqueue(&pqueue, <size_t>heap_length, <size_t>vertex_count)
152
+
153
+ # the key is set to zero for the source vertex,
154
+ # which is inserted into the heap
155
+ pq.insert(&pqueue, source, 0.0)
156
+
157
+ # main loop
158
+ while pqueue.size > 0:
159
+ tail_vert_idx = pq.extract_min(&pqueue)
160
+ tail_vert_val = pqueue.Elements[tail_vert_idx].key
161
+
162
+ # loop on outgoing edges
163
+ for idx in range(<size_t>csr_indptr[tail_vert_idx],
164
+ <size_t>csr_indptr[tail_vert_idx + 1]):
165
+
166
+ head_vert_idx = <size_t>csr_indices[idx]
167
+ vert_state = pqueue.Elements[head_vert_idx].state
168
+ if vert_state != SCANNED:
169
+ head_vert_val = tail_vert_val + csr_data[idx]
170
+ if vert_state == UNLABELED:
171
+ pq.insert(&pqueue, head_vert_idx, head_vert_val)
172
+ predecessor[head_vert_idx] = tail_vert_idx
173
+ elif pqueue.Elements[head_vert_idx].key > head_vert_val:
174
+ pq.decrease_key(&pqueue, head_vert_idx, head_vert_val)
175
+ predecessor[head_vert_idx] = tail_vert_idx
176
+
177
+ # copy the results into a numpy array
178
+ path_lengths = pq.copy_keys_to_numpy(&pqueue, <size_t>vertex_count)
179
+
180
+ # cleanup
181
+ pq.free_pqueue(&pqueue)
182
+
183
+ return path_lengths
184
+
185
+
186
+ cpdef cnp.ndarray compute_stsp(
187
+ cnp.uint32_t[::1] csc_indptr,
188
+ cnp.uint32_t[::1] csc_indices,
189
+ DTYPE_t[::1] csc_data,
190
+ int target_vert_idx,
191
+ int vertex_count,
192
+ int heap_length):
193
+ """
194
+ Compute single-target shortest path (from all vertices to one vertex). Does
195
+ not return successors.
196
+
197
+ Parameters
198
+ ----------
199
+ csc_indices : cnp.uint32_t[::1]
200
+ indices in the CSC format
201
+ csc_indptr : cnp.uint32_t[::1]
202
+ pointers in the CSC format
203
+ csc_data : DTYPE_t[::1]
204
+ data (edge weights) in the CSC format
205
+ target_vert_idx : int
206
+ source vertex index
207
+ vertex_count : int
208
+ vertex count
209
+ heap_length : int
210
+ heap length
211
+
212
+ Returns
213
+ -------
214
+ path_lengths : cnp.ndarray
215
+ shortest path length for each vertex
216
+ """
217
+
218
+ cdef:
219
+ size_t tail_vert_idx, head_vert_idx, idx
220
+ DTYPE_t tail_vert_val, head_vert_val
221
+ pq.PriorityQueue pqueue
222
+ ElementState vert_state
223
+ size_t target = <size_t>target_vert_idx
224
+
225
+ with nogil:
226
+
227
+ # initialization of the heap elements
228
+ # all nodes have INFINITY key and UNLABELED state
229
+ pq.init_pqueue(&pqueue, <size_t>heap_length, <size_t>vertex_count)
230
+
231
+ # the key is set to zero for the target vertex,
232
+ # which is inserted into the heap
233
+ pq.insert(&pqueue, target, 0.0)
234
+
235
+ # main loop
236
+ while pqueue.size > 0:
237
+ head_vert_idx = pq.extract_min(&pqueue)
238
+ head_vert_val = pqueue.Elements[head_vert_idx].key
239
+
240
+ # loop on incoming edges
241
+ for idx in range(<size_t>csc_indptr[head_vert_idx],
242
+ <size_t>csc_indptr[head_vert_idx + 1]):
243
+
244
+ tail_vert_idx = <size_t>csc_indices[idx]
245
+ vert_state = pqueue.Elements[tail_vert_idx].state
246
+ if vert_state != SCANNED:
247
+ tail_vert_val = head_vert_val + csc_data[idx]
248
+ if vert_state == UNLABELED:
249
+ pq.insert(&pqueue, tail_vert_idx, tail_vert_val)
250
+ elif pqueue.Elements[tail_vert_idx].key > tail_vert_val:
251
+ pq.decrease_key(&pqueue, tail_vert_idx, tail_vert_val)
252
+
253
+ # copy the results into a numpy array
254
+ path_lengths = pq.copy_keys_to_numpy(&pqueue, <size_t>vertex_count)
255
+
256
+ # cleanup
257
+ pq.free_pqueue(&pqueue)
258
+
259
+ return path_lengths
260
+
261
+
262
+ cpdef cnp.ndarray compute_stsp_w_path(
263
+ cnp.uint32_t[::1] csc_indptr,
264
+ cnp.uint32_t[::1] csc_indices,
265
+ DTYPE_t[::1] csc_data,
266
+ cnp.uint32_t[::1] successor,
267
+ int target_vert_idx,
268
+ int vertex_count,
269
+ int heap_length):
270
+ """
271
+ Compute single-target shortest path (from all vertices to one vertex).
272
+ Compute successors.
273
+
274
+ Parameters
275
+ ----------
276
+ csc_indices : cnp.uint32_t[::1]
277
+ Indices in the CSC format.
278
+ csc_indices : cnp.uint32_t[::1]
279
+ Pointers in the CSC format.
280
+ csc_data : DTYPE_t[::1]
281
+ Data (edge weights) in the CSC format.
282
+ target_vert_idx : int
283
+ Target vertex index.
284
+ vertex_count : int
285
+ Vertex count.
286
+ heap_length : int
287
+ heap_length.
288
+
289
+ Returns
290
+ -------
291
+ path_lengths : cnp.ndarray
292
+ shortest path length for each vertex
293
+ """
294
+
295
+ cdef:
296
+ size_t tail_vert_idx, head_vert_idx, idx
297
+ DTYPE_t tail_vert_val, head_vert_val
298
+ pq.PriorityQueue pqueue
299
+ ElementState vert_state
300
+ size_t target = <size_t>target_vert_idx
301
+
302
+ with nogil:
303
+
304
+ # initialization of the heap elements
305
+ # all nodes have INFINITY key and UNLABELED state
306
+ pq.init_pqueue(&pqueue, <size_t>heap_length, <size_t>vertex_count)
307
+
308
+ # the key is set to zero for the target vertex,
309
+ # which is inserted into the heap
310
+ pq.insert(&pqueue, target, 0.0)
311
+
312
+ # main loop
313
+ while pqueue.size > 0:
314
+ head_vert_idx = pq.extract_min(&pqueue)
315
+ head_vert_val = pqueue.Elements[head_vert_idx].key
316
+
317
+ # loop on incoming edges
318
+ for idx in range(<size_t>csc_indptr[head_vert_idx],
319
+ <size_t>csc_indptr[head_vert_idx + 1]):
320
+
321
+ tail_vert_idx = <size_t>csc_indices[idx]
322
+ vert_state = pqueue.Elements[tail_vert_idx].state
323
+ if vert_state != SCANNED:
324
+ tail_vert_val = head_vert_val + csc_data[idx]
325
+ if vert_state == UNLABELED:
326
+ pq.insert(&pqueue, tail_vert_idx, tail_vert_val)
327
+ successor[tail_vert_idx] = head_vert_idx
328
+ elif pqueue.Elements[tail_vert_idx].key > tail_vert_val:
329
+ pq.decrease_key(&pqueue, tail_vert_idx, tail_vert_val)
330
+ successor[tail_vert_idx] = head_vert_idx
331
+
332
+ # copy the results into a numpy array
333
+ path_lengths = pq.copy_keys_to_numpy(&pqueue, <size_t>vertex_count)
334
+
335
+ # cleanup
336
+ pq.free_pqueue(&pqueue)
337
+
338
+ return path_lengths
339
+
340
+
341
+ # ============================================================================ #
342
+ # tests #
343
+ # ============================================================================ #
344
+
345
+ from edsger.commons import DTYPE_PY
346
+ import numpy as np
347
+
348
+
349
+ cdef generate_single_edge_network_csr():
350
+ """
351
+ Generate a single edge network in CSR format.
352
+
353
+ This network has 1 edge and 2 vertices.
354
+ """
355
+
356
+ csr_indptr = np.array([0, 1, 1], dtype=np.uint32)
357
+ csr_indices = np.array([1], dtype=np.uint32)
358
+ csr_data = np.array([1.], dtype=DTYPE_PY)
359
+
360
+ return csr_indptr, csr_indices, csr_data
361
+
362
+
363
+ cdef generate_single_edge_network_csc():
364
+ """
365
+ Generate a single edge network in CSC format.
366
+
367
+ This network has 1 edge and 2 vertices.
368
+ """
369
+
370
+ csc_indptr = np.array([0, 0, 1], dtype=np.uint32)
371
+ csc_indices = np.array([0], dtype=np.uint32)
372
+ csc_data = np.array([1.], dtype=DTYPE_PY)
373
+
374
+ return csc_indptr, csc_indices, csc_data
375
+
376
+
377
+ cdef generate_braess_network_csr():
378
+ """
379
+ Generate a Braess-like network in CSR format.
380
+
381
+ This network hs 5 edges and 4 vertices.
382
+ """
383
+
384
+ csr_indptr = np.array([0, 2, 4, 5, 5], dtype=np.uint32)
385
+ csr_indices = np.array([1, 2, 2, 3, 3], dtype=np.uint32)
386
+ csr_data = np.array([1., 2., 0., 2., 1.], dtype=DTYPE_PY)
387
+
388
+ return csr_indptr, csr_indices, csr_data
389
+
390
+
391
+ cdef generate_braess_network_csc():
392
+ """
393
+ Generate a Braess-like network in CSC format.
394
+
395
+ This network hs 5 edges and 4 vertices.
396
+ """
397
+
398
+ csc_indptr = np.array([0, 0, 1, 3, 5], dtype=np.uint32)
399
+ csc_indices = np.array([0, 0, 1, 1, 2], dtype=np.uint32)
400
+ csc_data = np.array([1., 2., 0., 2., 1.], dtype=DTYPE_PY)
401
+
402
+ return csc_indptr, csc_indices, csc_data
403
+
404
+
405
+ cpdef compute_sssp_01():
406
+ """
407
+ Compute SSSP with the compute_sssp_pq_bd0 routine on a single edge
408
+ network.
409
+ """
410
+
411
+ csr_indptr, csr_indices, csr_data = generate_single_edge_network_csr()
412
+
413
+ # from vertex 0
414
+ path_lengths = compute_sssp(csr_indptr, csr_indices, csr_data, 0, 2, 2)
415
+ path_lengths_ref = np.array([0., 1.], dtype=DTYPE_PY)
416
+ assert np.allclose(path_lengths_ref, path_lengths)
417
+
418
+ # from vertex 1
419
+ path_lengths = compute_sssp(csr_indptr, csr_indices, csr_data, 1, 2, 2)
420
+ path_lengths_ref = np.array([DTYPE_INF, 0.], dtype=DTYPE_PY)
421
+ assert np.allclose(path_lengths_ref, path_lengths)
422
+
423
+
424
+ cpdef compute_stsp_01():
425
+ """
426
+ Compute TSSP with the compute_stsp_pq_bd0 routine on a single edge
427
+ network.
428
+ """
429
+
430
+ csc_indptr, csc_indices, csc_data = generate_single_edge_network_csc()
431
+
432
+ # from vertex 0
433
+ path_lengths = compute_stsp(csc_indptr, csc_indices, csc_data, 0, 2, 2)
434
+ path_lengths_ref = np.array([0., DTYPE_INF], dtype=DTYPE_PY)
435
+ assert np.allclose(path_lengths_ref, path_lengths)
436
+
437
+ # from vertex 1
438
+ path_lengths = compute_stsp(csc_indptr, csc_indices, csc_data, 1, 2, 2)
439
+ path_lengths_ref = np.array([1., 0.], dtype=DTYPE_PY)
440
+ assert np.allclose(path_lengths_ref, path_lengths)
441
+
442
+
443
+ cpdef compute_sssp_02():
444
+ """
445
+ Compute SSSP with the compute_sssp_pq_bd0 routine on Braess-like
446
+ network.
447
+ """
448
+
449
+ csr_indptr, csr_indices, csr_data = generate_braess_network_csr()
450
+
451
+ # from vertex 0
452
+ path_lengths = compute_sssp(csr_indptr, csr_indices, csr_data, 0, 4, 4)
453
+ path_lengths_ref = np.array([0., 1., 1., 2.], dtype=DTYPE_PY)
454
+ assert np.allclose(path_lengths_ref, path_lengths)
455
+
456
+ # from vertex 1
457
+ path_lengths = compute_sssp(csr_indptr, csr_indices, csr_data, 1, 4, 4)
458
+ path_lengths_ref = np.array([DTYPE_INF, 0., 0., 1.], dtype=DTYPE_PY)
459
+ assert np.allclose(path_lengths_ref, path_lengths)
460
+
461
+ # from vertex 2
462
+ path_lengths = compute_sssp(csr_indptr, csr_indices, csr_data, 2, 4, 4)
463
+ path_lengths_ref = np.array([DTYPE_INF, DTYPE_INF, 0., 1.], dtype=DTYPE_PY)
464
+ assert np.allclose(path_lengths_ref, path_lengths)
465
+
466
+ # from vertex 3
467
+ path_lengths = compute_sssp(csr_indptr, csr_indices, csr_data, 3, 4, 4)
468
+ path_lengths_ref = np.array([DTYPE_INF, DTYPE_INF, DTYPE_INF, 0.], dtype=DTYPE_PY)
469
+ assert np.allclose(path_lengths_ref, path_lengths)
470
+
471
+
472
+ cpdef compute_stsp_02():
473
+ """
474
+ Compute STSP with the compute_stsp_pq_bd0 routine on Braess-like
475
+ network.
476
+ """
477
+
478
+ csc_indptr, csc_indices, csc_data = generate_braess_network_csc()
479
+
480
+ # from vertex 0
481
+ path_lengths = compute_stsp(csc_indptr, csc_indices, csc_data, 0, 4, 4)
482
+ path_lengths_ref = np.array([0., DTYPE_INF, DTYPE_INF, DTYPE_INF], dtype=DTYPE_PY)
483
+ assert np.allclose(path_lengths_ref, path_lengths)
484
+
485
+ # from vertex 1
486
+ path_lengths = compute_stsp(csc_indptr, csc_indices, csc_data, 1, 4, 4)
487
+ path_lengths_ref = np.array([1., 0., DTYPE_INF, DTYPE_INF], dtype=DTYPE_PY)
488
+ assert np.allclose(path_lengths_ref, path_lengths)
489
+
490
+ # from vertex 2
491
+ path_lengths = compute_stsp(csc_indptr, csc_indices, csc_data, 2, 4, 4)
492
+ path_lengths_ref = np.array([1., 0., 0., DTYPE_INF], dtype=DTYPE_PY)
493
+ assert np.allclose(path_lengths_ref, path_lengths)
494
+
495
+ # from vertex 3
496
+ path_lengths = compute_stsp(csc_indptr, csc_indices, csc_data, 3, 4, 4)
497
+ path_lengths_ref = np.array([2., 1.0, 1., 0.], dtype=DTYPE_PY)
498
+ assert np.allclose(path_lengths_ref, path_lengths)
499
+
500
+
501
+ # author : Francois Pacull
502
+ # copyright : Architecture & Performance
503
+ # email: francois.pacull@architecture-performance.fr
504
+ # license : MIT