edsger 0.1.2__cp312-cp312-win32.whl → 0.1.4__cp312-cp312-win32.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/_version.py +1 -1
- edsger/commons.cp312-win32.pyd +0 -0
- edsger/dijkstra.cp312-win32.pyd +0 -0
- edsger/dijkstra.pyx +507 -5
- edsger/path.py +145 -37
- edsger/path_tracking.cp312-win32.pyd +0 -0
- edsger/pq_4ary_dec_0b.cp312-win32.pyd +0 -0
- edsger/spiess_florian.cp312-win32.pyd +0 -0
- edsger/star.cp312-win32.pyd +0 -0
- {edsger-0.1.2.dist-info → edsger-0.1.4.dist-info}/METADATA +21 -14
- edsger-0.1.4.dist-info/RECORD +27 -0
- edsger-0.1.2.dist-info/RECORD +0 -27
- {edsger-0.1.2.dist-info → edsger-0.1.4.dist-info}/WHEEL +0 -0
- {edsger-0.1.2.dist-info → edsger-0.1.4.dist-info}/licenses/AUTHORS.rst +0 -0
- {edsger-0.1.2.dist-info → edsger-0.1.4.dist-info}/licenses/LICENSE +0 -0
- {edsger-0.1.2.dist-info → edsger-0.1.4.dist-info}/top_level.txt +0 -0
edsger/_version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.1.
|
1
|
+
__version__ = "0.1.4"
|
edsger/commons.cp312-win32.pyd
CHANGED
Binary file
|
edsger/dijkstra.cp312-win32.pyd
CHANGED
Binary file
|
edsger/dijkstra.pyx
CHANGED
@@ -9,12 +9,24 @@ cpdef functions:
|
|
9
9
|
- compute_sssp_w_path
|
10
10
|
Compute single-source shortest path (from one vertex to all vertices).
|
11
11
|
Compute predecessors.
|
12
|
+
- compute_sssp_early_termination
|
13
|
+
Compute single-source shortest path with early termination when target nodes
|
14
|
+
are reached. Does not return predecessors.
|
15
|
+
- compute_sssp_w_path_early_termination
|
16
|
+
Compute single-source shortest path with early termination when target nodes
|
17
|
+
are reached. Compute predecessors.
|
12
18
|
- compute_stsp
|
13
19
|
Compute single-target shortest path (from all vertices to one vertex). Does
|
14
20
|
not return successors.
|
15
21
|
- compute_stsp_w_path
|
16
22
|
Compute single-target shortest path (from all vertices to one vertex).
|
17
23
|
Compute successors.
|
24
|
+
- compute_stsp_early_termination
|
25
|
+
Compute single-target shortest path with early termination when target nodes
|
26
|
+
are reached. Does not return successors.
|
27
|
+
- compute_stsp_w_path_early_termination
|
28
|
+
Compute single-target shortest path with early termination when target nodes
|
29
|
+
are reached. Compute successors.
|
18
30
|
"""
|
19
31
|
|
20
32
|
cimport numpy as cnp
|
@@ -23,7 +35,7 @@ from edsger.commons cimport (
|
|
23
35
|
DTYPE_INF, UNLABELED, SCANNED, DTYPE_t, ElementState)
|
24
36
|
cimport edsger.pq_4ary_dec_0b as pq # priority queue
|
25
37
|
|
26
|
-
#
|
38
|
+
# memory prefetching support (x86/x64 only)
|
27
39
|
cdef extern from "prefetch_compat.h":
|
28
40
|
void prefetch_hint(char*, int) nogil
|
29
41
|
int PREFETCH_T0
|
@@ -89,14 +101,14 @@ cpdef cnp.ndarray compute_sssp(
|
|
89
101
|
|
90
102
|
head_vert_idx = <size_t>csr_indices[idx]
|
91
103
|
|
92
|
-
#
|
104
|
+
# prefetch next iteration data to improve cache performance
|
93
105
|
if idx + 1 < <size_t>csr_indptr[tail_vert_idx + 1]:
|
94
106
|
prefetch_hint(<char*>&csr_indices[idx + 1], PREFETCH_T0)
|
95
107
|
prefetch_hint(<char*>&csr_data[idx + 1], PREFETCH_T0)
|
96
108
|
|
97
109
|
vert_state = pqueue.Elements[head_vert_idx].state
|
98
110
|
if vert_state != SCANNED:
|
99
|
-
#
|
111
|
+
# prefetch priority queue element data for the vertex
|
100
112
|
prefetch_hint(<char*>&pqueue.Elements[head_vert_idx], PREFETCH_T0)
|
101
113
|
|
102
114
|
head_vert_val = tail_vert_val + csr_data[idx]
|
@@ -114,6 +126,109 @@ cpdef cnp.ndarray compute_sssp(
|
|
114
126
|
return path_lengths
|
115
127
|
|
116
128
|
|
129
|
+
cpdef cnp.ndarray compute_sssp_early_termination(
|
130
|
+
cnp.uint32_t[::1] csr_indptr,
|
131
|
+
cnp.uint32_t[::1] csr_indices,
|
132
|
+
DTYPE_t[::1] csr_data,
|
133
|
+
cnp.uint32_t[::1] termination_nodes,
|
134
|
+
int source_vert_idx,
|
135
|
+
int vertex_count,
|
136
|
+
int heap_length):
|
137
|
+
"""
|
138
|
+
Compute single-source shortest path with early termination when target
|
139
|
+
nodes are reached.
|
140
|
+
Parameters
|
141
|
+
----------
|
142
|
+
csr_indices : cnp.uint32_t[::1]
|
143
|
+
indices in the CSR format
|
144
|
+
csr_indptr : cnp.uint32_t[::1]
|
145
|
+
pointers in the CSR format
|
146
|
+
csr_data DTYPE_t[::1]
|
147
|
+
data (edge weights) in the CSR format
|
148
|
+
termination_nodes : cnp.uint32_t[::1]
|
149
|
+
target node indices for early termination
|
150
|
+
source_vert_idx : int
|
151
|
+
source vertex index
|
152
|
+
vertex_count : int
|
153
|
+
vertex count
|
154
|
+
heap_length : int
|
155
|
+
heap length
|
156
|
+
|
157
|
+
Returns
|
158
|
+
-------
|
159
|
+
path_lengths : cnp.ndarray
|
160
|
+
shortest path length for each termination node
|
161
|
+
"""
|
162
|
+
|
163
|
+
cdef:
|
164
|
+
size_t tail_vert_idx, head_vert_idx, idx, i
|
165
|
+
DTYPE_t tail_vert_val, head_vert_val
|
166
|
+
pq.PriorityQueue pqueue
|
167
|
+
ElementState vert_state
|
168
|
+
size_t source = <size_t>source_vert_idx
|
169
|
+
size_t target_count = termination_nodes.shape[0]
|
170
|
+
size_t visited_targets = 0
|
171
|
+
size_t iteration_count = 0
|
172
|
+
size_t check_frequency = 16
|
173
|
+
|
174
|
+
with nogil:
|
175
|
+
|
176
|
+
# initialization of the heap elements
|
177
|
+
# all nodes have INFINITY key and UNLABELED state
|
178
|
+
pq.init_pqueue(&pqueue, <size_t>heap_length, <size_t>vertex_count)
|
179
|
+
|
180
|
+
# the key is set to zero for the source vertex,
|
181
|
+
# which is inserted into the heap
|
182
|
+
pq.insert(&pqueue, source, 0.0)
|
183
|
+
|
184
|
+
# main loop
|
185
|
+
while pqueue.size > 0:
|
186
|
+
tail_vert_idx = pq.extract_min(&pqueue)
|
187
|
+
tail_vert_val = pqueue.Elements[tail_vert_idx].key
|
188
|
+
|
189
|
+
# check for early termination every check_frequency iterations
|
190
|
+
iteration_count += 1
|
191
|
+
if iteration_count % check_frequency == 0:
|
192
|
+
visited_targets = 0
|
193
|
+
for i in range(target_count):
|
194
|
+
if pqueue.Elements[termination_nodes[i]].state == SCANNED:
|
195
|
+
visited_targets += 1
|
196
|
+
if visited_targets == target_count:
|
197
|
+
break
|
198
|
+
|
199
|
+
# loop on outgoing edges
|
200
|
+
for idx in range(<size_t>csr_indptr[tail_vert_idx],
|
201
|
+
<size_t>csr_indptr[tail_vert_idx + 1]):
|
202
|
+
|
203
|
+
head_vert_idx = <size_t>csr_indices[idx]
|
204
|
+
|
205
|
+
# prefetch next iteration data to improve cache performance
|
206
|
+
if idx + 1 < <size_t>csr_indptr[tail_vert_idx + 1]:
|
207
|
+
prefetch_hint(<char*>&csr_indices[idx + 1], PREFETCH_T0)
|
208
|
+
prefetch_hint(<char*>&csr_data[idx + 1], PREFETCH_T0)
|
209
|
+
|
210
|
+
vert_state = pqueue.Elements[head_vert_idx].state
|
211
|
+
if vert_state != SCANNED:
|
212
|
+
# prefetch priority queue element data for the vertex
|
213
|
+
prefetch_hint(<char*>&pqueue.Elements[head_vert_idx], PREFETCH_T0)
|
214
|
+
|
215
|
+
head_vert_val = tail_vert_val + csr_data[idx]
|
216
|
+
if vert_state == UNLABELED:
|
217
|
+
pq.insert(&pqueue, head_vert_idx, head_vert_val)
|
218
|
+
elif pqueue.Elements[head_vert_idx].key > head_vert_val:
|
219
|
+
pq.decrease_key(&pqueue, head_vert_idx, head_vert_val)
|
220
|
+
|
221
|
+
# copy only the termination nodes' results into a numpy array
|
222
|
+
cdef cnp.ndarray path_lengths = np.empty(target_count, dtype=DTYPE_PY)
|
223
|
+
for i in range(target_count):
|
224
|
+
path_lengths[i] = pqueue.Elements[termination_nodes[i]].key
|
225
|
+
|
226
|
+
# cleanup
|
227
|
+
pq.free_pqueue(&pqueue)
|
228
|
+
|
229
|
+
return path_lengths
|
230
|
+
|
231
|
+
|
117
232
|
cpdef cnp.ndarray compute_sssp_w_path(
|
118
233
|
cnp.uint32_t[::1] csr_indptr,
|
119
234
|
cnp.uint32_t[::1] csr_indices,
|
@@ -179,14 +294,14 @@ cpdef cnp.ndarray compute_sssp_w_path(
|
|
179
294
|
|
180
295
|
head_vert_idx = <size_t>csr_indices[idx]
|
181
296
|
|
182
|
-
#
|
297
|
+
# prefetch next iteration data to improve cache performance
|
183
298
|
if idx + 1 < <size_t>csr_indptr[tail_vert_idx + 1]:
|
184
299
|
prefetch_hint(<char*>&csr_indices[idx + 1], PREFETCH_T0)
|
185
300
|
prefetch_hint(<char*>&csr_data[idx + 1], PREFETCH_T0)
|
186
301
|
|
187
302
|
vert_state = pqueue.Elements[head_vert_idx].state
|
188
303
|
if vert_state != SCANNED:
|
189
|
-
#
|
304
|
+
# prefetch priority queue element data for the vertex
|
190
305
|
prefetch_hint(<char*>&pqueue.Elements[head_vert_idx], PREFETCH_T0)
|
191
306
|
|
192
307
|
head_vert_val = tail_vert_val + csr_data[idx]
|
@@ -206,6 +321,115 @@ cpdef cnp.ndarray compute_sssp_w_path(
|
|
206
321
|
return path_lengths
|
207
322
|
|
208
323
|
|
324
|
+
cpdef cnp.ndarray compute_sssp_w_path_early_termination(
|
325
|
+
cnp.uint32_t[::1] csr_indptr,
|
326
|
+
cnp.uint32_t[::1] csr_indices,
|
327
|
+
DTYPE_t[::1] csr_data,
|
328
|
+
cnp.uint32_t[::1] predecessor,
|
329
|
+
cnp.uint32_t[::1] termination_nodes,
|
330
|
+
int source_vert_idx,
|
331
|
+
int vertex_count,
|
332
|
+
int heap_length):
|
333
|
+
"""
|
334
|
+
Compute single-source shortest path with path tracking and early termination.
|
335
|
+
Parameters
|
336
|
+
----------
|
337
|
+
csr_indices : cnp.uint32_t[::1]
|
338
|
+
indices in the CSR format
|
339
|
+
csr_indptr : cnp.uint32_t[::1]
|
340
|
+
pointers in the CSR format
|
341
|
+
csr_data : DTYPE_t[::1]
|
342
|
+
data (edge weights) in the CSR format
|
343
|
+
predecessor : cnp.uint32_t[::1]
|
344
|
+
array of indices, one for each vertex of the graph. Each vertex'
|
345
|
+
entry contains the index of its predecessor in a path from the
|
346
|
+
source, through the graph.
|
347
|
+
termination_nodes : cnp.uint32_t[::1]
|
348
|
+
target node indices for early termination
|
349
|
+
source_vert_idx : int
|
350
|
+
source vertex index
|
351
|
+
vertex_count : int
|
352
|
+
vertex count
|
353
|
+
heap_length : int
|
354
|
+
heap length
|
355
|
+
|
356
|
+
Returns
|
357
|
+
-------
|
358
|
+
path_lengths : cnp.ndarray
|
359
|
+
shortest path length for each termination node
|
360
|
+
"""
|
361
|
+
|
362
|
+
cdef:
|
363
|
+
size_t tail_vert_idx, head_vert_idx, idx, i
|
364
|
+
DTYPE_t tail_vert_val, head_vert_val
|
365
|
+
pq.PriorityQueue pqueue
|
366
|
+
ElementState vert_state
|
367
|
+
size_t source = <size_t>source_vert_idx
|
368
|
+
size_t target_count = termination_nodes.shape[0]
|
369
|
+
size_t visited_targets = 0
|
370
|
+
size_t iteration_count = 0
|
371
|
+
size_t check_frequency = 16
|
372
|
+
|
373
|
+
with nogil:
|
374
|
+
|
375
|
+
# initialization of the heap elements
|
376
|
+
# all nodes have INFINITY key and UNLABELED state
|
377
|
+
pq.init_pqueue(&pqueue, <size_t>heap_length, <size_t>vertex_count)
|
378
|
+
|
379
|
+
# the key is set to zero for the source vertex,
|
380
|
+
# which is inserted into the heap
|
381
|
+
pq.insert(&pqueue, source, 0.0)
|
382
|
+
|
383
|
+
# main loop
|
384
|
+
while pqueue.size > 0:
|
385
|
+
tail_vert_idx = pq.extract_min(&pqueue)
|
386
|
+
tail_vert_val = pqueue.Elements[tail_vert_idx].key
|
387
|
+
|
388
|
+
# check for early termination every check_frequency iterations
|
389
|
+
iteration_count += 1
|
390
|
+
if iteration_count % check_frequency == 0:
|
391
|
+
visited_targets = 0
|
392
|
+
for i in range(target_count):
|
393
|
+
if pqueue.Elements[termination_nodes[i]].state == SCANNED:
|
394
|
+
visited_targets += 1
|
395
|
+
if visited_targets == target_count:
|
396
|
+
break
|
397
|
+
|
398
|
+
# loop on outgoing edges
|
399
|
+
for idx in range(<size_t>csr_indptr[tail_vert_idx],
|
400
|
+
<size_t>csr_indptr[tail_vert_idx + 1]):
|
401
|
+
|
402
|
+
head_vert_idx = <size_t>csr_indices[idx]
|
403
|
+
|
404
|
+
# prefetch next iteration data to improve cache performance
|
405
|
+
if idx + 1 < <size_t>csr_indptr[tail_vert_idx + 1]:
|
406
|
+
prefetch_hint(<char*>&csr_indices[idx + 1], PREFETCH_T0)
|
407
|
+
prefetch_hint(<char*>&csr_data[idx + 1], PREFETCH_T0)
|
408
|
+
|
409
|
+
vert_state = pqueue.Elements[head_vert_idx].state
|
410
|
+
if vert_state != SCANNED:
|
411
|
+
# prefetch priority queue element data for the vertex
|
412
|
+
prefetch_hint(<char*>&pqueue.Elements[head_vert_idx], PREFETCH_T0)
|
413
|
+
|
414
|
+
head_vert_val = tail_vert_val + csr_data[idx]
|
415
|
+
if vert_state == UNLABELED:
|
416
|
+
pq.insert(&pqueue, head_vert_idx, head_vert_val)
|
417
|
+
predecessor[head_vert_idx] = tail_vert_idx
|
418
|
+
elif pqueue.Elements[head_vert_idx].key > head_vert_val:
|
419
|
+
pq.decrease_key(&pqueue, head_vert_idx, head_vert_val)
|
420
|
+
predecessor[head_vert_idx] = tail_vert_idx
|
421
|
+
|
422
|
+
# copy only the termination nodes' results into a numpy array
|
423
|
+
cdef cnp.ndarray path_lengths = np.empty(target_count, dtype=DTYPE_PY)
|
424
|
+
for i in range(target_count):
|
425
|
+
path_lengths[i] = pqueue.Elements[termination_nodes[i]].key
|
426
|
+
|
427
|
+
# cleanup
|
428
|
+
pq.free_pqueue(&pqueue)
|
429
|
+
|
430
|
+
return path_lengths
|
431
|
+
|
432
|
+
|
209
433
|
cpdef cnp.ndarray compute_stsp(
|
210
434
|
cnp.uint32_t[::1] csc_indptr,
|
211
435
|
cnp.uint32_t[::1] csc_indices,
|
@@ -265,8 +489,17 @@ cpdef cnp.ndarray compute_stsp(
|
|
265
489
|
<size_t>csc_indptr[head_vert_idx + 1]):
|
266
490
|
|
267
491
|
tail_vert_idx = <size_t>csc_indices[idx]
|
492
|
+
|
493
|
+
# prefetch next iteration data to improve cache performance
|
494
|
+
if idx + 1 < <size_t>csc_indptr[head_vert_idx + 1]:
|
495
|
+
prefetch_hint(<char*>&csc_indices[idx + 1], PREFETCH_T0)
|
496
|
+
prefetch_hint(<char*>&csc_data[idx + 1], PREFETCH_T0)
|
497
|
+
|
268
498
|
vert_state = pqueue.Elements[tail_vert_idx].state
|
269
499
|
if vert_state != SCANNED:
|
500
|
+
# prefetch priority queue element data for the vertex
|
501
|
+
prefetch_hint(<char*>&pqueue.Elements[tail_vert_idx], PREFETCH_T0)
|
502
|
+
|
270
503
|
tail_vert_val = head_vert_val + csc_data[idx]
|
271
504
|
if vert_state == UNLABELED:
|
272
505
|
pq.insert(&pqueue, tail_vert_idx, tail_vert_val)
|
@@ -342,8 +575,17 @@ cpdef cnp.ndarray compute_stsp_w_path(
|
|
342
575
|
<size_t>csc_indptr[head_vert_idx + 1]):
|
343
576
|
|
344
577
|
tail_vert_idx = <size_t>csc_indices[idx]
|
578
|
+
|
579
|
+
# prefetch next iteration data to improve cache performance
|
580
|
+
if idx + 1 < <size_t>csc_indptr[head_vert_idx + 1]:
|
581
|
+
prefetch_hint(<char*>&csc_indices[idx + 1], PREFETCH_T0)
|
582
|
+
prefetch_hint(<char*>&csc_data[idx + 1], PREFETCH_T0)
|
583
|
+
|
345
584
|
vert_state = pqueue.Elements[tail_vert_idx].state
|
346
585
|
if vert_state != SCANNED:
|
586
|
+
# prefetch priority queue element data for the vertex
|
587
|
+
prefetch_hint(<char*>&pqueue.Elements[tail_vert_idx], PREFETCH_T0)
|
588
|
+
|
347
589
|
tail_vert_val = head_vert_val + csc_data[idx]
|
348
590
|
if vert_state == UNLABELED:
|
349
591
|
pq.insert(&pqueue, tail_vert_idx, tail_vert_val)
|
@@ -361,6 +603,216 @@ cpdef cnp.ndarray compute_stsp_w_path(
|
|
361
603
|
return path_lengths
|
362
604
|
|
363
605
|
|
606
|
+
cpdef cnp.ndarray compute_stsp_early_termination(
|
607
|
+
cnp.uint32_t[::1] csc_indptr,
|
608
|
+
cnp.uint32_t[::1] csc_indices,
|
609
|
+
DTYPE_t[::1] csc_data,
|
610
|
+
cnp.uint32_t[::1] termination_nodes,
|
611
|
+
int target_vert_idx,
|
612
|
+
int vertex_count,
|
613
|
+
int heap_length):
|
614
|
+
"""
|
615
|
+
Compute single-target shortest path with early termination when target
|
616
|
+
nodes are reached.
|
617
|
+
Parameters
|
618
|
+
----------
|
619
|
+
csc_indices : cnp.uint32_t[::1]
|
620
|
+
indices in the CSC format
|
621
|
+
csc_indptr : cnp.uint32_t[::1]
|
622
|
+
pointers in the CSC format
|
623
|
+
csc_data : DTYPE_t[::1]
|
624
|
+
data (edge weights) in the CSC format
|
625
|
+
termination_nodes : cnp.uint32_t[::1]
|
626
|
+
target node indices for early termination
|
627
|
+
target_vert_idx : int
|
628
|
+
target vertex index
|
629
|
+
vertex_count : int
|
630
|
+
vertex count
|
631
|
+
heap_length : int
|
632
|
+
heap length
|
633
|
+
|
634
|
+
Returns
|
635
|
+
-------
|
636
|
+
path_lengths : cnp.ndarray
|
637
|
+
shortest path length for each termination node
|
638
|
+
"""
|
639
|
+
|
640
|
+
cdef:
|
641
|
+
size_t tail_vert_idx, head_vert_idx, idx, i
|
642
|
+
DTYPE_t tail_vert_val, head_vert_val
|
643
|
+
pq.PriorityQueue pqueue
|
644
|
+
ElementState vert_state
|
645
|
+
size_t target = <size_t>target_vert_idx
|
646
|
+
size_t target_count = termination_nodes.shape[0]
|
647
|
+
size_t visited_targets = 0
|
648
|
+
size_t iteration_count = 0
|
649
|
+
size_t check_frequency = 16
|
650
|
+
|
651
|
+
with nogil:
|
652
|
+
|
653
|
+
# initialization of the heap elements
|
654
|
+
# all nodes have INFINITY key and UNLABELED state
|
655
|
+
pq.init_pqueue(&pqueue, <size_t>heap_length, <size_t>vertex_count)
|
656
|
+
|
657
|
+
# the key is set to zero for the target vertex,
|
658
|
+
# which is inserted into the heap
|
659
|
+
pq.insert(&pqueue, target, 0.0)
|
660
|
+
|
661
|
+
# main loop
|
662
|
+
while pqueue.size > 0:
|
663
|
+
head_vert_idx = pq.extract_min(&pqueue)
|
664
|
+
head_vert_val = pqueue.Elements[head_vert_idx].key
|
665
|
+
|
666
|
+
# check for early termination every check_frequency iterations
|
667
|
+
iteration_count += 1
|
668
|
+
if iteration_count % check_frequency == 0:
|
669
|
+
visited_targets = 0
|
670
|
+
for i in range(target_count):
|
671
|
+
if pqueue.Elements[termination_nodes[i]].state == SCANNED:
|
672
|
+
visited_targets += 1
|
673
|
+
if visited_targets == target_count:
|
674
|
+
break
|
675
|
+
|
676
|
+
# loop on incoming edges
|
677
|
+
for idx in range(<size_t>csc_indptr[head_vert_idx],
|
678
|
+
<size_t>csc_indptr[head_vert_idx + 1]):
|
679
|
+
|
680
|
+
tail_vert_idx = <size_t>csc_indices[idx]
|
681
|
+
|
682
|
+
# prefetch next iteration data to improve cache performance
|
683
|
+
if idx + 1 < <size_t>csc_indptr[head_vert_idx + 1]:
|
684
|
+
prefetch_hint(<char*>&csc_indices[idx + 1], PREFETCH_T0)
|
685
|
+
prefetch_hint(<char*>&csc_data[idx + 1], PREFETCH_T0)
|
686
|
+
|
687
|
+
vert_state = pqueue.Elements[tail_vert_idx].state
|
688
|
+
if vert_state != SCANNED:
|
689
|
+
# prefetch priority queue element data for the vertex
|
690
|
+
prefetch_hint(<char*>&pqueue.Elements[tail_vert_idx], PREFETCH_T0)
|
691
|
+
|
692
|
+
tail_vert_val = head_vert_val + csc_data[idx]
|
693
|
+
if vert_state == UNLABELED:
|
694
|
+
pq.insert(&pqueue, tail_vert_idx, tail_vert_val)
|
695
|
+
elif pqueue.Elements[tail_vert_idx].key > tail_vert_val:
|
696
|
+
pq.decrease_key(&pqueue, tail_vert_idx, tail_vert_val)
|
697
|
+
|
698
|
+
# copy only the termination nodes' results into a numpy array
|
699
|
+
cdef cnp.ndarray path_lengths = np.empty(target_count, dtype=DTYPE_PY)
|
700
|
+
for i in range(target_count):
|
701
|
+
path_lengths[i] = pqueue.Elements[termination_nodes[i]].key
|
702
|
+
|
703
|
+
# cleanup
|
704
|
+
pq.free_pqueue(&pqueue)
|
705
|
+
|
706
|
+
return path_lengths
|
707
|
+
|
708
|
+
|
709
|
+
cpdef cnp.ndarray compute_stsp_w_path_early_termination(
|
710
|
+
cnp.uint32_t[::1] csc_indptr,
|
711
|
+
cnp.uint32_t[::1] csc_indices,
|
712
|
+
DTYPE_t[::1] csc_data,
|
713
|
+
cnp.uint32_t[::1] successor,
|
714
|
+
cnp.uint32_t[::1] termination_nodes,
|
715
|
+
int target_vert_idx,
|
716
|
+
int vertex_count,
|
717
|
+
int heap_length):
|
718
|
+
"""
|
719
|
+
Compute single-target shortest path with path tracking and early termination.
|
720
|
+
Parameters
|
721
|
+
----------
|
722
|
+
csc_indices : cnp.uint32_t[::1]
|
723
|
+
Indices in the CSC format.
|
724
|
+
csc_indptr : cnp.uint32_t[::1]
|
725
|
+
Pointers in the CSC format.
|
726
|
+
csc_data : DTYPE_t[::1]
|
727
|
+
Data (edge weights) in the CSC format.
|
728
|
+
successor : cnp.uint32_t[::1]
|
729
|
+
Array of successor indices for path reconstruction.
|
730
|
+
termination_nodes : cnp.uint32_t[::1]
|
731
|
+
target node indices for early termination
|
732
|
+
target_vert_idx : int
|
733
|
+
Target vertex index.
|
734
|
+
vertex_count : int
|
735
|
+
Vertex count.
|
736
|
+
heap_length : int
|
737
|
+
heap_length.
|
738
|
+
|
739
|
+
Returns
|
740
|
+
-------
|
741
|
+
path_lengths : cnp.ndarray
|
742
|
+
shortest path length for each termination node
|
743
|
+
"""
|
744
|
+
|
745
|
+
cdef:
|
746
|
+
size_t tail_vert_idx, head_vert_idx, idx, i
|
747
|
+
DTYPE_t tail_vert_val, head_vert_val
|
748
|
+
pq.PriorityQueue pqueue
|
749
|
+
ElementState vert_state
|
750
|
+
size_t target = <size_t>target_vert_idx
|
751
|
+
size_t target_count = termination_nodes.shape[0]
|
752
|
+
size_t visited_targets = 0
|
753
|
+
size_t iteration_count = 0
|
754
|
+
size_t check_frequency = 16
|
755
|
+
|
756
|
+
with nogil:
|
757
|
+
|
758
|
+
# initialization of the heap elements
|
759
|
+
# all nodes have INFINITY key and UNLABELED state
|
760
|
+
pq.init_pqueue(&pqueue, <size_t>heap_length, <size_t>vertex_count)
|
761
|
+
|
762
|
+
# the key is set to zero for the target vertex,
|
763
|
+
# which is inserted into the heap
|
764
|
+
pq.insert(&pqueue, target, 0.0)
|
765
|
+
|
766
|
+
# main loop
|
767
|
+
while pqueue.size > 0:
|
768
|
+
head_vert_idx = pq.extract_min(&pqueue)
|
769
|
+
head_vert_val = pqueue.Elements[head_vert_idx].key
|
770
|
+
|
771
|
+
# check for early termination every check_frequency iterations
|
772
|
+
iteration_count += 1
|
773
|
+
if iteration_count % check_frequency == 0:
|
774
|
+
visited_targets = 0
|
775
|
+
for i in range(target_count):
|
776
|
+
if pqueue.Elements[termination_nodes[i]].state == SCANNED:
|
777
|
+
visited_targets += 1
|
778
|
+
if visited_targets == target_count:
|
779
|
+
break
|
780
|
+
|
781
|
+
# loop on incoming edges
|
782
|
+
for idx in range(<size_t>csc_indptr[head_vert_idx],
|
783
|
+
<size_t>csc_indptr[head_vert_idx + 1]):
|
784
|
+
|
785
|
+
tail_vert_idx = <size_t>csc_indices[idx]
|
786
|
+
|
787
|
+
# prefetch next iteration data to improve cache performance
|
788
|
+
if idx + 1 < <size_t>csc_indptr[head_vert_idx + 1]:
|
789
|
+
prefetch_hint(<char*>&csc_indices[idx + 1], PREFETCH_T0)
|
790
|
+
prefetch_hint(<char*>&csc_data[idx + 1], PREFETCH_T0)
|
791
|
+
|
792
|
+
vert_state = pqueue.Elements[tail_vert_idx].state
|
793
|
+
if vert_state != SCANNED:
|
794
|
+
# prefetch priority queue element data for the vertex
|
795
|
+
prefetch_hint(<char*>&pqueue.Elements[tail_vert_idx], PREFETCH_T0)
|
796
|
+
|
797
|
+
tail_vert_val = head_vert_val + csc_data[idx]
|
798
|
+
if vert_state == UNLABELED:
|
799
|
+
pq.insert(&pqueue, tail_vert_idx, tail_vert_val)
|
800
|
+
successor[tail_vert_idx] = head_vert_idx
|
801
|
+
elif pqueue.Elements[tail_vert_idx].key > tail_vert_val:
|
802
|
+
pq.decrease_key(&pqueue, tail_vert_idx, tail_vert_val)
|
803
|
+
successor[tail_vert_idx] = head_vert_idx
|
804
|
+
|
805
|
+
# copy only the termination nodes' results into a numpy array
|
806
|
+
cdef cnp.ndarray path_lengths = np.empty(target_count, dtype=DTYPE_PY)
|
807
|
+
for i in range(target_count):
|
808
|
+
path_lengths[i] = pqueue.Elements[termination_nodes[i]].key
|
809
|
+
|
810
|
+
# cleanup
|
811
|
+
pq.free_pqueue(&pqueue)
|
812
|
+
|
813
|
+
return path_lengths
|
814
|
+
|
815
|
+
|
364
816
|
# ============================================================================ #
|
365
817
|
# tests #
|
366
818
|
# ============================================================================ #
|
@@ -521,6 +973,56 @@ cpdef compute_stsp_02():
|
|
521
973
|
assert np.allclose(path_lengths_ref, path_lengths)
|
522
974
|
|
523
975
|
|
976
|
+
cpdef compute_sssp_early_termination_01():
|
977
|
+
"""
|
978
|
+
Test SSSP early termination on Braess-like network.
|
979
|
+
"""
|
980
|
+
|
981
|
+
csr_indptr, csr_indices, csr_data = generate_braess_network_csr()
|
982
|
+
|
983
|
+
# from vertex 0, stop when vertices 1 and 3 are reached
|
984
|
+
target_nodes = np.array([1, 3], dtype=np.uint32)
|
985
|
+
path_lengths = compute_sssp_early_termination(
|
986
|
+
csr_indptr, csr_indices, csr_data, target_nodes, 0, 4, 4
|
987
|
+
)
|
988
|
+
|
989
|
+
# should return path lengths only for termination nodes [1, 3]
|
990
|
+
path_lengths_ref = np.array([1., 2.], dtype=DTYPE_PY) # lengths to nodes 1 and 3
|
991
|
+
assert np.allclose(path_lengths_ref, path_lengths)
|
992
|
+
|
993
|
+
# test with path tracking
|
994
|
+
predecessor = np.arange(0, 4, dtype=np.uint32)
|
995
|
+
path_lengths_w_path = compute_sssp_w_path_early_termination(
|
996
|
+
csr_indptr, csr_indices, csr_data, predecessor, target_nodes, 0, 4, 4
|
997
|
+
)
|
998
|
+
assert np.allclose(path_lengths_ref, path_lengths_w_path)
|
999
|
+
|
1000
|
+
|
1001
|
+
cpdef compute_stsp_early_termination_01():
|
1002
|
+
"""
|
1003
|
+
Test STSP early termination on Braess-like network.
|
1004
|
+
"""
|
1005
|
+
|
1006
|
+
csc_indptr, csc_indices, csc_data = generate_braess_network_csc()
|
1007
|
+
|
1008
|
+
# to vertex 3, stop when vertices 0 and 2 are reached
|
1009
|
+
target_nodes = np.array([0, 2], dtype=np.uint32)
|
1010
|
+
path_lengths = compute_stsp_early_termination(
|
1011
|
+
csc_indptr, csc_indices, csc_data, target_nodes, 3, 4, 4
|
1012
|
+
)
|
1013
|
+
|
1014
|
+
# should return path lengths only for termination nodes [0, 2]
|
1015
|
+
path_lengths_ref = np.array([2., 1.], dtype=DTYPE_PY) # lengths to nodes 0 and 2
|
1016
|
+
assert np.allclose(path_lengths_ref, path_lengths)
|
1017
|
+
|
1018
|
+
# test with path tracking
|
1019
|
+
successor = np.arange(0, 4, dtype=np.uint32)
|
1020
|
+
path_lengths_w_path = compute_stsp_w_path_early_termination(
|
1021
|
+
csc_indptr, csc_indices, csc_data, successor, target_nodes, 3, 4, 4
|
1022
|
+
)
|
1023
|
+
assert np.allclose(path_lengths_ref, path_lengths_w_path)
|
1024
|
+
|
1025
|
+
|
524
1026
|
# author : Francois Pacull
|
525
1027
|
# copyright : Architecture & Performance
|
526
1028
|
# email: francois.pacull@architecture-performance.fr
|
edsger/path.py
CHANGED
@@ -17,8 +17,12 @@ from edsger.commons import (
|
|
17
17
|
from edsger.dijkstra import (
|
18
18
|
compute_sssp,
|
19
19
|
compute_sssp_w_path,
|
20
|
+
compute_sssp_early_termination,
|
21
|
+
compute_sssp_w_path_early_termination,
|
20
22
|
compute_stsp,
|
21
23
|
compute_stsp_w_path,
|
24
|
+
compute_stsp_early_termination,
|
25
|
+
compute_stsp_w_path_early_termination,
|
22
26
|
)
|
23
27
|
from edsger.path_tracking import compute_path
|
24
28
|
from edsger.spiess_florian import compute_SF_in
|
@@ -285,6 +289,7 @@ class Dijkstra:
|
|
285
289
|
return_inf=True,
|
286
290
|
return_series=False,
|
287
291
|
heap_length_ratio=1.0,
|
292
|
+
termination_nodes=None,
|
288
293
|
):
|
289
294
|
"""
|
290
295
|
Runs shortest path algorithm between a given vertex and all other vertices in the graph.
|
@@ -303,6 +308,11 @@ class Dijkstra:
|
|
303
308
|
as values.
|
304
309
|
heap_length_ratio : float, optional (default=1.0)
|
305
310
|
The heap length as a fraction of the number of vertices. Must be in the range (0, 1].
|
311
|
+
termination_nodes : array-like, optional (default=None)
|
312
|
+
List or array of vertex indices for early termination. For SSSP (orientation='out'),
|
313
|
+
these are target nodes to reach. For STSP (orientation='in'), these are source nodes
|
314
|
+
to find paths from. When provided, the algorithm stops once all specified nodes have
|
315
|
+
been processed, potentially improving performance. If None, runs to completion.
|
306
316
|
|
307
317
|
Returns
|
308
318
|
-------
|
@@ -355,49 +365,140 @@ class Dijkstra:
|
|
355
365
|
)
|
356
366
|
heap_length = int(np.rint(heap_length_ratio * self._n_vertices))
|
357
367
|
|
368
|
+
# validate and process termination_nodes
|
369
|
+
termination_nodes_array = None
|
370
|
+
if termination_nodes is not None:
|
371
|
+
try:
|
372
|
+
termination_nodes_array = np.array(termination_nodes, dtype=np.uint32)
|
373
|
+
except (ValueError, TypeError):
|
374
|
+
raise TypeError(
|
375
|
+
"argument 'termination_nodes' must be array-like of integers"
|
376
|
+
)
|
377
|
+
|
378
|
+
if termination_nodes_array.ndim != 1:
|
379
|
+
raise ValueError("argument 'termination_nodes' must be 1-dimensional")
|
380
|
+
|
381
|
+
if len(termination_nodes_array) == 0:
|
382
|
+
raise ValueError("argument 'termination_nodes' must not be empty")
|
383
|
+
|
384
|
+
# handle vertex permutation if needed
|
385
|
+
if self._permute:
|
386
|
+
termination_nodes_permuted = []
|
387
|
+
for termination_node in termination_nodes_array:
|
388
|
+
if termination_node not in self._permutation.vert_idx_old.values:
|
389
|
+
raise ValueError(
|
390
|
+
f"termination node {termination_node} not found in graph"
|
391
|
+
)
|
392
|
+
termination_node_new = self._permutation.loc[
|
393
|
+
self._permutation.vert_idx_old == termination_node,
|
394
|
+
"vert_idx_new",
|
395
|
+
].iloc[0]
|
396
|
+
termination_nodes_permuted.append(termination_node_new)
|
397
|
+
termination_nodes_array = np.array(
|
398
|
+
termination_nodes_permuted, dtype=np.uint32
|
399
|
+
)
|
400
|
+
else:
|
401
|
+
# validate that termination nodes exist
|
402
|
+
if np.any(termination_nodes_array >= self._n_vertices) or np.any(
|
403
|
+
termination_nodes_array < 0
|
404
|
+
):
|
405
|
+
raise ValueError(
|
406
|
+
"termination_nodes contains invalid vertex indices"
|
407
|
+
)
|
408
|
+
|
358
409
|
# compute path length
|
359
410
|
if not path_tracking:
|
360
411
|
self._path_links = None
|
361
|
-
if
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
412
|
+
if termination_nodes_array is not None:
|
413
|
+
# use early termination algorithms
|
414
|
+
if self._orientation == "in":
|
415
|
+
path_length_values = compute_stsp_early_termination(
|
416
|
+
self.__indptr,
|
417
|
+
self.__indices,
|
418
|
+
self.__edge_weights,
|
419
|
+
termination_nodes_array,
|
420
|
+
vertex_new,
|
421
|
+
self._n_vertices,
|
422
|
+
heap_length,
|
423
|
+
)
|
424
|
+
else:
|
425
|
+
path_length_values = compute_sssp_early_termination(
|
426
|
+
self.__indptr,
|
427
|
+
self.__indices,
|
428
|
+
self.__edge_weights,
|
429
|
+
termination_nodes_array,
|
430
|
+
vertex_new,
|
431
|
+
self._n_vertices,
|
432
|
+
heap_length,
|
433
|
+
)
|
370
434
|
else:
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
435
|
+
# use standard algorithms
|
436
|
+
if self._orientation == "in":
|
437
|
+
path_length_values = compute_stsp(
|
438
|
+
self.__indptr,
|
439
|
+
self.__indices,
|
440
|
+
self.__edge_weights,
|
441
|
+
vertex_new,
|
442
|
+
self._n_vertices,
|
443
|
+
heap_length,
|
444
|
+
)
|
445
|
+
else:
|
446
|
+
path_length_values = compute_sssp(
|
447
|
+
self.__indptr,
|
448
|
+
self.__indices,
|
449
|
+
self.__edge_weights,
|
450
|
+
vertex_new,
|
451
|
+
self._n_vertices,
|
452
|
+
heap_length,
|
453
|
+
)
|
379
454
|
else:
|
380
455
|
self._path_links = np.arange(0, self._n_vertices, dtype=np.uint32)
|
381
|
-
if
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
456
|
+
if termination_nodes_array is not None:
|
457
|
+
# use early termination algorithms with path tracking
|
458
|
+
if self._orientation == "in":
|
459
|
+
path_length_values = compute_stsp_w_path_early_termination(
|
460
|
+
self.__indptr,
|
461
|
+
self.__indices,
|
462
|
+
self.__edge_weights,
|
463
|
+
self._path_links,
|
464
|
+
termination_nodes_array,
|
465
|
+
vertex_new,
|
466
|
+
self._n_vertices,
|
467
|
+
heap_length,
|
468
|
+
)
|
469
|
+
else:
|
470
|
+
path_length_values = compute_sssp_w_path_early_termination(
|
471
|
+
self.__indptr,
|
472
|
+
self.__indices,
|
473
|
+
self.__edge_weights,
|
474
|
+
self._path_links,
|
475
|
+
termination_nodes_array,
|
476
|
+
vertex_new,
|
477
|
+
self._n_vertices,
|
478
|
+
heap_length,
|
479
|
+
)
|
391
480
|
else:
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
481
|
+
# use standard algorithms with path tracking
|
482
|
+
if self._orientation == "in":
|
483
|
+
path_length_values = compute_stsp_w_path(
|
484
|
+
self.__indptr,
|
485
|
+
self.__indices,
|
486
|
+
self.__edge_weights,
|
487
|
+
self._path_links,
|
488
|
+
vertex_new,
|
489
|
+
self._n_vertices,
|
490
|
+
heap_length,
|
491
|
+
)
|
492
|
+
else:
|
493
|
+
path_length_values = compute_sssp_w_path(
|
494
|
+
self.__indptr,
|
495
|
+
self.__indices,
|
496
|
+
self.__edge_weights,
|
497
|
+
self._path_links,
|
498
|
+
vertex_new,
|
499
|
+
self._n_vertices,
|
500
|
+
heap_length,
|
501
|
+
)
|
401
502
|
|
402
503
|
if self._permute:
|
403
504
|
# permute back the path vertex indices
|
@@ -445,7 +546,7 @@ class Dijkstra:
|
|
445
546
|
|
446
547
|
# reorder path lengths
|
447
548
|
if return_series:
|
448
|
-
if self._permute:
|
549
|
+
if self._permute and termination_nodes_array is None:
|
449
550
|
self._permutation["path_length"] = path_length_values
|
450
551
|
path_lengths_df = self._permutation[
|
451
552
|
["vert_idx_old", "path_length"]
|
@@ -457,9 +558,16 @@ class Dijkstra:
|
|
457
558
|
path_lengths_series = pd.Series(path_length_values)
|
458
559
|
path_lengths_series.index.name = "vertex_idx"
|
459
560
|
path_lengths_series.name = "path_length"
|
561
|
+
if self._permute and termination_nodes_array is not None:
|
562
|
+
# For early termination with permutation, use original termination node indices
|
563
|
+
path_lengths_series.index = termination_nodes
|
460
564
|
|
461
565
|
return path_lengths_series
|
462
566
|
|
567
|
+
# For early termination, return results directly (already in correct order)
|
568
|
+
if termination_nodes_array is not None:
|
569
|
+
return path_length_values
|
570
|
+
|
463
571
|
if self._permute:
|
464
572
|
self._permutation["path_length"] = path_length_values
|
465
573
|
if return_inf:
|
Binary file
|
Binary file
|
Binary file
|
edsger/star.cp312-win32.pyd
CHANGED
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: edsger
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.4
|
4
4
|
Summary: Graph algorithms in Cython.
|
5
5
|
Author-email: François Pacull <francois.pacull@architecture-performance.fr>
|
6
6
|
Maintainer-email: François Pacull <francois.pacull@architecture-performance.fr>
|
@@ -42,7 +42,8 @@ Dynamic: license-file
|
|
42
42
|
|
43
43
|

|
44
44
|
[](https://codecov.io/gh/aetperf/edsger)
|
45
|
-
[](https://edsger.readthedocs.io/en/latest/?badge=latest)
|
46
|
+
[](https://pypi.org/project/edsger/)
|
46
47
|
[](https://pepy.tech/project/edsger)
|
47
48
|
[](https://pypi.org/project/edsger/)
|
48
49
|
[](https://github.com/psf/black)
|
@@ -75,14 +76,14 @@ edges = pd.DataFrame({
|
|
75
76
|
edges
|
76
77
|
```
|
77
78
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
79
|
+
| | tail | head | weight |
|
80
|
+
|---:|-------:|-------:|---------:|
|
81
|
+
| 0 | 0 | 1 | 1.0 |
|
82
|
+
| 1 | 0 | 2 | 4.0 |
|
83
|
+
| 2 | 1 | 2 | 2.0 |
|
84
|
+
| 3 | 2 | 3 | 1.5 |
|
85
|
+
| 4 | 2 | 4 | 3.0 |
|
86
|
+
| 5 | 3 | 4 | 1.0 |
|
86
87
|
|
87
88
|
```python
|
88
89
|
# Initialize the Dijkstra object
|
@@ -97,13 +98,19 @@ print("Shortest paths:", shortest_paths)
|
|
97
98
|
|
98
99
|
We get the shortest paths from the source node 0 to all other nodes in the graph. The output is an array with the shortest path length to each node. A path length is the sum of the weights of the edges in the path.
|
99
100
|
|
100
|
-
##
|
101
|
+
## Installation
|
102
|
+
|
103
|
+
### Standard Installation
|
101
104
|
|
102
|
-
|
105
|
+
```bash
|
106
|
+
pip install edsger
|
107
|
+
```
|
108
|
+
|
109
|
+
## Why Use Edsger?
|
103
110
|
|
104
|
-
|
111
|
+
Edsger is designed to be **dataframe-friendly**, providing seamless integration with pandas workflows for graph algorithms. Also it is rather efficient on Linux. Our benchmarks on the USA road network (23.9M vertices, 57.7M edges) demonstrate nice performance:
|
105
112
|
|
106
|
-
|
113
|
+
<img src="https://raw.githubusercontent.com/aetperf/edsger/release/docs/source/assets/dijkstra_benchmark_comparison.png" alt="Dijkstra Performance Comparison" width="700">
|
107
114
|
|
108
115
|
## Contributing
|
109
116
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
edsger/.gitignore,sha256=mr9Izcwvjgv215xjRKhWEZ7vsyrKWhMqvWjSLHRYDjk,13
|
2
|
+
edsger/__init__.py,sha256=lgtGe3cqdwWdO1DLEOx7fX3i8D4Z_2rXHSq7Xecf-NM,41
|
3
|
+
edsger/_version.py,sha256=JMD28FXYHc_TM03visyUSd3UA9FZAaJMRStnfZoq50Y,21
|
4
|
+
edsger/commons.cp312-win32.pyd,sha256=Ij8OCS8r0EYdUGeU8sokLJRYItAKYa9boIJ_PTPPKnw,20480
|
5
|
+
edsger/commons.pxd,sha256=UshKjr5ve3Or9u75xGyGPKRz1RwCCb5N-xgNevXZ4j4,464
|
6
|
+
edsger/commons.pyx,sha256=6Ze22eE_zwXPRAe550DEhEvu-b7hvKmwQu73rzzWMUE,839
|
7
|
+
edsger/dijkstra.cp312-win32.pyd,sha256=TCNFPOoVvGeRGn_n_G00zWWRwl9PWGWonD5Iydyv6h8,214016
|
8
|
+
edsger/dijkstra.pyx,sha256=kBXFya0bugjp97xas145sZEUXtb89_Sg9v8IdWiURoE,37542
|
9
|
+
edsger/networks.py,sha256=hH9sgT5Ic4TLVCjxPNzMDWNjNDbqpXMxXxLeWxCpdLE,10730
|
10
|
+
edsger/path.py,sha256=2NtkhwN2HQUsoZn0Sl6UbFKWIcWVTvnE6D8IH-xEG88,35768
|
11
|
+
edsger/path_tracking.cp312-win32.pyd,sha256=gjsAtjRWQ4itlrdmklw2H-pS-q4OcKNl7jJFvlF_SqY,116736
|
12
|
+
edsger/path_tracking.pyx,sha256=H24TLmC53I8LjbM1S5E7gS8WEb5uE_PZ8nhG6BteMYA,1900
|
13
|
+
edsger/pq_4ary_dec_0b.cp312-win32.pyd,sha256=1_pXQ1Xtxwx1rCo9AzFvKFUFW9rryU7by4GD0sYIERk,142848
|
14
|
+
edsger/pq_4ary_dec_0b.pxd,sha256=VvXcQzJq3OGBptrbawtemagPimuqSCayGQ91Jrad894,1098
|
15
|
+
edsger/pq_4ary_dec_0b.pyx,sha256=IzvzQerf-LYy7weQpgI0f28Q8gUrR4ENaedekXs1Jeg,18486
|
16
|
+
edsger/prefetch_compat.h,sha256=AyAYq_ZHKk5ChaJDrZOAOYe6SprL0_2byjRbjcBGrsU,826
|
17
|
+
edsger/spiess_florian.cp312-win32.pyd,sha256=KHt94IJ_Xvhs9a2VAtPS1cMamFypM7VdnGJDtDybmus,162304
|
18
|
+
edsger/spiess_florian.pyx,sha256=tjfF9Iv8nqpp4lnv4KAjF-37ij0_SgQ0fnacVVKx-CE,9934
|
19
|
+
edsger/star.cp312-win32.pyd,sha256=8LFDWdmxlNrI_PfdRcFzJz4IEBceYrZYtqJi8UqrpF0,154112
|
20
|
+
edsger/star.pyx,sha256=9LAIXhlccEeDgT41ico7n57FJ7PKCzhPv4f22Lphn78,9602
|
21
|
+
edsger/utils.py,sha256=xYfOFIbYpAiZljhUOgGWy0TVNvWaMFCwbCLPBkzdVos,2097
|
22
|
+
edsger-0.1.4.dist-info/licenses/AUTHORS.rst,sha256=8udN6bgZHdHYcVzV38y6SPnF-x6Ks0uXxxFsic6Aces,110
|
23
|
+
edsger-0.1.4.dist-info/licenses/LICENSE,sha256=w7gRlruGxK3_4KTZAyJsOR2tML4UQgB-GNm2LerwJS0,1132
|
24
|
+
edsger-0.1.4.dist-info/METADATA,sha256=fl_OoQXbo9d0B0sIkuOSDD5JAB-CgxWA6dRNujINONc,5494
|
25
|
+
edsger-0.1.4.dist-info/WHEEL,sha256=LwxTQZ0gyDP_uaeNCLm-ZIktY9hv6x0e22Q-hgFd-po,97
|
26
|
+
edsger-0.1.4.dist-info/top_level.txt,sha256=QvhzFORJIIot6GzSnDrtGa9KQt9iifCbOC5ULlzY5dg,7
|
27
|
+
edsger-0.1.4.dist-info/RECORD,,
|
edsger-0.1.2.dist-info/RECORD
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
edsger/.gitignore,sha256=mr9Izcwvjgv215xjRKhWEZ7vsyrKWhMqvWjSLHRYDjk,13
|
2
|
-
edsger/__init__.py,sha256=lgtGe3cqdwWdO1DLEOx7fX3i8D4Z_2rXHSq7Xecf-NM,41
|
3
|
-
edsger/_version.py,sha256=K5SiDdEGYMpdqXThrqwTqECJJBOQNTQDrnpc2K5mzKs,21
|
4
|
-
edsger/commons.cp312-win32.pyd,sha256=A4VhAzKWRKdaOm2qAydr-Yw2K4JRz1k2A9CLGhBGqHs,19968
|
5
|
-
edsger/commons.pxd,sha256=UshKjr5ve3Or9u75xGyGPKRz1RwCCb5N-xgNevXZ4j4,464
|
6
|
-
edsger/commons.pyx,sha256=6Ze22eE_zwXPRAe550DEhEvu-b7hvKmwQu73rzzWMUE,839
|
7
|
-
edsger/dijkstra.cp312-win32.pyd,sha256=rwRaxfFz0SUpuKKoMNlk-0KTRkqMdCTq9PCg1M85uZ0,171008
|
8
|
-
edsger/dijkstra.pyx,sha256=5yjCC2NqXrfBe8tp1sN_XSsWF92IHFrOu-QdbOV8Rvo,17915
|
9
|
-
edsger/networks.py,sha256=hH9sgT5Ic4TLVCjxPNzMDWNjNDbqpXMxXxLeWxCpdLE,10730
|
10
|
-
edsger/path.py,sha256=OnXbP8Mf1rcO_9m6XsDrdXCRcLMeOb2vOAb1eHcZfM8,30395
|
11
|
-
edsger/path_tracking.cp312-win32.pyd,sha256=zKOdWTiOOLtihPEsKDMRcSMnygp0v6MjQ1uEDwjday4,113664
|
12
|
-
edsger/path_tracking.pyx,sha256=H24TLmC53I8LjbM1S5E7gS8WEb5uE_PZ8nhG6BteMYA,1900
|
13
|
-
edsger/pq_4ary_dec_0b.cp312-win32.pyd,sha256=_g51tHNv46-1KGSuFYR1Od8MvBn9GnDK9XKu3rB32mM,139776
|
14
|
-
edsger/pq_4ary_dec_0b.pxd,sha256=VvXcQzJq3OGBptrbawtemagPimuqSCayGQ91Jrad894,1098
|
15
|
-
edsger/pq_4ary_dec_0b.pyx,sha256=IzvzQerf-LYy7weQpgI0f28Q8gUrR4ENaedekXs1Jeg,18486
|
16
|
-
edsger/prefetch_compat.h,sha256=AyAYq_ZHKk5ChaJDrZOAOYe6SprL0_2byjRbjcBGrsU,826
|
17
|
-
edsger/spiess_florian.cp312-win32.pyd,sha256=mF_MRkXyjQJfWzQr-EiJoBIOPqT6-UFJJLFgEjNU2rE,159232
|
18
|
-
edsger/spiess_florian.pyx,sha256=tjfF9Iv8nqpp4lnv4KAjF-37ij0_SgQ0fnacVVKx-CE,9934
|
19
|
-
edsger/star.cp312-win32.pyd,sha256=sLn5npOoHmJJXTZW8-rNM7kX_yP8g67CZPBoy4wamGs,151040
|
20
|
-
edsger/star.pyx,sha256=9LAIXhlccEeDgT41ico7n57FJ7PKCzhPv4f22Lphn78,9602
|
21
|
-
edsger/utils.py,sha256=xYfOFIbYpAiZljhUOgGWy0TVNvWaMFCwbCLPBkzdVos,2097
|
22
|
-
edsger-0.1.2.dist-info/licenses/AUTHORS.rst,sha256=8udN6bgZHdHYcVzV38y6SPnF-x6Ks0uXxxFsic6Aces,110
|
23
|
-
edsger-0.1.2.dist-info/licenses/LICENSE,sha256=w7gRlruGxK3_4KTZAyJsOR2tML4UQgB-GNm2LerwJS0,1132
|
24
|
-
edsger-0.1.2.dist-info/METADATA,sha256=Z2KnsYE4vh_m5tvRYU-LIyDso2Kpdl7iQQeFYH_zfhM,5273
|
25
|
-
edsger-0.1.2.dist-info/WHEEL,sha256=LwxTQZ0gyDP_uaeNCLm-ZIktY9hv6x0e22Q-hgFd-po,97
|
26
|
-
edsger-0.1.2.dist-info/top_level.txt,sha256=QvhzFORJIIot6GzSnDrtGa9KQt9iifCbOC5ULlzY5dg,7
|
27
|
-
edsger-0.1.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|